diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-ai-vterm--collapse-split.el | 171 | ||||
| -rw-r--r-- | tests/test-ai-vterm--reuse-edge-window.el | 45 |
2 files changed, 194 insertions, 22 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 diff --git a/tests/test-ai-vterm--reuse-edge-window.el b/tests/test-ai-vterm--reuse-edge-window.el index 9f621477..eb1b1d75 100644 --- a/tests/test-ai-vterm--reuse-edge-window.el +++ b/tests/test-ai-vterm--reuse-edge-window.el @@ -150,10 +150,12 @@ ends up displayed." (when (get-buffer bottom-name) (kill-buffer bottom-name)) (cj/test--kill-agent-buffers)))) -(ert-deftest test-ai-vterm--reuse-edge-window-toggle-off-restores-displaced () - "Normal: toggle-off after a slot reuse restores the displaced buffer. -=| 1 | 2 |= + show agent -> =| 1 | A |=; toggle off -> =| 1 | 2 |= again, -window count stays 2 (the native `quit-restore-window' puts 2 back)." +(ert-deftest test-ai-vterm--reuse-edge-window-toggle-off-collapses-split () + "Normal: toggle-off after a slot reuse collapses the agent split. +=| 1 | 2 |= + show agent -> =| 1 | A |=; toggle off -> =| 1 |= (one +window). F9 always collapses the agent split back to the working layout +regardless of how the agent window came to be -- it deletes the agent +window rather than restoring the displaced buffer into a kept slot." (cj/test--kill-agent-buffers) (let ((agent-name "agent [edge-restore]") (left-name "*test-restore-left*") @@ -174,22 +176,23 @@ window count stays 2 (the native `quit-restore-window' puts 2 back)." (display-buffer agent-buf) (should (= (count-windows) 2)) (should (member agent-name (cj/test--displayed-buffer-names))) - ;; Toggle off -> the displaced buffer (2) returns to the slot. + ;; Toggle off -> the agent window is deleted, leaving the + ;; working buffer at full frame. (cj/test--call-as-gui #'cj/ai-vterm) - (should (= (count-windows) 2)) + (should (= (count-windows) 1)) (let ((bufs (cj/test--displayed-buffer-names))) - (should (member right-name bufs)) (should (member left-name bufs)) (should-not (member agent-name bufs))))))) (when (get-buffer left-name) (kill-buffer left-name)) (when (get-buffer right-name) (kill-buffer right-name)) (cj/test--kill-agent-buffers)))) -(ert-deftest test-ai-vterm--reuse-edge-window-cycle-keeps-count-and-swaps () - "Normal: on/off/on cycle keeps the window count at 2 and swaps the slot. -=| 1 | 2 |= -> on =| 1 | A |= -> off =| 1 | 2 |= -> on =| 1 | A |=, never -creating or deleting a window, and the agent returns to the same slot at -the same width." +(ert-deftest test-ai-vterm--reuse-edge-window-cycle-collapses-then-resplits () + "Normal: on/off/on cycle collapses on off and re-splits at the same width. +=| 1 | 2 |= -> on =| 1 | A |= (2 windows) -> off =| 1 |= (1 window, +collapsed) -> on =| 1 | A |= (2 windows again), with the agent re-split at +the width captured at toggle-off -- the user's chosen split width is +preserved across the toggle (respect-split-width)." (cj/test--kill-agent-buffers) (let ((agent-name "agent [edge-cycle]") (left-name "*test-cycle-left*") @@ -206,26 +209,24 @@ the same width." slot-width) (set-window-buffer (selected-window) left-buf) (let ((rw (split-window (selected-window) nil 'right))) - (set-window-buffer rw right-buf) - (setq slot-width (window-body-width rw))) + (set-window-buffer rw right-buf)) (let ((display-buffer-alist (cj/--ai-vterm-display-rule-list))) - ;; on + ;; on -- agent takes the existing right slot (display-buffer agent-buf) (should (= (count-windows) 2)) - ;; off + (setq slot-width + (window-body-width (cj/--ai-vterm-displayed-agent-window))) + ;; off -- the split collapses to a single window (cj/test--call-as-gui #'cj/ai-vterm) - (should (= (count-windows) 2)) + (should (= (count-windows) 1)) (should-not (cj/--ai-vterm-displayed-agent-window)) - ;; on again + ;; on again -- re-split at the captured width (cj/test--call-as-gui #'cj/ai-vterm) (should (= (count-windows) 2)) (let ((win (cj/--ai-vterm-displayed-agent-window))) (should (windowp win)) (should (eq (window-buffer win) agent-buf)) - ;; reused the same slot -> same body width as the - ;; original right column - (should (= (window-body-width win) slot-width))) - (should-not (member right-name (cj/test--displayed-buffer-names))))))) + (should (= (window-body-width win) slot-width))))))) (when (get-buffer left-name) (kill-buffer left-name)) (when (get-buffer right-name) (kill-buffer right-name)) (cj/test--kill-agent-buffers)))) |
