<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/Makefile, branch load-graph-classify-start</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=load-graph-classify-start'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-22T21:09:49+00:00</updated>
<entry>
<title>fix(test): make test-name resilient to load-time cwd changes</title>
<updated>2026-05-22T21:09:49+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-22T21:09:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=4fbe435f515a26ea11732c982900a1f011dff589'/>
<id>urn:sha1:4fbe435f515a26ea11732c982900a1f011dff589</id>
<content type='text'>
make test-name loads every test file into one Emacs, then selects by name. test-system-defaults-functions.el requires system-defaults at load, which runs (setq default-directory user-home-dir), an intentional config choice. That leaked the cwd into the shared session, so every relative -l tests/X.el load after it resolved against the wrong directory and aborted the whole run with Error 255.

I made two changes. test-name now passes absolute paths to -l so loads survive any cwd change, and the test contains the leak by let-binding default-directory around the require. The production setq stays as is.
</content>
</entry>
<entry>
<title>fix(coverage): include gptel-tools in instrumentation glob</title>
<updated>2026-05-16T15:29:50+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-16T15:29:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=faf716de7ad4b69486e42de591588d8b750bbdb9'/>
<id>urn:sha1:faf716de7ad4b69486e42de591588d8b750bbdb9</id>
<content type='text'>
Undercover now instruments gptel-tools/*.el alongside modules/*.el,
so the new git_status / git_log / git_diff / web_fetch tools (and
their successors) report coverage instead of reading as zero.

The matching pre-coverage clean step deletes gptel-tools/*.elc so
stale byte-compiled artifacts don't shadow the .el sources.  If
Emacs loads the .elc first, undercover's source instrumentation
never runs.

docs/design/coverage.org gains an Elisp-coverage-producer subsection
documenting the glob, the :merge-report dependence (SimpleCov merges
cross-process reports, LCOV does not), and the missing-artifact
failure mode.
</content>
</entry>
<entry>
<title>refactor(build): extract the shared test-runner loop into a make macro</title>
<updated>2026-05-12T10:11:14+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T10:11:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=fc966aa764cf30bcd6e75d9a1c3d89558ca95988'/>
<id>urn:sha1:fc966aa764cf30bcd6e75d9a1c3d89558ca95988</id>
<content type='text'>
`test-unit' and `test-integration' carried the same ~45-line shell loop (run each .el file in its own Emacs with the slow/perf-tagged tests skipped, count "Ran N", collect failures, dump a per-file log, print a ✓/✗ summary banner, exit 1 on any fail), differing only in the file list and the label. The `:perf' tag filter had to be added in both last week, which is the kind of drift this invites.

Now a `define run-el-tests' macro (parametrized by the file list and the lowercase/uppercase labels) holds the loop once, and the two targets are one `@$(call run-el-tests,...)' line each. The banner string moved to a `BANNER' variable. No behavior change: `make test-unit', `make test-integration', and `make test' produce the same output.

`coverage' keeps its own loop. It uses `run-coverage-file.el' instead of `-l ert', skips the pass-count and the per-file log, has a much shorter summary, and is bracketed by the .elc cleanup and the coverage-file check. Folding it in would need three more parameters and conditionals, which would cost more clarity than the duplication does.
</content>
</entry>
<entry>
<title>test(scripts): add bats coverage for setup-email.sh password helpers</title>
<updated>2026-05-12T05:56:27+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T05:56:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=839bbeb14a92a777a3857102dba08a212b21443d'/>
<id>urn:sha1:839bbeb14a92a777a3857102dba08a212b21443d</id>
<content type='text'>
`setup-email.sh' ran top to bottom, so the only way to exercise `install_encrypted_password' / `decrypt_password' was to run the whole new-machine setup (mbsync, mu init). Its procedural body now lives in a `main()' function guarded by the usual `[[ "${BASH_SOURCE[0]}" == "${0}" ]]' check, so sourcing the script just defines the helpers, and running it directly is unchanged.

New `tests/test-setup-email.bats' sources the script, points the password dirs at a per-test tmpdir, and covers both helpers across the normal / skip-existing / missing-source / (for decrypt) gpg-failure paths, stubbing `gpg' so no real key is needed. `make test-bash' runs the bats files, and `make test' picks them up after the Elisp suite when bats is installed.
</content>
</entry>
<entry>
<title>build: add make benchmark target and skip :perf tests by default</title>
<updated>2026-05-12T05:09:15+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T05:09:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=cd0b90dc74996f7bd7b897834bac7038ffb7f5b8'/>
<id>urn:sha1:cd0b90dc74996f7bd7b897834bac7038ffb7f5b8</id>
<content type='text'>
`make test', `make coverage', and the editor's PostToolUse test runner all selected `(not (tag :slow))', which let the now-`:perf'-tagged benchmark suite run alongside the unit tests. Each of those three filters now also excludes `:perf', and a new `make benchmark' target runs the benchmark file on its own. `make test-file' and `make test-name' keep their old filters so the suite stays reachable for ad-hoc runs.

`COVERAGE_EXCLUDE' loses `test-lorem-optimum-benchmark.el'. The tag filter handles it now, so the only entry left is `test-all-comp-errors.el', which byte-compiles modules and can't run under undercover's instrumentation.
</content>
</entry>
<entry>
<title>docs: clarify the coverage-exclude and token-seed comments</title>
<updated>2026-05-11T23:17:22+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T23:17:22+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=2b88c6a83f854c3e166774d2855491de6e230d03'/>
<id>urn:sha1:2b88c6a83f854c3e166774d2855491de6e230d03</id>
<content type='text'>
The Makefile's `COVERAGE_EXCLUDE' comment said why `test-all-comp-errors.el' is excluded but not why `test-lorem-optimum-benchmark.el' is. It now notes that undercover's instrumentation slows execution enough to fail the benchmark's wall-clock assertions. And `cj/markov-generate' now has a comment explaining why `tokens' is seeded reversed (`(list w2 w1)'): the list is built with `push' and `nreverse'd at the end, so without the note the reversed seed reads like a bug at a glance.
</content>
</entry>
<entry>
<title>build(make): exclude the lorem-optimum benchmark from coverage runs</title>
<updated>2026-05-11T22:17:54+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T22:17:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1f4c69218cc56a1cd8f670bd9cff34eb5f19d406'/>
<id>urn:sha1:1f4c69218cc56a1cd8f670bd9cff34eb5f19d406</id>
<content type='text'>
`test-lorem-optimum-benchmark.el' runs under undercover during `make coverage', and the instrumentation slows the path enough to fail the benchmark's timing assertions. Added it to `COVERAGE_EXCLUDE' alongside `test-all-comp-errors.el'. It still runs in the normal `make test' flow.
</content>
</entry>
<entry>
<title>Make batch Emacs prefer newer sources</title>
<updated>2026-05-10T07:44:32+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-10T07:44:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1d24227c1335b8b154d0bd14a34b6db5e8069f02'/>
<id>urn:sha1:1d24227c1335b8b154d0bd14a34b6db5e8069f02</id>
<content type='text'>
Set load-prefer-newer for Makefile batch/test invocations. This matches normal startup and keeps tests from accidentally loading stale .elc files instead of the edited source.
</content>
</entry>
<entry>
<title>fix: make test scratch paths sandbox-friendly</title>
<updated>2026-05-04T00:59:42+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-04T00:59:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=deff663d480afb23e47f0d0fd834d2c0959d0b00'/>
<id>urn:sha1:deff663d480afb23e47f0d0fd834d2c0959d0b00</id>
<content type='text'>
`tests/testutil-general.el` hard-coded `~/.temp-emacs-tests/` as the test root. That worked locally but blew up under sandboxed `make` runs and CI environments that can't write outside the repo or `/tmp`. A clean sandbox `make test` run reported 32 failing test files purely from the home-directory write attempt, even though the same suite passed when run with normal write permission.

I rewrote `cj/test-base-dir` to honor `CJ_EMACS_TEST_DIR` if set, otherwise create a unique directory under `temporary-file-directory` via `make-temp-file`. So sandbox and CI paths just work, and a stable local debug root is still one env-var away.

I also tightened the path-containment checks. The old `(string-prefix-p base fullpath)` was a textual hack. Relative paths and weird trailing slashes could fool it. I extracted `cj/test--assert-inside-base` using `file-in-directory-p`, which is the proper API. While I was there, I added `cj/test--safe-base-dir-p` so `cj/delete-test-base-dir` refuses to recursively wipe `/`, `~/`, `temporary-file-directory`, `user-emacs-directory`, `default-directory`, or any path of length under six characters. That guards against an env-var typo or a misaligned `let` binding accidentally deleting something important.

I updated the Makefile's `clean-tests` target to nuke the new `$TMPDIR/cj-emacs-tests-*` pattern plus an explicit `CJ_EMACS_TEST_DIR` (if set) and the legacy `~/.temp-emacs-tests` directory.

I added `tests/test-testutil-general.el` with five tests: default base lives under `temporary-file-directory`, env override resolves correctly, parent-escape paths are rejected, broad roots are refused for deletion, and a specific selected root is cleaned cleanly.
</content>
</entry>
<entry>
<title>feat(coverage): wire make coverage target + simplecov pipeline</title>
<updated>2026-04-23T00:58:00+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-23T00:58:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a97266c0e89ef8560824789063512d2613849fc9'/>
<id>urn:sha1:a97266c0e89ef8560824789063512d2613849fc9</id>
<content type='text'>
Completes the coverage v1 pipeline by adding the Makefile target, the undercover driver script, the exclusion list, and the .gitignore entry. Uses simplecov JSON rather than LCOV as the collection format.

The LCOV vs simplecov choice: Undercover's :merge-report t option only supports simplecov. Since the pipeline runs tests per-file (matching test-unit's isolation pattern) and accumulates coverage across runs, merge-report is required. LCOV is better-supported by external coverage viewers, but for a primarily interactive workflow the on-disk format is an internal detail.

Other moves in this commit:

- Renamed cj/--coverage-parse-lcov to cj/--coverage-parse-simplecov and rewrote its tests for the JSON schema. Same signature, same semantics (file to set of covered lines), different parser.
- Renamed the backend protocol's :lcov-path key to :report-path, format-neutral and matching the renamed cj/--coverage-elisp-report-path function.
- The coverage target deletes modules/*.elc before running so undercover can instrument the .el sources. Without this, byte-compiled versions shadow the instrumentation and only a handful of pre-loaded modules end up with coverage data.
- Excluded tests/test-all-comp-errors.el from make coverage runs. That test byte-compiles every module, which fails under undercover's instrumentation. Excluded only from coverage. Normal make test still runs it.
- Updated docs/design/coverage.org to reflect the simplecov pivot with a historical note on why we moved off LCOV.

Verified end-to-end: make coverage produces .coverage/simplecov.json with 2717 of 4559 executable lines hit across 44 tracked modules.
</content>
</entry>
</feed>
