aboutsummaryrefslogtreecommitdiff
path: root/tests/test-coverage-core--parse-simplecov.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-coverage-core--parse-simplecov.el')
-rw-r--r--tests/test-coverage-core--parse-simplecov.el153
1 files changed, 153 insertions, 0 deletions
diff --git a/tests/test-coverage-core--parse-simplecov.el b/tests/test-coverage-core--parse-simplecov.el
new file mode 100644
index 00000000..09a3051e
--- /dev/null
+++ b/tests/test-coverage-core--parse-simplecov.el
@@ -0,0 +1,153 @@
+;;; test-coverage-core--parse-simplecov.el --- Tests for cj/--coverage-parse-simplecov -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Unit tests for `cj/--coverage-parse-simplecov', the pure helper
+;; that reads a simplecov JSON report and returns a hash table of
+;; file → set of covered line numbers.
+;;
+;; Simplecov JSON structure:
+;; { <test-name>: { "coverage": { <path>: [null | 0 | int, ...] } } }
+;;
+;; Array index i (0-based) corresponds to line (i+1).
+;; nil — line is not executable (blank, comment)
+;; 0 — line is executable but not hit
+;; positive int — hit count
+;;
+;; When the JSON has multiple top-level test-name keys, coverage is
+;; unioned across them.
+
+;;; Code:
+
+(require 'ert)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'coverage-core)
+
+(defun test-coverage-parse-simplecov--write-temp-json (content)
+ "Write CONTENT (a JSON string) to a temp file; return its path."
+ (let ((file (make-temp-file "test-simplecov-" nil ".json")))
+ (with-temp-file file
+ (insert content))
+ file))
+
+;;; Normal cases
+
+(ert-deftest test-coverage-parse-simplecov-single-file-all-hit ()
+ "Normal: one file with every executable line hit."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/foo.el\":[null,1,2,3]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let* ((result (cj/--coverage-parse-simplecov file))
+ (lines (gethash "/foo.el" result)))
+ (should (hash-table-p result))
+ (should (= 3 (hash-table-count lines)))
+ (should (gethash 2 lines))
+ (should (gethash 3 lines))
+ (should (gethash 4 lines))
+ (should-not (gethash 1 lines)))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-multiple-files ()
+ "Normal: multiple files under one test-name are both parsed."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/a.el\":[1,1],\"/b.el\":[null,5]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let ((result (cj/--coverage-parse-simplecov file)))
+ (should (= 2 (hash-table-count result)))
+ (should (gethash "/a.el" result))
+ (should (gethash "/b.el" result))
+ (should (= 2 (hash-table-count (gethash "/a.el" result))))
+ (should (= 1 (hash-table-count (gethash "/b.el" result)))))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-mixed-hits ()
+ "Normal: null (not executable) and 0 (not hit) are excluded."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/foo.el\":[null,1,0,5,null,0,2]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let* ((result (cj/--coverage-parse-simplecov file))
+ (lines (gethash "/foo.el" result)))
+ (should (= 3 (hash-table-count lines)))
+ (should-not (gethash 1 lines))
+ (should (gethash 2 lines))
+ (should-not (gethash 3 lines))
+ (should (gethash 4 lines))
+ (should-not (gethash 5 lines))
+ (should-not (gethash 6 lines))
+ (should (gethash 7 lines)))
+ (delete-file file))))
+
+;;; Boundary cases
+
+(ert-deftest test-coverage-parse-simplecov-empty-json ()
+ "Boundary: a JSON object with no test-name keys returns empty hash."
+ (let* ((content "{}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let ((result (cj/--coverage-parse-simplecov file)))
+ (should (hash-table-p result))
+ (should (= 0 (hash-table-count result))))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-file-with-spaces-in-path ()
+ "Boundary: filename with spaces is parsed as one key."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/my path/spaces.el\":[1]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let ((result (cj/--coverage-parse-simplecov file)))
+ (should (gethash "/my path/spaces.el" result)))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-all-zero-hits ()
+ "Boundary: file with every executable line at 0 returns empty set."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/foo.el\":[0,0,null,0]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let* ((result (cj/--coverage-parse-simplecov file))
+ (lines (gethash "/foo.el" result)))
+ (should (hash-table-p lines))
+ (should (= 0 (hash-table-count lines))))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-all-null-entries ()
+ "Boundary: all-null coverage array (no executable lines) returns empty set."
+ (let* ((content "{\"run\":{\"timestamp\":1,\"coverage\":{\"/foo.el\":[null,null,null]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let* ((result (cj/--coverage-parse-simplecov file))
+ (lines (gethash "/foo.el" result)))
+ (should (hash-table-p lines))
+ (should (= 0 (hash-table-count lines))))
+ (delete-file file))))
+
+(ert-deftest test-coverage-parse-simplecov-multiple-test-names-unioned ()
+ "Boundary: multiple top-level test-name keys are unioned for the same file."
+ (let* ((content "{\"run1\":{\"timestamp\":1,\"coverage\":{\"/foo.el\":[1,1,0,0]}},\"run2\":{\"timestamp\":2,\"coverage\":{\"/foo.el\":[0,0,1,1]}}}")
+ (file (test-coverage-parse-simplecov--write-temp-json content)))
+ (unwind-protect
+ (let* ((result (cj/--coverage-parse-simplecov file))
+ (lines (gethash "/foo.el" result)))
+ (should (= 4 (hash-table-count lines)))
+ (should (gethash 1 lines))
+ (should (gethash 2 lines))
+ (should (gethash 3 lines))
+ (should (gethash 4 lines)))
+ (delete-file file))))
+
+;;; Error cases
+
+(ert-deftest test-coverage-parse-simplecov-missing-file-errors ()
+ "Error: nonexistent file signals user-error."
+ (should-error (cj/--coverage-parse-simplecov "/nonexistent/path/xyz.json")
+ :type 'user-error))
+
+(ert-deftest test-coverage-parse-simplecov-malformed-json-errors ()
+ "Error: malformed JSON input signals user-error naming the file."
+ (let ((file (test-coverage-parse-simplecov--write-temp-json "{not valid json")))
+ (unwind-protect
+ (should-error (cj/--coverage-parse-simplecov file)
+ :type 'user-error)
+ (delete-file file))))
+
+(provide 'test-coverage-core--parse-simplecov)
+;;; test-coverage-core--parse-simplecov.el ends here