diff options
Diffstat (limited to 'tests/test-org-agenda-frame.el')
| -rw-r--r-- | tests/test-org-agenda-frame.el | 125 |
1 files changed, 115 insertions, 10 deletions
diff --git a/tests/test-org-agenda-frame.el b/tests/test-org-agenda-frame.el index 21842600..3c56d361 100644 --- a/tests/test-org-agenda-frame.el +++ b/tests/test-org-agenda-frame.el @@ -121,14 +121,50 @@ (should (equal (nth 0 (cj/--agenda-frame-command)) "F"))) (ert-deftest test-org-agenda-frame-command-today-anchored-7-day () - "Normal: the span is seven days anchored to today, not Monday." + "Normal: the default span is seven days anchored to today, not Monday. +The span is the frame-span variable (default 7), evaluated the way org +evaluates custom-command settings." (let ((s (test-org-agenda-frame--block-settings))) - (should (equal (cadr (assq 'org-agenda-span s)) 7)) + (should (equal (default-value 'cj/--agenda-frame-span) 7)) + (should (equal (eval (cadr (assq 'org-agenda-span s)) t) + (default-value 'cj/--agenda-frame-span))) (should (equal (cadr (assq 'org-agenda-start-day s)) "0d")) ;; start-on-weekday nil is what un-anchors the span from Monday. (should (assq 'org-agenda-start-on-weekday s)) (should (null (cadr (assq 'org-agenda-start-on-weekday s)))))) +(ert-deftest test-org-agenda-frame-command-span-follows-variable () + "Normal: the block span reads `cj/--agenda-frame-span', so d/w can change it +and a redo -- which re-evaluates the lprops -- picks up the new span." + (let ((cj/--agenda-frame-span 1)) + (should (equal (eval (cadr (assq 'org-agenda-span + (test-org-agenda-frame--block-settings))) + t) + 1))) + (let ((cj/--agenda-frame-span 7)) + (should (equal (eval (cadr (assq 'org-agenda-span + (test-org-agenda-frame--block-settings))) + t) + 7)))) + +(ert-deftest test-org-agenda-frame-day-view-sets-span-1-and-redoes () + "Normal: d sets the span to one day and refreshes via the safe redo." + (let ((cj/--agenda-frame-span 7) redone) + (cl-letf (((symbol-function 'cj/--agenda-frame-safe-redo) + (lambda (&rest _) (setq redone t)))) + (cj/--agenda-frame-day-view) + (should (equal cj/--agenda-frame-span 1)) + (should redone)))) + +(ert-deftest test-org-agenda-frame-week-view-sets-span-7-and-redoes () + "Normal: w restores the seven-day span and refreshes." + (let ((cj/--agenda-frame-span 1) redone) + (cl-letf (((symbol-function 'cj/--agenda-frame-safe-redo) + (lambda (&rest _) (setq redone t)))) + (cj/--agenda-frame-week-view) + (should (equal cj/--agenda-frame-span 7)) + (should redone)))) + (ert-deftest test-org-agenda-frame-command-tight-prefix-format () "Normal: the view sets its own prefix format with a narrow category column. Without it the global agenda format applies, whose 25-char category pad @@ -212,7 +248,7 @@ the spawn wrapper, where it names the buffer." (cl-letf (((symbol-function 'message) (lambda (fmt &rest args) (setq captured (apply #'format fmt args))))) (cj/--agenda-frame-denied-fixed-view)) - (should (string-match-p "7-day view" captured)))) + (should (string-match-p "day (d) and week (w)" captured)))) ;;; Default-deny policy — the keymap @@ -255,19 +291,58 @@ graphical frame and RET would be denied instead of opening the item." 'cj/--agenda-frame-engage-open))) (ert-deftest test-org-agenda-frame-map-lifecycle-keys () - "Normal: q/Q/x close the frame; r takes the safe-redo path." + "Normal: q/Q/x close the frame; r and g take the safe-redo path. +g is the muscle-memory agenda refresh; it must refresh, not hit the +fixed-view deny handler." (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "q")) 'cj/--agenda-frame-close)) (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "Q")) 'cj/--agenda-frame-close)) (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "x")) 'cj/--agenda-frame-close)) - (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "r")) 'cj/--agenda-frame-safe-redo))) + (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "r")) 'cj/--agenda-frame-safe-redo)) + (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "g")) 'cj/--agenda-frame-safe-redo))) (ert-deftest test-org-agenda-frame-map-view-changers-fixed-view-deny () "Boundary: view-changing keys are explicitly denied with the fixed-view message, not caught by the read-only catch-all." - (dolist (key '("w" "d" "y" "f" "b" "j" "g")) + (dolist (key '("y" "f" "b" "j")) (should (eq (lookup-key cj/agenda-frame-mode-map (kbd key)) 'cj/--agenda-frame-denied-fixed-view)))) +(ert-deftest test-org-agenda-frame-map-day-week-view-keys () + "Normal: d and w toggle the span (day / week) rather than being denied. +d shrinks the frame to the current day, w restores the seven-day span." + (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "d")) + 'cj/--agenda-frame-day-view)) + (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "w")) + 'cj/--agenda-frame-week-view))) + +(ert-deftest test-org-agenda-frame-shadow-denies-org-mutations-preserves-allowlist () + "Boundary: with the frame mode active over `org-agenda-mode-map', mutating +org-agenda keys are denied and the allowlist still works. +The `[t]' default cannot shadow org-agenda-mode-map's explicit bindings, so +the shadow walk must add explicit denies for every non-allowlisted key -- +single keys (t/I/k/z/s/.), the C-c mutators (schedule/deadline/clock), and +C-x (save-all) -- while leaving the allowlist (navigation, engage, refresh, +d/w, C-c C-o) intact." + (require 'org-agenda) + (cj/--agenda-frame-shadow-mutations) + (with-temp-buffer + (use-local-map org-agenda-mode-map) + (cj/agenda-frame-mode 1) + ;; escaping mutators are now explicitly denied (not org's commands) + (dolist (chord '("t" "I" "k" "z" "s" "." "C-c C-s" "C-c C-d" + "C-c C-x C-i" "C-x C-s")) + (should (eq (key-binding (kbd chord)) + 'cj/--agenda-frame-denied-readonly))) + ;; the allowlist survives the walk + (should (eq (key-binding (kbd "n")) 'org-agenda-next-line)) + (should (eq (key-binding (kbd "p")) 'org-agenda-previous-line)) + (should (eq (key-binding (kbd "RET")) 'cj/--agenda-frame-engage-open)) + (should (eq (key-binding (kbd "g")) 'cj/--agenda-frame-safe-redo)) + (should (eq (key-binding (kbd "d")) 'cj/--agenda-frame-day-view)) + (should (eq (key-binding (kbd "w")) 'cj/--agenda-frame-week-view)) + (should (eq (key-binding (kbd "C-c C-o")) 'cj/--agenda-frame-open-link)) + (should (eq (key-binding (kbd "q")) 'cj/--agenda-frame-close)))) + (ert-deftest test-org-agenda-frame-map-frame-controls-bound () "Normal: the frame's own controls work from inside the frame. S-<f8> must close/toggle and C-M-<f8> must force-rescan; unbound, the @@ -301,6 +376,16 @@ scroll spams the deny message." ;; global map); an unpunched key returns the catch-all deny handler. (should (null (lookup-key cj/agenda-frame-mode-map key t))))) +(ert-deftest test-org-agenda-frame-map-global-escape-chords-denied () + "Boundary: global chords bound elsewhere (M-SPC / M-S-SPC swap ai-term +agents) are denied by an explicit binding, not left to the [t] catch-all. +A keymap's default binding does not shadow an explicit binding in a +lower-priority map, so without an explicit deny here M-SPC follows its +global binding and escapes the read-only frame into ai-term." + (dolist (key '("M-SPC" "M-S-SPC")) + (should (eq (lookup-key cj/agenda-frame-mode-map (kbd key)) + 'cj/--agenda-frame-denied-readonly)))) + (ert-deftest test-org-agenda-frame-map-unpunched-still-denied () "Normal: an ordinary unbound key still hits the catch-all after the punches." (should (eq (lookup-key cj/agenda-frame-mode-map (kbd "t") t) @@ -333,10 +418,15 @@ removed after a later success -- the failure banner would stick forever." (should (= 0 (seq-count (lambda (o) (overlay-get o 'before-string)) (overlays-in (point-min) (point-max))))))) -(ert-deftest test-org-agenda-frame-map-mutation-keys-not-explicitly-bound () - "Boundary: a mutation key (t = org-agenda-todo) is not explicitly bound, so the -[t] catch-all denies it as read-only." - (should (null (lookup-key cj/agenda-frame-mode-map (kbd "t"))))) +(ert-deftest test-org-agenda-frame-map-mutation-keys-denied () + "Boundary: a mutation key (t = org-agenda-todo) is denied, never allowlisted. +It is denied two ways depending on whether the shadow walk has run: the `[t]' +catch-all handles it (lookup returns nil) before the walk, and the walk binds +it explicitly to the deny handler once `org-agenda-mode-map' is present. Both +are a read-only denial; the test asserts the outcome, not which path produced +it, so it holds whether or not org-agenda is loaded in the test process." + (let ((b (lookup-key cj/agenda-frame-mode-map (kbd "t")))) + (should (or (null b) (eq b 'cj/--agenda-frame-denied-readonly))))) ;;; Default-deny policy — the minor mode + finalize re-enable @@ -931,6 +1021,21 @@ showing the launch buffer." (cj/--agenda-frame-spawn) (should collapsed)))) +(ert-deftest test-org-agenda-frame-spawn-resets-span-to-7 () + "Normal: a fresh spawn opens at the documented seven-day default, even when a +prior frame's session left `cj/--agenda-frame-span' at the day view." + (let ((cj/--agenda-frame-span 1)) + (cl-letf (((symbol-function 'selected-frame) (lambda () 'launch)) + ((symbol-function 'make-frame) (lambda (&rest _) 'af)) + ((symbol-function 'select-frame-set-input-focus) (lambda (_f &rest _) nil)) + ((symbol-function 'cj/build-org-agenda-list) (lambda (&rest _) nil)) + ((symbol-function 'org-agenda) (lambda (&rest _) nil)) + ((symbol-function 'delete-other-windows) (lambda (&rest _) nil)) + ((symbol-function 'cj/--agenda-frame-sticky-buffer) (lambda () nil)) + ((symbol-function 'cj/--agenda-frame-start-timer) (lambda (_f) nil))) + (cj/--agenda-frame-spawn) + (should (equal cj/--agenda-frame-span 7))))) + (ert-deftest test-org-agenda-frame-spawn-starts-timer () "Normal: a successful spawn starts the refresh timer for the new frame." (let (timed) |
