summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/coverage-core.el58
1 files changed, 58 insertions, 0 deletions
diff --git a/modules/coverage-core.el b/modules/coverage-core.el
new file mode 100644
index 00000000..4a3112ce
--- /dev/null
+++ b/modules/coverage-core.el
@@ -0,0 +1,58 @@
+;;; coverage-core.el --- Coverage reporting engine and backend registry -*- lexical-binding: t; coding: utf-8; -*-
+;; author: Craig Jennings <c@cjennings.net>
+
+;;; Commentary:
+;; Language-agnostic core for diff-aware coverage reporting.
+;;
+;; Reads an LCOV file, shells to git diff at a selectable scope,
+;; intersects the results, and displays a report buffer. Languages
+;; plug in via the backend registry (see `cj/coverage-backends').
+;;
+;; See docs/design/coverage.org for the design rationale.
+
+;;; Code:
+
+(defun cj/--coverage-parse-lcov (file)
+ "Parse FILE as LCOV and return a hash table of covered lines.
+Keys are source-file paths (strings). Values are hash tables whose
+keys are line numbers (integers) that had a hit count greater than
+zero. Only the SF, DA, and end_of_record fields are read; other
+LCOV fields are ignored. Malformed DA lines are skipped silently.
+Signals `user-error' if FILE does not exist."
+ (unless (file-exists-p file)
+ (user-error "LCOV file not found: %s" file))
+ (let ((result (make-hash-table :test 'equal))
+ (current-file nil)
+ (current-lines nil))
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let ((line (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))
+ (cond
+ ((string-prefix-p "SF:" line)
+ (setq current-file (substring line 3))
+ (setq current-lines (make-hash-table :test 'eql)))
+ ((string-prefix-p "DA:" line)
+ (when current-lines
+ (let* ((rest (substring line 3))
+ (parts (split-string rest ","))
+ (line-str (car parts))
+ (hits-str (cadr parts))
+ (line-num (and line-str (string-match-p "\\`[0-9]+\\'" line-str)
+ (string-to-number line-str)))
+ (hits (and hits-str (string-match-p "\\`[0-9]+\\'" hits-str)
+ (string-to-number hits-str))))
+ (when (and line-num hits (> hits 0))
+ (puthash line-num t current-lines)))))
+ ((string= line "end_of_record")
+ (when current-file
+ (puthash current-file current-lines result))
+ (setq current-file nil
+ current-lines nil))))
+ (forward-line 1)))
+ result))
+
+(provide 'coverage-core)
+;;; coverage-core.el ends here