1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
;;; test-chime-async-injection.el --- Tests for async environment injection -*- lexical-binding: t; -*-
;; Copyright (C) 2024-2026 Craig Jennings
;; Author: Craig Jennings <c@cjennings.net>
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;; Commentary:
;; Tests that every chime defcustom the async child reads is injected into
;; the child by `chime--environment-regex'.
;;
;; The child calls (require 'chime), so an uninjected defcustom is still
;; *bound* there -- at its default. A user who customizes it sees no error
;; and no effect, which is the worst shape a bug can take. That is exactly
;; what happened to chime-tooltip-lookahead-hours: the docstring invites
;; 8760 "to see distant events", and the child kept fetching 168 hours.
;;
;; The load-bearing test walks the child form and fails on any chime
;; defcustom it reads that the regex doesn't cover, so a variable added to
;; the child later cannot reintroduce the bug quietly.
;;; Code:
(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))
;;; Helpers
(defun test-chime-injection--symbols (form)
"Return every symbol appearing anywhere in FORM."
(cond
((symbolp form) (and form (list form)))
((consp form) (append (test-chime-injection--symbols (car form))
(test-chime-injection--symbols (cdr form))))
(t nil)))
(defun test-chime-injection--chime-defcustoms (form)
"Return the chime defcustoms appearing in FORM, deduplicated."
(seq-uniq
(seq-filter (lambda (sym)
(and (custom-variable-p sym)
(string-prefix-p "chime-" (symbol-name sym))))
(test-chime-injection--symbols form))))
;;; Normal Cases
(ert-deftest test-chime-async-injection-covers-every-chime-defcustom-in-the-child ()
"Every chime defcustom the async child reads is injected into it.
An uninjected one silently runs at its default in the child, so a user's
customization is ignored without any error."
(let* ((form (chime--retrieve-events))
(regex (chime--environment-regex))
(uncovered (seq-remove
(lambda (sym) (string-match-p regex (symbol-name sym)))
(test-chime-injection--chime-defcustoms form))))
(should-not uncovered)))
(ert-deftest test-chime-async-injection-covers-the-lookahead-variables ()
"Both lookahead variables reach the child.
The child sizes its agenda span from them, so without injection it fetches
the default 168-hour window no matter what the user set."
(let ((regex (chime--environment-regex)))
(should (string-match-p regex "chime-modeline-lookahead-minutes"))
(should (string-match-p regex "chime-tooltip-lookahead-hours"))))
(ert-deftest test-chime-async-injection-covers-the-pre-existing-variables ()
"The variables injected before the lookahead fix still are."
(let ((regex (chime--environment-regex)))
(dolist (name '("org-agenda-files" "load-path" "org-todo-keywords"
"chime-alert-intervals" "chime-include-filters"
"chime-exclude-filters"))
(should (string-match-p regex name)))))
;;; Boundary Cases
(ert-deftest test-chime-async-injection-regex-is-anchored ()
"The regex matches whole variable names, not substrings.
Without anchoring, a user's unrelated `my-org-agenda-files-backup' would
be swept into the child."
(let ((regex (chime--environment-regex)))
(should-not (string-match-p regex "my-org-agenda-files"))
(should-not (string-match-p regex "org-agenda-files-extra"))))
(ert-deftest test-chime-async-injection-honors-additional-regexes ()
"`chime-additional-environment-regexes' extends the injected set."
(let* ((chime-additional-environment-regexes '("\\`my-var\\'"))
(regex (chime--environment-regex)))
(should (string-match-p regex "my-var"))
(should (string-match-p regex "org-agenda-files"))))
(provide 'test-chime-async-injection)
;;; test-chime-async-injection.el ends here
|