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
|