diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-31 16:20:34 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-31 16:20:34 -0500 |
| commit | b72e794be60c5d4e94c61e5af8c08245773e3393 (patch) | |
| tree | c1a3f3cdce0ffed773213c0180badffc58843e14 /tests/test-ai-vterm--terminal-guard.el | |
| parent | 79db37565a356dead9a4c663361e77627d83d864 (diff) | |
| download | dotemacs-b72e794be60c5d4e94c61e5af8c08245773e3393.tar.gz dotemacs-b72e794be60c5d4e94c61e5af8c08245773e3393.zip | |
feat(ai-vterm): gate the F9 launcher to GUI frames
AI-vterm launches a graphical vterm side window, so F9 / C-F9 / M-F9 now decline with a message in a terminal frame instead of opening a vterm. The guard checks the current frame at command time rather than at load. That matters under the daemon, which serves GUI and terminal frames both with display-graphic-p nil at load, so a load-time gate would have disabled the launcher in its GUI frames too.
Routed the three window-behavior tests through a GUI-frame stub, since a batch run is itself a terminal frame.
Diffstat (limited to 'tests/test-ai-vterm--terminal-guard.el')
| -rw-r--r-- | tests/test-ai-vterm--terminal-guard.el | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/tests/test-ai-vterm--terminal-guard.el b/tests/test-ai-vterm--terminal-guard.el new file mode 100644 index 00000000..5a7971bf --- /dev/null +++ b/tests/test-ai-vterm--terminal-guard.el @@ -0,0 +1,78 @@ +;;; test-ai-vterm--terminal-guard.el --- Tests for the terminal-frame guard -*- lexical-binding: t; -*- + +;;; Commentary: +;; AI-vterm launches a graphical vterm side window, so it is GUI-only. +;; `cj/--ai-vterm-refuse-in-terminal' signals a `user-error' when the +;; current frame is a terminal frame; each interactive entry point +;; (`cj/ai-vterm', `cj/ai-vterm-pick-project', `cj/ai-vterm-close') +;; calls it first so F9 and friends decline -- with a message -- in a +;; terminal frame instead of launching a vterm. The check is per-frame +;; at command time, not at load, so a daemon serving both GUI and +;; terminal frames keeps the launcher working in its GUI frames. +;; +;; `env-terminal-p' is mocked so the tests are deterministic regardless +;; of whether the run itself is graphical (batch runs are terminal). + +;;; 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) + +;; ---------------------------- the guard helper ---------------------------- + +(ert-deftest test-ai-vterm--refuse-in-terminal-errors-in-terminal-frame () + "Error: terminal frame -> `user-error', so the command declines." + (cl-letf (((symbol-function 'env-terminal-p) (lambda () t))) + (should-error (cj/--ai-vterm-refuse-in-terminal) :type 'user-error))) + +(ert-deftest test-ai-vterm--refuse-in-terminal-passes-in-gui-frame () + "Normal: GUI frame -> returns nil, no error, command proceeds." + (cl-letf (((symbol-function 'env-terminal-p) (lambda () nil))) + (should-not (cj/--ai-vterm-refuse-in-terminal)))) + +;; ------------------- the three interactive entry points ------------------- + +(ert-deftest test-ai-vterm-f9-declines-in-terminal-without-dispatching () + "Error: F9 in a terminal frame errors and never reaches dispatch." + (let ((dispatched nil)) + (cl-letf (((symbol-function 'env-terminal-p) (lambda () t)) + ((symbol-function 'cj/--ai-vterm-dispatch) + (lambda () (setq dispatched t) '(pick-project)))) + (should-error (cj/ai-vterm) :type 'user-error) + (should-not dispatched)))) + +(ert-deftest test-ai-vterm-pick-project-declines-in-terminal-without-prompting () + "Error: C-F9 in a terminal frame errors and never reaches the picker." + (let ((prompted nil)) + (cl-letf (((symbol-function 'env-terminal-p) (lambda () t)) + ((symbol-function 'cj/--ai-vterm-pick-project) + (lambda () (setq prompted t) "/tmp"))) + (should-error (cj/ai-vterm-pick-project) :type 'user-error) + (should-not prompted)))) + +(ert-deftest test-ai-vterm-close-declines-in-terminal-without-targeting () + "Error: M-F9 in a terminal frame errors and never reaches close-target." + (let ((targeted nil)) + (cl-letf (((symbol-function 'env-terminal-p) (lambda () t)) + ((symbol-function 'cj/--ai-vterm-close-target) + (lambda () (setq targeted t) nil))) + (should-error (cj/ai-vterm-close) :type 'user-error) + (should-not targeted)))) + +(ert-deftest test-ai-vterm-f9-passes-guard-in-gui-frame () + "Normal: F9 in a GUI frame passes the guard and reaches dispatch." + (let ((dispatched nil)) + (cl-letf (((symbol-function 'env-terminal-p) (lambda () nil)) + ((symbol-function 'cj/--ai-vterm-dispatch) + (lambda () (setq dispatched t) '(pick-project))) + ((symbol-function 'cj/ai-vterm-pick-project) + (lambda (&optional _arg) nil))) + (cj/ai-vterm) + (should dispatched)))) + +(provide 'test-ai-vterm--terminal-guard) +;;; test-ai-vterm--terminal-guard.el ends here |
