diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-31 11:04:42 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-31 11:04:42 -0500 |
| commit | 445a0be315f3d6fff585f1558262fb5dacd10d12 (patch) | |
| tree | ca12cae724f4516f30e3e0995436bb89fef6ed71 /tests/test-agenda-query--render.el | |
| parent | 37f21839ca62617fef07684b2f98268de47a71c2 (diff) | |
| download | dotemacs-445a0be315f3d6fff585f1558262fb5dacd10d12.tar.gz dotemacs-445a0be315f3d6fff585f1558262fb5dacd10d12.zip | |
feat(agenda): refresh the render cache on a timer, without the daemon
The surface reading this has to stay correct while Emacs is down, and
emacsclient is exactly the thing that cannot. So the writer is a batch
Emacs and a user timer runs it every five minutes.
- scripts/agenda-render-cache writes the cache from a batch Emacs. It
resolves the agenda file list through the config's own resolver rather
than restating it, so adding a calendar source stays a one-place change.
- The timer uses OnCalendar so Persistent actually applies. On a monotonic
schedule it is silently ignored, and a machine that slept would come back
to a stale file with nothing to trigger a catch-up.
- The window is now three days, yesterday through tomorrow. A consumer
drawing a rolling window centred on now has nothing to draw for the part
of its span outside today, which late in the evening is half the surface.
The keyword list moved to user-constants, where a batch Emacs can reach it
without this config's package dependencies. Without it org did not
recognise DOING or VERIFY, so it stopped parsing those headlines as tasks
at all: the keyword and priority cookie stayed glued to the front of every
title and each row reported no keyword and not-done. The file parsed
cleanly and was wrong, which is the failure worth guarding.
The bats tests run against a fixture and this checkout, not the machine's
real agenda and installed config. Asserting over live data let the same
suite pass on a day that happened to have no keyworded entries.
Diffstat (limited to 'tests/test-agenda-query--render.el')
| -rw-r--r-- | tests/test-agenda-query--render.el | 64 |
1 files changed, 52 insertions, 12 deletions
diff --git a/tests/test-agenda-query--render.el b/tests/test-agenda-query--render.el index 1f7232f2..48d28773 100644 --- a/tests/test-agenda-query--render.el +++ b/tests/test-agenda-query--render.el @@ -26,6 +26,9 @@ (add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) (require 'agenda-query) +;; Supplies `cj/org-todo-keywords', the vocabulary the batch writer sets and +;; the editor's org config reads. +(require 'user-constants) (defun test-aq-render--epoch (min hour day month year) "Return the epoch for local MIN HOUR DAY MONTH YEAR." @@ -136,10 +139,43 @@ The renderer parses the same shape whether or not anything is scheduled." (let ((org-agenda-files nil)) (should (equal "[]" (cj/agenda-render-json 1785474000 1785477600))))) +;;; ---------- the batch reader has to know the keyword vocabulary ---------- + +(ert-deftest test-agenda-render-normal-custom-keyword-is-parsed () + "Normal: a config keyword is recognised, so it leaves the title. + +The batch writer runs without the editor's init, so it has to set +`org-todo-keywords' itself. When it does not, org stops parsing the headline +as a task at all: DOING and the priority cookie stay glued to the front of the +title and the row reads as having no keyword. That is a wrong answer that +still parses as JSON, which is the worst kind." + (let ((org-todo-keywords cj/org-todo-keywords)) + (test-aq-render--with-agenda-file + "* DOING [#A] Justin Johns advisor projects\nSCHEDULED: <2026-07-31 Fri 09:00>\n" + (let ((row (car rows))) + (should (equal "Justin Johns advisor projects" (alist-get 't row))) + (should (equal "DOING" (alist-get 'keyword row))))))) + +(ert-deftest test-agenda-render-boundary-unknown-keyword-stays-in-title () + "Boundary: with stock keywords the same headline degrades visibly. + +Pinning the failure mode, not endorsing it. This is what the surface showed +before the batch writer learned the vocabulary, and it is why the test above +exists." + (let ((org-todo-keywords '((sequence "TODO" "|" "DONE")))) + (test-aq-render--with-agenda-file + "* DOING [#A] Justin Johns advisor projects\nSCHEDULED: <2026-07-31 Fri 09:00>\n" + (should (string-prefix-p "DOING" (alist-get 't (car rows))))))) + ;;; ---------- the cache writer ---------- (ert-deftest test-agenda-render-normal-cache-update-writes-today () - "Normal: the cache writer covers the whole local day and creates its dir. + "Normal: the cache writer covers three whole local days and creates its dir. + +Yesterday's midnight through tomorrow's day close. A consumer drawing a +rolling window centred on now needs both sides of midnight: with a single +calendar day, the part of its span outside today has nothing to draw, which +late in the evening is half the surface. This is the function that actually ships the feature, so it gets its own coverage rather than riding on the tests for the profile beneath it. The @@ -161,19 +197,23 @@ or the next 24 from now, would still produce a plausible-looking file." (cj/agenda-render-cache-update))) (should (file-exists-p cj/agenda-render-cache-file)) (let* ((window (car windows)) - (d (decode-time (car window)))) + (start (decode-time (car window))) + (now (decode-time))) ;; Opens at local midnight... - (should (= 0 (nth 2 d))) - (should (= 0 (nth 1 d))) - (should (= 0 (nth 0 d))) - ;; ...and closes one second before the next. + (should (= 0 (nth 2 start))) + (should (= 0 (nth 1 start))) + (should (= 0 (nth 0 start))) + ;; ...on yesterday, and closes at the end of tomorrow. + (should (= (car window) + (cj/--agenda-query-epoch + 0 0 0 (1- (nth 3 now)) (nth 4 now) (nth 5 now)))) (should (= (cdr window) - (1- (cj/--agenda-query-epoch - 0 0 0 (1+ (nth 3 d)) (nth 4 d) (nth 5 d))))) - ;; It is today's day, not an arbitrary one. - (should (equal (list (nth 3 d) (nth 4 d) (nth 5 d)) - (let ((now (decode-time))) - (list (nth 3 now) (nth 4 now) (nth 5 now))))))) + (cj/--agenda-query-day-close + (1+ (nth 3 now)) (nth 4 now) (nth 5 now)))) + ;; Three whole days, give or take an hour at a DST changeover. + (let ((hours (/ (- (cdr window) (car window)) 3600.0))) + (should (>= hours 70.9)) + (should (<= hours 73.1))))) (delete-directory dir t)))) (ert-deftest test-agenda-render-boundary-cache-update-is-idempotent () |
