aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-10 16:36:17 -0500
committerCraig Jennings <c@cjennings.net>2026-05-10 16:36:17 -0500
commit93063d8a35060d5467e2d056bd4496e51f17ddc1 (patch)
tree666a81fdb34e758ffb1a49ab8808d0efcdd1face
parent08cf28b2b752a9fdad10201484763f1fbb5733b3 (diff)
downloadchime-93063d8a35060d5467e2d056bd4496e51f17ddc1.tar.gz
chime-93063d8a35060d5467e2d056bd4496e51f17ddc1.zip
test: harden test dependency and temp-dir setup
-rw-r--r--TESTING.org30
-rw-r--r--tests/Makefile11
-rw-r--r--tests/check-deps.el38
-rw-r--r--tests/test-testutil-general.el49
-rw-r--r--tests/testutil-general.el31
5 files changed, 143 insertions, 16 deletions
diff --git a/TESTING.org b/TESTING.org
index 92e4117..b1a80d1 100644
--- a/TESTING.org
+++ b/TESTING.org
@@ -40,7 +40,7 @@ All test logic lives in =tests/Makefile=. The root Makefile delegates to it, so
| =make clean= | Remove byte-compiled files and logs |
| =make help= | Show all available commands |
-Each test file runs in its own Emacs process for isolation. Integration tests are identified by the =test-integration-= prefix. Dependencies are auto-detected from =~/.emacs.d/elpa/=. Override with =EMACS= or =ELPA_DIR= environment variables.
+Each test file runs in its own Emacs process for isolation. Integration tests are identified by the =test-integration-= prefix. Dependency checks run inside Emacs with =package-initialize= and =require=, so any setup that makes the required features available on =load-path= works.
** Examples
@@ -236,11 +236,19 @@ Builds org events and event data structures for tests.
("Birthday" bday-time nil t))
org-file
(setq org-agenda-files (list org-file)))
+
+;; Build tooltip text from org content without manual buffer setup
+(with-chime-tooltip-from-content content tooltip
+ (should (string-match-p "Meeting" tooltip)))
#+end_src
** testutil-general.el --- File system utilities
-Manages test directories and temp files under =~/.temp-chime-tests/=.
+Manages test directories and temp files under =chime-test-base-dir=. By default
+this is a unique per-process directory under =temporary-file-directory=, so test
+runs do not write into the user's home and parallel runs do not share one fixed
+root. Set =CHIME_TEST_TMPDIR= to force a specific test root when debugging or
+when CI needs a predictable artifact location.
| Function | Purpose |
|----------+---------|
@@ -252,6 +260,8 @@ Manages test directories and temp files under =~/.temp-chime-tests/=.
| =chime-create-directory-or-file-ensuring-parents= | Create dir (trailing /) or file |
All paths are sandboxed under =chime-test-base-dir= -- attempts to escape are rejected with an error.
+Tests should create files through these helpers and clean up with
+=chime-delete-test-base-dir= or the higher-level setup macros.
* Key patterns
@@ -281,9 +291,17 @@ All paths are sandboxed under =chime-test-base-dir= -- attempts to escape are re
(chime--process-notifications events))
#+end_src
+** State isolation
+
+Prefer lexical =let=, =with-chime-config=, =with-test-setup=, and event helpers
+over file-local setup/teardown functions that save globals into defvars. Dynamic
+bindings restore state automatically on both pass and failure, and helpers like
+=with-gathered-events= and =with-chime-tooltip-from-content= avoid repeating temp
+file and buffer cleanup logic.
+
* Important notes
-1. *Load path*: The Makefile automatically finds dependencies in =~/.emacs.d/elpa/=
+1. *Load path*: =make check-deps= verifies dependencies by requiring them inside Emacs, rather than assuming a package install directory.
2. *Fuzzy matching*: =test-file= and =test-one= support partial names
3. *Test logs*: Output saved to =test-output.log=, =test-file-output.log=, etc. in =tests/=
4. *Mock warnings*: "Redefining 'file-exists-p' might break native compilation" is normal and expected
@@ -292,13 +310,15 @@ All paths are sandboxed under =chime-test-base-dir= -- attempts to escape are re
* Dependencies
-Required packages (auto-detected by Makefile):
+Required packages (verified by =make check-deps=):
- =dash= (list manipulation)
- =alert= (notifications)
- =async= (async processes)
- =org-agenda= (built-in, events source)
-Use =make check-deps= (from =tests/=) to verify all dependencies are installed.
+Use =make check-deps= (from the project root or =tests/=) to verify all
+dependencies are loadable. If any are missing, run =make setup= from the project
+root or otherwise make the missing features available on Emacs' =load-path=.
* Test inventory
diff --git a/tests/Makefile b/tests/Makefile
index abf91bb..8fd2e0c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -55,7 +55,12 @@ check-deps:
printf "$(YELLOW)Warning: .eask not found — run 'make setup' from project root$(NC)\n"; \
exit 1; \
fi
- @printf "$(GREEN)✓ eask available, deps installed$(NC)\n"
+ @$(EMACS_BATCH) -l check-deps.el >$(PROJECT_ROOT)/tests/check-deps-output.log 2>&1 || { \
+ printf "$(RED)Error: required Emacs Lisp test dependencies are missing$(NC)\n"; \
+ cat $(PROJECT_ROOT)/tests/check-deps-output.log; \
+ exit 1; \
+ }
+ @printf "$(GREEN)✓ eask available, required Emacs Lisp deps loadable$(NC)\n"
# Run all tests (excluding :slow)
test: check-deps
@@ -260,7 +265,7 @@ lint: check-deps
clean:
@printf "$(YELLOW)Cleaning byte-compiled files...$(NC)\n"
@rm -f *.elc ../*.elc
- @rm -f test-output.log test-file-output.log test-unit-output.log test-integration-output.log
+ @rm -f check-deps-output.log test-output.log test-file-output.log test-unit-output.log test-integration-output.log
@printf "$(GREEN)✓ Cleaned$(NC)\n"
# Show help
@@ -280,7 +285,7 @@ help:
@echo " make count - Count tests per file"
@echo " make list - List all test names"
@echo " make clean - Remove byte-compiled files and logs"
- @echo " make check-deps - Verify eask + installed deps"
+ @echo " make check-deps - Verify eask + loadable Emacs Lisp deps"
@echo " make help - Show this help message"
@echo ""
@echo "Project-root targets (run from project root):"
diff --git a/tests/check-deps.el b/tests/check-deps.el
new file mode 100644
index 0000000..0cfa99c
--- /dev/null
+++ b/tests/check-deps.el
@@ -0,0 +1,38 @@
+;;; check-deps.el --- Verify test dependencies are loadable -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 Craig Jennings
+
+;;; Commentary:
+
+;; Loaded by tests/Makefile's check-deps target after eask has prepared the
+;; test environment. Keep dependency discovery inside Emacs so package.el,
+;; package-vc, Eask, Nix, and pre-populated load-path setups all work the same
+;; way: a dependency is available if Emacs can require it.
+
+;;; Code:
+
+(when noninteractive
+ (package-initialize))
+
+(defconst chime-check-deps-required-features
+ '(dash alert async org-agenda)
+ "Features required by the Chime test suite.")
+
+(defun chime-check-deps--missing-features ()
+ "Return required test features that cannot be loaded."
+ (let (missing)
+ (dolist (feature chime-check-deps-required-features (nreverse missing))
+ (unless (require feature nil t)
+ (push feature missing)))))
+
+(let ((missing (chime-check-deps--missing-features)))
+ (if missing
+ (progn
+ (message "Missing Emacs Lisp test dependencies: %s"
+ (mapconcat #'symbol-name missing ", "))
+ (message "Run `make setup' from the project root, or make these features available on load-path.")
+ (kill-emacs 1))
+ (message "Required Emacs Lisp dependencies are loadable: %s"
+ (mapconcat #'symbol-name chime-check-deps-required-features ", "))))
+
+;;; check-deps.el ends here
diff --git a/tests/test-testutil-general.el b/tests/test-testutil-general.el
new file mode 100644
index 0000000..7b4e445
--- /dev/null
+++ b/tests/test-testutil-general.el
@@ -0,0 +1,49 @@
+;;; test-testutil-general.el --- Tests for shared test file utilities -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 Craig Jennings
+
+;;; Commentary:
+
+;; Tests for the shared filesystem helpers in testutil-general.el.
+
+;;; Code:
+
+(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))
+(require 'testutil-general (expand-file-name "testutil-general.el"))
+
+(ert-deftest test-chime-test-default-base-dir-uses-env-override ()
+ "Normal: CHIME_TEST_TMPDIR selects an explicit test root."
+ (cl-letf (((symbol-function 'getenv)
+ (lambda (name)
+ (when (string= name "CHIME_TEST_TMPDIR")
+ "/tmp/chime-explicit-root"))))
+ (should (equal "/tmp/chime-explicit-root/"
+ (chime-test--default-base-dir)))))
+
+(ert-deftest test-chime-test-default-base-dir-uses-temporary-directory ()
+ "Normal: absent override uses a unique temp-directory path."
+ (let ((temporary-file-directory "/tmp/chime-parent/"))
+ (cl-letf (((symbol-function 'getenv) (lambda (_name) nil)))
+ (should (string-prefix-p
+ "/tmp/chime-parent/chime-tests-"
+ (chime-test--default-base-dir))))))
+
+(ert-deftest test-chime-test-base-dir-is-not-fixed-home-path ()
+ "Regression: default test root is no longer ~/.temp-chime-tests/."
+ (skip-unless (not (getenv "CHIME_TEST_TMPDIR")))
+ (should-not
+ (equal (expand-file-name "~/.temp-chime-tests/")
+ chime-test-base-dir)))
+
+(ert-deftest test-chime-test-base-dir-create-and-delete-roundtrip ()
+ "Normal: create and delete work for the configured test root."
+ (unwind-protect
+ (progn
+ (should (equal (file-name-as-directory chime-test-base-dir)
+ (chime-create-test-base-dir)))
+ (should (file-directory-p chime-test-base-dir)))
+ (chime-delete-test-base-dir))
+ (should-not (file-exists-p chime-test-base-dir)))
+
+(provide 'test-testutil-general)
+;;; test-testutil-general.el ends here
diff --git a/tests/testutil-general.el b/tests/testutil-general.el
index 556e520..2fffbca 100644
--- a/tests/testutil-general.el
+++ b/tests/testutil-general.el
@@ -6,22 +6,37 @@
;; This library provides general helper functions and constants for managing
;; test directories and files across test suites.
;;
-;; It establishes a user-local hidden directory as the root for all test assets,
-;; provides utilities to create this directory safely, create temporary files
-;; and subdirectories within it, and clean up after tests.
+;; It establishes a per-process temporary directory as the root for all test
+;; assets, provides utilities to create this directory safely, create temporary
+;; files and subdirectories within it, and clean up after tests.
;;
;; This library should be required by test suites to ensure consistent,
;; reliable, and isolated file-system resources.
;;
;;; Code:
+(defun chime-test--default-base-dir ()
+ "Return the default base directory for CHIME test files.
+When CHIME_TEST_TMPDIR is set and non-empty, use it as an explicit
+override. Otherwise use a unique process-local directory under
+`temporary-file-directory' so test runs do not write into the user's home
+or collide with other runs."
+ (let ((override (getenv "CHIME_TEST_TMPDIR")))
+ (file-name-as-directory
+ (expand-file-name
+ (if (and override (> (length override) 0))
+ override
+ (make-temp-name
+ (expand-file-name
+ (format "chime-tests-%s-" (emacs-pid))
+ temporary-file-directory)))))))
+
(defconst chime-test-base-dir
- (expand-file-name "~/.temp-chime-tests/")
+ (chime-test--default-base-dir)
"Base directory for all CHIME test files and directories.
-All test file-system artifacts should be created under this hidden
-directory in the user's home. This avoids relying on ephemeral system
-directories like /tmp and reduces flaky test failures caused by external
-cleanup.")
+All test file-system artifacts should be created under this directory.
+Set CHIME_TEST_TMPDIR to force a specific root; otherwise a unique
+process-local directory under `temporary-file-directory' is used.")
(defun chime-create-test-base-dir ()
"Create the test base directory `chime-test-base-dir' if it does not exist.