diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-12 05:12:17 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-12 05:12:17 -0500 |
| commit | a032f45fe30ce300163bc052257c3c5c993c85d5 (patch) | |
| tree | bd96c3c802a0ed5f3c5b1b758fda6688a2233bff | |
| parent | fc966aa764cf30bcd6e75d9a1c3d89558ca95988 (diff) | |
| download | dotemacs-a032f45fe30ce300163bc052257c3c5c993c85d5.tar.gz dotemacs-a032f45fe30ce300163bc052257c3c5c993c85d5.zip | |
test: add terminal coverage summary helper
| -rw-r--r-- | scripts/coverage-summary.el | 57 | ||||
| -rw-r--r-- | tests/test-coverage-summary.el | 66 |
2 files changed, 123 insertions, 0 deletions
diff --git a/scripts/coverage-summary.el b/scripts/coverage-summary.el new file mode 100644 index 00000000..4947171f --- /dev/null +++ b/scripts/coverage-summary.el @@ -0,0 +1,57 @@ +;;; coverage-summary.el --- Terminal summary for SimpleCov module coverage -*- lexical-binding: t; -*- + +;;; Commentary: +;; Batch helper for `make coverage' and `make coverage-summary'. +;; Reuses coverage-core's SimpleCov parser and whole-project formatter so the +;; terminal table matches the editor's whole-project coverage semantics. + +;;; Code: + +(require 'coverage-core) + +(defun cj/coverage-summary--copy-lines (lines) + "Return a copy of hash table LINES." + (let ((copy (make-hash-table :test 'eql))) + (when (hash-table-p lines) + (maphash (lambda (line value) + (puthash line value copy)) + lines)) + copy)) + +(defun cj/coverage-summary--modules-only (table module-dir project-root) + "Filter coverage TABLE to files under MODULE-DIR. + +Returned keys are relative to PROJECT-ROOT for readable terminal output." + (let ((result (make-hash-table :test 'equal)) + (module-dir (file-name-as-directory (expand-file-name module-dir))) + (project-root (file-name-as-directory (expand-file-name project-root)))) + (maphash + (lambda (path lines) + (let ((absolute-path (expand-file-name path))) + (when (string-prefix-p module-dir absolute-path) + (puthash (file-relative-name absolute-path project-root) + (cj/coverage-summary--copy-lines lines) + result)))) + table) + result)) + +(defun cj/coverage-summary-text (report-file module-dir project-root) + "Return a whole-project coverage summary for MODULE-DIR from REPORT-FILE." + (let* ((covered (cj/coverage-summary--modules-only + (cj/--coverage-parse-simplecov report-file) + module-dir + project-root)) + (executable (cj/coverage-summary--modules-only + (cj/--coverage-simplecov-executable-lines report-file) + module-dir + project-root)) + (records (cj/--coverage-intersect covered executable))) + (cj/--coverage-format-summary records "modules/"))) + +(defun cj/coverage-print-module-summary (report-file module-dir project-root) + "Print a whole-project coverage summary for MODULE-DIR from REPORT-FILE." + (princ "\n") + (princ (cj/coverage-summary-text report-file module-dir project-root))) + +(provide 'coverage-summary) +;;; coverage-summary.el ends here diff --git a/tests/test-coverage-summary.el b/tests/test-coverage-summary.el new file mode 100644 index 00000000..01c9efa0 --- /dev/null +++ b/tests/test-coverage-summary.el @@ -0,0 +1,66 @@ +;;; test-coverage-summary.el --- Tests for terminal coverage summary -*- lexical-binding: t; -*- + +;;; Commentary: +;; Unit tests for the batch helper used by `make coverage-summary'. + +;;; Code: + +(require 'ert) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(add-to-list 'load-path (expand-file-name "scripts" user-emacs-directory)) +(require 'coverage-summary) + +(defun test-coverage-summary--write-json (content) + "Write CONTENT to a temp file; return its path." + (let ((file (make-temp-file "test-coverage-summary-" nil ".json"))) + (with-temp-file file + (insert content)) + file)) + +(ert-deftest test-coverage-summary-modules-only () + "Normal: summary includes modules files and ignores non-module files." + (let* ((root (file-name-as-directory (make-temp-file "coverage-root-" t))) + (module-a (expand-file-name "modules/a.el" root)) + (module-b (expand-file-name "modules/b.el" root)) + (other (expand-file-name "tests/test-a.el" root)) + (content (format + "{\"run\":{\"coverage\":{\"%s\":[1,0,null,1],\"%s\":[0,0],\"%s\":[1,1]}}}" + module-a module-b other)) + (file (test-coverage-summary--write-json content))) + (unwind-protect + (let ((output (cj/coverage-summary-text + file + (expand-file-name "modules" root) + root))) + (should (string-match-p "modules/a\\.el" output)) + (should (string-match-p "modules/b\\.el" output)) + (should-not (string-match-p "tests/test-a\\.el" output)) + (should (string-match-p "2 of 5" output))) + (delete-file file) + (delete-directory root t)))) + +(ert-deftest test-coverage-summary-sorts-worst-first () + "Normal: module rows use the same worst-first sorting as the editor summary." + (let* ((root (file-name-as-directory (make-temp-file "coverage-root-" t))) + (low (expand-file-name "modules/low.el" root)) + (high (expand-file-name "modules/high.el" root)) + (content (format + "{\"run\":{\"coverage\":{\"%s\":[0,0,1,1],\"%s\":[1,1]}}}" + low high)) + (file (test-coverage-summary--write-json content))) + (unwind-protect + (let* ((output (cj/coverage-summary-text + file + (expand-file-name "modules" root) + root)) + (pos-low (string-match "modules/low\\.el" output)) + (pos-high (string-match "modules/high\\.el" output))) + (should pos-low) + (should pos-high) + (should (< pos-low pos-high))) + (delete-file file) + (delete-directory root t)))) + +(provide 'test-coverage-summary) +;;; test-coverage-summary.el ends here |
