aboutsummaryrefslogtreecommitdiff
path: root/tests/test-coverage-core--relativize-keys.el
blob: 82031cd158762bcb2dd9a29483460c9c06e509ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;;; test-coverage-core--relativize-keys.el --- Tests for path-key normalization -*- lexical-binding: t; -*-

;;; Commentary:
;; Unit + integration tests for `cj/--coverage-relativize-keys', the helper
;; that normalizes a file-path-keyed coverage table to repo-relative paths.
;;
;; The bug it fixes: `cj/--coverage-parse-simplecov' returns ABSOLUTE path
;; keys (simplecov/undercover emit absolute source paths), while
;; `cj/--coverage-parse-diff-output' returns repo-RELATIVE keys (git's
;; "+++ b/<path>").  `cj/--coverage-intersect' joins the two by exact string
;; key, so for the diff-aware scopes every changed file was classified
;; ":tracked nil" — zero matches ever.  Normalizing both tables to
;; repo-relative before the intersect makes the join work.
;;
;; The integration test drives the real parsers (a simplecov JSON fixture
;; with an absolute key + a git-diff string with the relative key) through
;; relativize + intersect, and asserts the file is tracked with the right
;; covered/uncovered split — the end-to-end reproduction of the bug.

;;; Code:

(require 'ert)

(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
(require 'coverage-core)

(defun test-coverage-relativize--hash-of-lines (pairs)
  "Build a file → line-set hash table from PAIRS.
Each pair is (FILE . (LINES...)); LINES becomes a hash-table of line → t."
  (let ((result (make-hash-table :test 'equal)))
    (dolist (pair pairs)
      (let ((lines (make-hash-table :test 'eql)))
        (dolist (line (cdr pair))
          (puthash line t lines))
        (puthash (car pair) lines result)))
    result))

;;; Normal cases

(ert-deftest test-coverage-relativize-absolute-key-made-relative ()
  "Normal: an absolute key is relativized against ROOT."
  (let* ((table (test-coverage-relativize--hash-of-lines
                 '(("/home/u/.emacs.d/modules/foo.el" 10 11))))
         (out (cj/--coverage-relativize-keys table "/home/u/.emacs.d")))
    (should (gethash "modules/foo.el" out))
    (should (null (gethash "/home/u/.emacs.d/modules/foo.el" out)))))

(ert-deftest test-coverage-relativize-preserves-line-set ()
  "Normal: the line-set value travels unchanged to the new key."
  (let* ((table (test-coverage-relativize--hash-of-lines
                 '(("/r/modules/foo.el" 4 8 15))))
         (out (cj/--coverage-relativize-keys table "/r"))
         (lines (gethash "modules/foo.el" out)))
    (should (hash-table-p lines))
    (should (gethash 4 lines))
    (should (gethash 8 lines))
    (should (gethash 15 lines))))

;;; Boundary cases

(ert-deftest test-coverage-relativize-already-relative-unchanged ()
  "Boundary: an already-relative key is left as-is, not re-relativized."
  (let* ((table (test-coverage-relativize--hash-of-lines
                 '(("modules/foo.el" 1 2))))
         (out (cj/--coverage-relativize-keys table "/home/u/.emacs.d")))
    (should (gethash "modules/foo.el" out))
    (should (= 1 (hash-table-count out)))))

(ert-deftest test-coverage-relativize-empty-table ()
  "Boundary: an empty table yields an empty table."
  (let ((out (cj/--coverage-relativize-keys (make-hash-table :test 'equal) "/r")))
    (should (hash-table-p out))
    (should (= 0 (hash-table-count out)))))

;;; Error cases

(ert-deftest test-coverage-relativize-nil-table-returns-empty ()
  "Error: a nil table returns an empty table rather than erroring."
  (let ((out (cj/--coverage-relativize-keys nil "/r")))
    (should (hash-table-p out))
    (should (= 0 (hash-table-count out)))))

;;; Integration — the real bug reproduction

(ert-deftest test-coverage-integration-absolute-report-relative-diff-tracks ()
  "Integration: a simplecov report (absolute keys) and a git diff (relative
keys) for the same file intersect as TRACKED once both are relativized.
This is the diff-aware-scope bug: without normalization the file reads
\":tracked nil\"."
  (let* ((root "/tmp/cov-root")
         (abs-path (concat root "/modules/foo.el"))
         (report (make-temp-file "cov-report-" nil ".json"))
         (diff (concat
                "diff --git a/modules/foo.el b/modules/foo.el\n"
                "index 1111111..2222222 100644\n"
                "--- a/modules/foo.el\n"
                "+++ b/modules/foo.el\n"
                "@@ -2,0 +2,3 @@\n"
                "+line two\n"
                "+line three\n"
                "+line four\n")))
    (unwind-protect
        (progn
          ;; simplecov array: index1=null, 2=hit, 3=0-hits, 4=hit
          ;; → covered lines {2, 4}
          (with-temp-file report
            (insert (format "{\"t\":{\"coverage\":{%S:[null,1,0,2]}}}" abs-path)))
          (let* ((covered (cj/--coverage-relativize-keys
                           (cj/--coverage-parse-simplecov report) root))
                 (changed (cj/--coverage-relativize-keys
                           (cj/--coverage-parse-diff-output diff) root))
                 (records (cj/--coverage-intersect covered changed))
                 (record (car records)))
            (should (= 1 (length records)))
            (should (equal "modules/foo.el" (plist-get record :path)))
            (should (eq t (plist-get record :tracked)))
            (should (equal '(2 3 4) (plist-get record :changed-lines)))
            (should (equal '(2 4) (plist-get record :covered-lines)))
            (should (equal '(3) (plist-get record :uncovered-lines)))))
      (delete-file report))))

(provide 'test-coverage-core--relativize-keys)
;;; test-coverage-core--relativize-keys.el ends here