aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-22 17:17:05 -0500
committerCraig Jennings <c@cjennings.net>2026-04-22 17:17:05 -0500
commitecca6c5809aa2945d593baae10308c0dcfe6ec17 (patch)
treec878f03abc082f0e407a5197d6f4e9ab35f7dbad /tests
parent071b25d43ad21eb1f5e7e74822bbf2cfa8f58b4e (diff)
downloaddotemacs-ecca6c5809aa2945d593baae10308c0dcfe6ec17.tar.gz
dotemacs-ecca6c5809aa2945d593baae10308c0dcfe6ec17.zip
feat(coverage): add elisp backend
First of the pluggable coverage backends. Registers itself with coverage-core on load. - :name is elisp - :detect returns non-nil when the project root has a Makefile, Eask, or Cask alongside .el files at root or under modules/. The heuristic is deliberately loose. For anything unusual, .dir-locals.el can pin the backend with cj/coverage-backend. - :run invokes make coverage in a compilation buffer. On success the callback fires with the LCOV path. On failure the buffer stays visible so the user can read the error. - :lcov-path resolves to <project-root>/.coverage/lcov.info. undercover is declared via use-package with :defer t so it's installed but not loaded at Emacs startup. The make coverage target will require it explicitly. Tests cover Normal (Makefile + modules/, Eask + root .el, Cask + modules/), Boundary (no build file, Makefile without .el, empty directory), and Error (nonexistent root returns nil). The registration-on-load case is also verified. The Makefile coverage target and the cj/coverage-report user command arrive in follow-up commits.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-coverage-elisp--detect.el99
1 files changed, 99 insertions, 0 deletions
diff --git a/tests/test-coverage-elisp--detect.el b/tests/test-coverage-elisp--detect.el
new file mode 100644
index 00000000..1301495a
--- /dev/null
+++ b/tests/test-coverage-elisp--detect.el
@@ -0,0 +1,99 @@
+;;; test-coverage-elisp--detect.el --- Tests for cj/--coverage-elisp-detect -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Unit tests for `cj/--coverage-elisp-detect', the heuristic that
+;; decides whether a given project root is an Elisp project.
+;;
+;; Heuristic: requires BOTH a Makefile/Eask/Cask AND some .el files
+;; (at root or under modules/).
+
+;;; Code:
+
+(require 'ert)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'coverage-elisp)
+
+(defun test-coverage-elisp-detect--make-project (spec)
+ "Create a temp directory matching SPEC.
+SPEC is a list of relative paths to create. Paths ending in `/' are
+directories; others are files. Returns the temp directory path."
+ (let ((root (make-temp-file "test-elisp-project-" t)))
+ (dolist (path spec)
+ (let ((full (expand-file-name path root)))
+ (if (string-suffix-p "/" path)
+ (make-directory full t)
+ (make-directory (file-name-directory full) t)
+ (write-region "" nil full))))
+ root))
+
+;;; Normal cases
+
+(ert-deftest test-coverage-elisp-detect-with-makefile-and-modules ()
+ "Normal: Makefile plus modules/foo.el is detected as elisp."
+ (let ((root (test-coverage-elisp-detect--make-project
+ '("Makefile" "modules/foo.el"))))
+ (unwind-protect
+ (should (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+(ert-deftest test-coverage-elisp-detect-with-eask-and-root-el ()
+ "Normal: Eask plus root-level .el file is detected."
+ (let ((root (test-coverage-elisp-detect--make-project
+ '("Eask" "main.el"))))
+ (unwind-protect
+ (should (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+(ert-deftest test-coverage-elisp-detect-with-cask-and-modules ()
+ "Normal: Cask plus modules/ directory is detected."
+ (let ((root (test-coverage-elisp-detect--make-project
+ '("Cask" "modules/bar.el"))))
+ (unwind-protect
+ (should (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+;;; Boundary cases
+
+(ert-deftest test-coverage-elisp-detect-no-build-file ()
+ "Boundary: .el files without a Makefile/Eask/Cask is NOT detected."
+ (let ((root (test-coverage-elisp-detect--make-project
+ '("main.el" "other.el"))))
+ (unwind-protect
+ (should-not (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+(ert-deftest test-coverage-elisp-detect-makefile-without-el ()
+ "Boundary: Makefile with no .el files is NOT detected."
+ (let ((root (test-coverage-elisp-detect--make-project
+ '("Makefile" "README.md"))))
+ (unwind-protect
+ (should-not (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+(ert-deftest test-coverage-elisp-detect-empty-directory ()
+ "Boundary: an empty directory is not an elisp project."
+ (let ((root (make-temp-file "test-empty-" t)))
+ (unwind-protect
+ (should-not (cj/--coverage-elisp-detect root))
+ (delete-directory root t))))
+
+;;; Error cases
+
+(ert-deftest test-coverage-elisp-detect-nonexistent-root ()
+ "Error: a nonexistent ROOT returns nil, not an error."
+ (should-not (cj/--coverage-elisp-detect "/nonexistent/path/for-test-12345")))
+
+;;; Registry integration
+
+(ert-deftest test-coverage-elisp-registered-on-load ()
+ "Normal: loading coverage-elisp registers the `elisp' backend."
+ (let ((backend (cj/--coverage-backend-by-name 'elisp)))
+ (should backend)
+ (should (eq 'elisp (plist-get backend :name)))
+ (should (functionp (plist-get backend :detect)))
+ (should (functionp (plist-get backend :run)))
+ (should (functionp (plist-get backend :lcov-path)))))
+
+(provide 'test-coverage-elisp--detect)
+;;; test-coverage-elisp--detect.el ends here