diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-31 11:43:03 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-31 11:43:03 -0500 |
| commit | b46619cd17ed4e36f2e59c1b600078521b2049ef (patch) | |
| tree | f128aeef3f0f679a400595c896a98618266706d9 /languages/elisp/coverage-makefile.txt | |
| parent | 3640664e0fa11d7eb99c2900df57734b411e2d2b (diff) | |
| download | rulesets-b46619cd17ed4e36f2e59c1b600078521b2049ef.tar.gz rulesets-b46619cd17ed4e36f2e59c1b600078521b2049ef.zip | |
feat(elisp): add coverage-summary to the Elisp bundle with missing-file detection
A line-weighted coverage total has a blind spot: a module no test loads never shows up in the SimpleCov report, so it can't drag the number down. The suite looks healthier than it is. This adds a summary that counts every source file on disk against the report and treats an absent file as 0%, weighting the project number by file instead of by line so untested modules stay visible.
The script ships at languages/elisp/claude/scripts/coverage-summary.el, self-contained on stock Emacs (just the built-in json). It parses the undercover SimpleCov shape directly rather than depending on the editor's coverage engine, so it runs anywhere the bundle lands. I proved it against a real 103-file report: 93 tracked, 27 untested modules surfaced, project number 66.4%.
Delivery follows the bundle convention. The script lives under the gitignored .claude/ footprint and gets auto-fixed on drift by sync-language-bundle.sh, which I made generic for any claude/scripts/* rather than coverage-specific. The Makefile targets ship as a project-owned fragment (languages/elisp/coverage-makefile.txt) that install-lang.sh seeds at the project root and sync drops into .ai/inbox/ when that convention exists. The bundle never edits the project's own Makefile.
Tests: 12 ERT for the kernel (Normal/Boundary/Error per function), wired into make test via a new languages/*/tests/ discovery path, plus bats for the sync auto-fix and the inbox-drop guards.
This is the Elisp pilot. The pattern is proven, so fanning out to Python, Go, and TypeScript is now a follow-up. Each one needs only its own parser and fragment. The plumbing is already generic.
Diffstat (limited to 'languages/elisp/coverage-makefile.txt')
| -rw-r--r-- | languages/elisp/coverage-makefile.txt | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/languages/elisp/coverage-makefile.txt b/languages/elisp/coverage-makefile.txt new file mode 100644 index 0000000..c85ad90 --- /dev/null +++ b/languages/elisp/coverage-makefile.txt @@ -0,0 +1,56 @@ +# Elisp coverage — Makefile fragment + setup recommendation +# +# This file is owned by the project, not the rulesets bundle. The bundle never +# edits your Makefile. Copy the two targets below into your own Makefile (and +# adjust the variables at the top), then delete this file or keep it as a note. +# +# What you get: +# make coverage runs the test suite under undercover, writing a +# SimpleCov JSON report to .coverage/simplecov.json +# make coverage-summary prints a per-file table, a unit-weighted project +# number, and — the point — every source file on disk +# that no test imported, counted as 0%. +# +# Why the summary matters: a module no test loads never appears in undercover's +# output, so a line-weighted total silently skips it. The summary weights by +# file and counts a missing file as 0%, so untested modules stay visible. +# +# --------------------------------------------------------------------------- +# Prerequisite: undercover +# +# Add undercover to your test dependencies and arm it in your test runner +# (e.g. tests/run-coverage-file.el) before the source under test is loaded: +# +# (when (require 'undercover nil t) +# (undercover "modules/*.el" +# (:report-format 'simplecov) +# (:report-file ".coverage/simplecov.json") +# (:merge-report t))) +# +# Sources must be loaded from .el (not byte-compiled .elc) for instrumentation +# to attach — the coverage target deletes stale .elc first. +# --------------------------------------------------------------------------- + +# Variables — adjust to your layout. +EMACS ?= emacs +SOURCE_DIR ?= modules +COVERAGE_DIR ?= .coverage +COVERAGE_FILE ?= $(COVERAGE_DIR)/simplecov.json +# The summary script ships with the bundle under .claude/scripts/ (gitignored). +COVERAGE_SUMMARY ?= .claude/scripts/coverage-summary.el + +coverage: + @rm -f $(COVERAGE_FILE) $(SOURCE_DIR)/*.elc + @mkdir -p $(COVERAGE_DIR) + @UNDERCOVER_FORCE=true $(EMACS) --batch -L $(SOURCE_DIR) -L tests \ + $(foreach t,$(wildcard tests/test-*.el),-l $(t)) \ + -f ert-run-tests-batch-and-exit + @$(MAKE) coverage-summary + +coverage-summary: + @if [ ! -f $(COVERAGE_FILE) ]; then \ + echo "[!] No coverage file at $(COVERAGE_FILE). Run 'make coverage' first."; \ + exit 1; \ + fi + @$(EMACS) --batch -q -l $(COVERAGE_SUMMARY) \ + --eval '(cj/coverage-print-module-summary "$(COVERAGE_FILE)" "$(SOURCE_DIR)" "$(CURDIR)")' |
