diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-11 05:40:24 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-11 05:40:24 -0500 |
| commit | ee90de269e4f65a9b57b4fc9e260d3aa6948b6ca (patch) | |
| tree | 6f16459e8bf47a6925131ccc743b59e33cd9b9ae /tests | |
| parent | 73faba8658ea783bca8392e4d4cc14cf7f94a48f (diff) | |
| download | chime-ee90de269e4f65a9b57b4fc9e260d3aa6948b6ca.tar.gz chime-ee90de269e4f65a9b57b4fc9e260d3aa6948b6ca.zip | |
feat: add per-event :CHIME_NOTIFY_BEFORE: interval override
Chime's migration from org-wild-notifier dropped the per-event notify-before property, so a heading could no longer override the global chime-alert-intervals. I brought it back.
A heading's :CHIME_NOTIFY_BEFORE: N (a non-negative integer) means "notify once, N minutes before, severity medium" and replaces chime-alert-intervals for that event. The org-wild-notifier name :WILD_NOTIFIER_NOTIFY_BEFORE: still works, as a deprecated alias. When it supplies the value, chime emits one per-session warning pointing at the new name. :CHIME_NOTIFY_BEFORE: wins when both are set. A malformed value logs a message naming the heading and falls back to the global.
chime--gather-info reads the property in the async child. The deprecation flag rides on the event alist so the parent emits the warning without changing the async return contract.
I also touched two test files. test-chime-async-helpers.el's fixtures fed bare symbols where chime--handle-async-success now expects event alists, so they build real events via chime--make-event. And the new test file's message-capture macro had a lexical-scoping bug (the captured list was invisible after the macro returned), so the two affected tests inline the capture and the macro is gone.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-chime-async-helpers.el | 59 | ||||
| -rw-r--r-- | tests/test-chime-intervals-for-marker.el | 49 |
2 files changed, 63 insertions, 45 deletions
diff --git a/tests/test-chime-async-helpers.el b/tests/test-chime-async-helpers.el index 86c5ed8..3e0e562 100644 --- a/tests/test-chime-async-helpers.el +++ b/tests/test-chime-async-helpers.el @@ -27,21 +27,32 @@ ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) +(require 'testutil-time (expand-file-name "testutil-time.el")) ;;; Setup and Teardown (defun test-chime-async-helpers-setup () - "Reset counters and modeline state before each test." + "Reset counters, modeline state, and the deprecation-warning guard before each test." (setq chime--consecutive-async-failures 0) (setq chime-max-consecutive-failures 5) (setq chime-modeline-no-events-text "*") - (setq chime-modeline-string nil)) + (setq chime-modeline-string nil) + (setq chime--deprecated-property-warned nil)) (defun test-chime-async-helpers-teardown () - "Restore default state after each test." + "Restore default state after each test, including the deprecation-warning guard." (setq chime--consecutive-async-failures 0) (setq chime-max-consecutive-failures 5) - (setq chime-modeline-string nil)) + (setq chime-modeline-string nil) + (setq chime--deprecated-property-warned nil)) + +(defun test-chime-async-helpers--event (title &optional deprecated-property) + "Build a minimal valid Chime event alist with TITLE. +DEPRECATED-PROPERTY, when given, marks the event as having used a +deprecated per-event property of that name." + (let ((time (test-time-tomorrow-at 14 0))) + (chime--make-event (list (cons (test-timestamp-string time) time)) + title '((10 . medium)) nil nil deprecated-property))) ;;;; Tests for chime--record-async-failure @@ -103,19 +114,22 @@ (setq chime--consecutive-async-failures 3) (chime--handle-async-success (lambda (events) (setq called-with events)) - '(event1 event2)) + (list (test-chime-async-helpers--event "A") + (test-chime-async-helpers--event "B"))) (should (= 0 chime--consecutive-async-failures))) (test-chime-async-helpers-teardown))) (ert-deftest test-chime-handle-async-success-normal-invokes-callback-with-events () - "Normal: calls the supplied callback with the events list." + "Normal: calls the supplied callback with the events list verbatim." (test-chime-async-helpers-setup) (unwind-protect - (let ((called-with 'unset)) + (let* ((called-with 'unset) + (events (list (test-chime-async-helpers--event "A") + (test-chime-async-helpers--event "B")))) (chime--handle-async-success - (lambda (events) (setq called-with events)) - '(a b c)) - (should (equal '(a b c) called-with))) + (lambda (e) (setq called-with e)) + events) + (should (eq events called-with))) (test-chime-async-helpers-teardown))) (ert-deftest test-chime-handle-async-success-boundary-empty-events () @@ -134,13 +148,30 @@ "Boundary: counter starts at zero, stays at zero, callback still fires." (test-chime-async-helpers-setup) (unwind-protect - (let ((called-with 'unset)) + (let* ((called-with 'unset) + (events (list (test-chime-async-helpers--event "X")))) (setq chime--consecutive-async-failures 0) (chime--handle-async-success - (lambda (events) (setq called-with events)) - '(x)) + (lambda (e) (setq called-with e)) + events) (should (= 0 chime--consecutive-async-failures)) - (should (equal '(x) called-with))) + (should (eq events called-with))) + (test-chime-async-helpers-teardown))) + +(ert-deftest test-chime-handle-async-success-normal-warns-on-deprecated-property () + "Normal: warns once when an event used a deprecated per-event property." + (test-chime-async-helpers-setup) + (unwind-protect + (let ((warned nil)) + (cl-letf (((symbol-function 'display-warning) + (lambda (_type msg &rest _) (push msg warned)))) + (chime--handle-async-success + #'ignore + (list (test-chime-async-helpers--event "A") + (test-chime-async-helpers--event "B" "WILD_NOTIFIER_NOTIFY_BEFORE")))) + (should (= 1 (length warned))) + (should (string-match-p "WILD_NOTIFIER_NOTIFY_BEFORE" (car warned))) + (should chime--deprecated-property-warned)) (test-chime-async-helpers-teardown))) (provide 'test-chime-async-helpers) diff --git a/tests/test-chime-intervals-for-marker.el b/tests/test-chime-intervals-for-marker.el index 1d74077..9b73394 100644 --- a/tests/test-chime-intervals-for-marker.el +++ b/tests/test-chime-intervals-for-marker.el @@ -32,20 +32,22 @@ ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) +(require 'testutil-time (expand-file-name "testutil-time.el")) (require 'cl-lib) ;;; Helpers (defun test-chime-intervals--org-heading-with-props (props) "Return org content for one heading whose drawer carries PROPS. -PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer." +PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer. +A dynamic timestamp is appended so `chime--gather-info' has one to extract." (concat "* Test Heading\n" (when props (concat ":PROPERTIES:\n" (mapconcat (lambda (p) (format ":%s: %s\n" (car p) (cdr p))) props "") ":END:\n")) - "<2026-05-12 Tue 14:00>\n")) + (test-timestamp-string (test-time-tomorrow-at 14 0)) "\n")) (defmacro test-chime-intervals--with-marker (props &rest body) "Run BODY in a temp org buffer with a heading carrying PROPS; bind `marker'." @@ -57,16 +59,6 @@ PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer." (let ((marker (point-marker))) ,@body))) -(defmacro test-chime-intervals--capture-messages (var &rest body) - "Run BODY with `message' calls captured into VAR (chronological)." - (declare (indent 1) (debug t)) - `(let ((,var nil)) - (cl-letf (((symbol-function 'message) - (lambda (fmt &rest args) - (push (apply #'format fmt args) ,var)))) - ,@body) - (setq ,var (nreverse ,var)))) - ;;; chime--parse-notify-before-value (ert-deftest test-chime-parse-notify-before-value-normal-and-boundary () @@ -116,18 +108,22 @@ PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer." (ert-deftest test-chime-intervals-for-marker-error-malformed-canonical-falls-back () "Error: a malformed :CHIME_NOTIFY_BEFORE: value logs and falls back to the global." - (let ((chime-alert-intervals '((10 . medium)))) + (let ((chime-alert-intervals '((10 . medium))) + (messages nil)) (test-chime-intervals--with-marker '(("CHIME_NOTIFY_BEFORE" . "soon")) - (test-chime-intervals--capture-messages messages + (cl-letf (((symbol-function 'message) + (lambda (fmt &rest args) (push (apply #'format fmt args) messages)))) (should (equal (cons '((10 . medium)) nil) (chime--intervals-for-marker marker)))) (should (cl-some (lambda (m) (string-match-p "CHIME_NOTIFY_BEFORE" m)) messages))))) (ert-deftest test-chime-intervals-for-marker-error-malformed-alias-falls-back () "Error: a malformed deprecated-alias value logs and falls back to the global." - (let ((chime-alert-intervals '((10 . medium)))) + (let ((chime-alert-intervals '((10 . medium))) + (messages nil)) (test-chime-intervals--with-marker '(("WILD_NOTIFIER_NOTIFY_BEFORE" . "-3")) - (test-chime-intervals--capture-messages messages + (cl-letf (((symbol-function 'message) + (lambda (fmt &rest args) (push (apply #'format fmt args) messages)))) (should (equal (cons '((10 . medium)) nil) (chime--intervals-for-marker marker)))) (should (cl-some (lambda (m) (string-match-p "WILD_NOTIFIER_NOTIFY_BEFORE" m)) messages))))) @@ -136,21 +132,15 @@ PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer." (ert-deftest test-chime-gather-info-integration-applies-canonical-override () "Integration: a heading with :CHIME_NOTIFY_BEFORE: 25 gathers an event with ((25 . medium))." - (with-temp-buffer - (org-mode) - (insert "* Meeting\n:PROPERTIES:\n:CHIME_NOTIFY_BEFORE: 25\n:END:\n<2026-05-12 Tue 14:00>\n") - (goto-char (point-min)) - (let ((event (chime--gather-info (point-marker)))) + (test-chime-intervals--with-marker '(("CHIME_NOTIFY_BEFORE" . "25")) + (let ((event (chime--gather-info marker))) (should (equal '((25 . medium)) (chime--event-intervals event))) (should-not (chime--event-deprecated-property event))))) (ert-deftest test-chime-gather-info-integration-flags-deprecated-alias () "Integration: a heading with the deprecated alias gathers an event carrying the deprecation flag." - (with-temp-buffer - (org-mode) - (insert "* Meeting\n:PROPERTIES:\n:WILD_NOTIFIER_NOTIFY_BEFORE: 20\n:END:\n<2026-05-12 Tue 14:00>\n") - (goto-char (point-min)) - (let ((event (chime--gather-info (point-marker)))) + (test-chime-intervals--with-marker '(("WILD_NOTIFIER_NOTIFY_BEFORE" . "20")) + (let ((event (chime--gather-info marker))) (should (equal '((20 . medium)) (chime--event-intervals event))) (should (string= "WILD_NOTIFIER_NOTIFY_BEFORE" (chime--event-deprecated-property event)))))) @@ -158,11 +148,8 @@ PROPS is a list of (NAME . VALUE) string pairs, or nil for no drawer." (ert-deftest test-chime-gather-info-integration-no-override-uses-global () "Integration: a heading without the property gathers with chime-alert-intervals." (let ((chime-alert-intervals '((10 . medium) (0 . high)))) - (with-temp-buffer - (org-mode) - (insert "* Meeting\n<2026-05-12 Tue 14:00>\n") - (goto-char (point-min)) - (let ((event (chime--gather-info (point-marker)))) + (test-chime-intervals--with-marker nil + (let ((event (chime--gather-info marker))) (should (equal '((10 . medium) (0 . high)) (chime--event-intervals event))) (should-not (chime--event-deprecated-property event)))))) |
