diff options
Diffstat (limited to 'tests/test-ai-vterm--collapse-split.el')
| -rw-r--r-- | tests/test-ai-vterm--collapse-split.el | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/tests/test-ai-vterm--collapse-split.el b/tests/test-ai-vterm--collapse-split.el new file mode 100644 index 00000000..ad299e47 --- /dev/null +++ b/tests/test-ai-vterm--collapse-split.el @@ -0,0 +1,171 @@ +;;; test-ai-vterm--collapse-split.el --- F9 collapses the agent split -*- lexical-binding: t; -*- + +;;; Commentary: +;; Regression coverage for the F9 toggle-off behavior Craig reported: with +;; several agents alive, F9 should HIDE the agent split (collapse it back to the +;; working layout) rather than surfacing a different agent. Two cases: +;; +;; - Multi-window: the agent occupies a split. F9 deletes that window so the +;; working buffer reclaims the frame -- never swaps in another agent. The +;; prior `quit-restore-window' path went stale after the slot was reused +;; across agents (C-F9 switching), so it surfaced a different agent. +;; - Single-window: the agent fills the frame. F9 returns to the most-recent +;; NON-agent buffer (the file being worked on), not another agent -- the prior +;; `other-buffer' call could pick another live agent. +;; +;; Also covers the `cj/--ai-vterm-most-recent-non-agent-buffer' helper. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(add-to-list 'load-path (expand-file-name "tests" user-emacs-directory)) +(require 'ai-vterm) +(require 'testutil-vterm-buffers) + +;;; cj/--ai-vterm-most-recent-non-agent-buffer + +(ert-deftest test-ai-vterm--most-recent-non-agent-buffer-skips-agents () + "Normal: returns a live non-agent buffer even when agents are most-recent." + (cj/test--kill-agent-buffers) + (let ((work (get-buffer-create "*test-mrna-work*")) + (agent-a (get-buffer-create "agent [mrna-a]")) + (agent-b (get-buffer-create "agent [mrna-b]"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + ;; Make the agents most-recent in this window's history. + (set-window-buffer (selected-window) work) + (set-window-buffer (selected-window) agent-b) + (set-window-buffer (selected-window) agent-a) + (let ((result (cj/--ai-vterm-most-recent-non-agent-buffer))) + (should (bufferp result)) + (should (buffer-live-p result)) + (should-not (cj/--ai-vterm-buffer-p result)))) + (when (get-buffer "*test-mrna-work*") (kill-buffer "*test-mrna-work*")) + (cj/test--kill-agent-buffers)))) + +;;; Multi-window: F9 collapses the split + +(ert-deftest test-ai-vterm--collapse-multi-window-deletes-agent-split () + "Normal/Regression: agent in a bottom split with other agents alive; F9 +collapses the split so the working buffer reclaims the frame, and no agent is +surfaced. Before the fix, `quit-restore-window' could switch the slot to a +different agent (stale quit-restore after slot reuse)." + (cj/test--kill-agent-buffers) + (let ((work (get-buffer-create "*test-collapse-work*")) + (agent-a (get-buffer-create "agent [collapse-a]")) + (agent-b (get-buffer-create "agent [collapse-b]")) + (agent-c (get-buffer-create "agent [collapse-c]")) + (cj/--ai-vterm-last-was-bury nil)) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) work) + (let ((agent-win (split-window (selected-window) nil 'below))) + ;; Reuse the slot across agents (as C-F9 switching does) so the + ;; window's prev-buffer history holds another agent. + (set-window-buffer agent-win agent-a) + (set-window-buffer agent-win agent-b) + (set-window-buffer agent-win agent-c) + (select-window agent-win) + (should-not (one-window-p)) + (cj/test--call-as-gui #'cj/ai-vterm) + (should (one-window-p)) + (should-not (cj/--ai-vterm-displayed-agent-window)) + (should (eq (window-buffer (selected-window)) work)))) + (when (get-buffer "*test-collapse-work*") (kill-buffer "*test-collapse-work*")) + (cj/test--kill-agent-buffers)))) + +;;; Single-window: F9 returns to a non-agent buffer + +(ert-deftest test-ai-vterm--collapse-single-window-returns-non-agent () + "Normal/Regression: agent fills the frame, other agents alive; F9 toggles back +to a NON-agent buffer (the working file), never another agent. Before the fix, +`other-buffer' could pick another live agent." + (cj/test--kill-agent-buffers) + (let ((work (get-buffer-create "*test-collapse-sw-work*")) + (agent-a (get-buffer-create "agent [collapse-sw-a]")) + (agent-b (get-buffer-create "agent [collapse-sw-b]")) + (cj/--ai-vterm-last-was-bury nil)) + (unwind-protect + (save-window-excursion + (delete-other-windows) + ;; MRU: work, then agent-b, then agent-a (current). `other-buffer' + ;; would pick agent-b; the fix must skip it for a non-agent. + (set-window-buffer (selected-window) work) + (set-window-buffer (selected-window) agent-b) + (set-window-buffer (selected-window) agent-a) + (should (one-window-p)) + (let ((display-buffer-alist (cj/--ai-vterm-display-rule-list))) + (cj/test--call-as-gui #'cj/ai-vterm)) + (should (one-window-p)) + (should-not (cj/--ai-vterm-buffer-p (window-buffer (selected-window))))) + (when (get-buffer "*test-collapse-sw-work*") (kill-buffer "*test-collapse-sw-work*")) + (cj/test--kill-agent-buffers)))) + +;;; Faithful toggle: reopen the SAME agent that was hidden + +(ert-deftest test-ai-vterm--dispatch-prefers-last-hidden-agent () + "Regression: dispatch reopens the last-hidden agent, not the buffer-list MRU. +After F9 hides an agent, the next F9 must reopen the SAME one even when a +different agent is ahead of it in `buffer-list'. Falls back to the MRU when +nothing was hidden yet or the remembered buffer was killed." + (cj/test--kill-agent-buffers) + (let ((a1 (get-buffer-create "agent [disp-mru]")) + (a2 (get-buffer-create "agent [disp-shown]")) + (cj/--ai-vterm-last-hidden-buffer nil)) + (unwind-protect + (cl-letf (((symbol-function 'cj/--ai-vterm-displayed-agent-window) + (lambda (&optional _f) nil)) + ((symbol-function 'cj/--ai-vterm-agent-buffers) + (lambda () (list a1 a2)))) ; a1 is the MRU + ;; No memory yet -> falls back to MRU (a1). + (should (equal (cj/--ai-vterm-dispatch) (cons 'redisplay-recent a1))) + ;; Remember a2 as last hidden -> dispatch prefers it. + (setq cj/--ai-vterm-last-hidden-buffer a2) + (should (equal (cj/--ai-vterm-dispatch) (cons 'redisplay-recent a2))) + ;; A killed last-hidden buffer -> falls back to MRU. + (let ((dead (get-buffer-create "agent [disp-dead]"))) + (setq cj/--ai-vterm-last-hidden-buffer dead) + (kill-buffer dead)) + (should (equal (cj/--ai-vterm-dispatch) (cons 'redisplay-recent a1)))) + (cj/test--kill-agent-buffers)))) + +(ert-deftest test-ai-vterm--toggle-roundtrip-reopens-same-agent () + "Regression: hide then show brings back the agent that was on screen. +With several agents alive and a different one most-recent in `buffer-list', +F9 off then F9 on restores the SAME agent that was visible -- not a swap to +another. Reproduces the \"the displayed buffer changes\" report." + (cj/test--kill-agent-buffers) + (let ((work (get-buffer-create "*test-roundtrip-work*")) + (a1 (get-buffer-create "agent [rt-1]")) + (a2 (get-buffer-create "agent [rt-2]")) + (cj/--ai-vterm-last-was-bury nil) + (cj/--ai-vterm-last-direction nil) + (cj/--ai-vterm-last-size nil) + (cj/--ai-vterm-last-hidden-buffer nil)) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) work) + (let ((agent-win (split-window (selected-window) nil 'below))) + ;; a2 is the visible agent; a1 sits ahead of it in buffer-list. + (set-window-buffer agent-win a1) + (bury-buffer a1) ; a1 stays alive, demoted in MRU + (set-window-buffer agent-win a2) + (select-window agent-win) + (should (eq (window-buffer (cj/--ai-vterm-displayed-agent-window)) a2)) + (let ((display-buffer-alist (cj/--ai-vterm-display-rule-list))) + (cj/test--call-as-gui #'cj/ai-vterm) ; off + (should-not (cj/--ai-vterm-displayed-agent-window)) + (cj/test--call-as-gui #'cj/ai-vterm) ; on -> must be a2 + (should (eq (window-buffer (cj/--ai-vterm-displayed-agent-window)) + a2))))) + (when (get-buffer "*test-roundtrip-work*") (kill-buffer "*test-roundtrip-work*")) + (cj/test--kill-agent-buffers)))) + +(provide 'test-ai-vterm--collapse-split) +;;; test-ai-vterm--collapse-split.el ends here |
