aboutsummaryrefslogtreecommitdiff
path: root/tests/test-system-commands-resolve-and-run.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-14 03:47:01 -0500
committerCraig Jennings <c@cjennings.net>2026-05-14 03:47:01 -0500
commitec66cc02c89c0d378c0333cb4f6e35234e39d2f0 (patch)
tree91bbe53d06d9d3ce8709f0889e66919e9c34ced5 /tests/test-system-commands-resolve-and-run.el
parentf6cfaee02412944e281c7ec4c6b20512b3e45708 (diff)
downloaddotemacs-ec66cc02c89c0d378c0333cb4f6e35234e39d2f0.tar.gz
dotemacs-ec66cc02c89c0d378c0333cb4f6e35234e39d2f0.zip
test(system-commands): cover resolve, run wrapper, exit/restart, menu
Sibling `test-system-commands-keymap.el` locked the keymap shape. This batch covers the runtime helpers and commands: - `cj/system-cmd--resolve`: trims strings, errors on empty/non-string-non-symbol, round-trips a symbol whose value is a non-empty string, errors on a symbol with empty value. - `cj/system-cmd`: wraps a plain string in `nohup ... &` and hands it to `start-process-shell-command`; a confirm-tagged var with an N response signals user-error. - `cj/system-cmd-exit-emacs`: declining the prompt aborts; accepting calls `kill-emacs`. - `cj/system-cmd-restart-emacs`: declining aborts before scheduling; accepting schedules two timers. - `cj/system-command-menu`: the completing-read pick routes through `call-interactively` to the right command symbol. Top-level defvars for `test-sc-my-cmd` and `test-sc-empty-cmd` make the let-bindings dynamic so `symbol-value` reaches them under lexical scope.
Diffstat (limited to 'tests/test-system-commands-resolve-and-run.el')
-rw-r--r--tests/test-system-commands-resolve-and-run.el142
1 files changed, 142 insertions, 0 deletions
diff --git a/tests/test-system-commands-resolve-and-run.el b/tests/test-system-commands-resolve-and-run.el
new file mode 100644
index 00000000..105628b6
--- /dev/null
+++ b/tests/test-system-commands-resolve-and-run.el
@@ -0,0 +1,142 @@
+;;; test-system-commands-resolve-and-run.el --- Tests for system-commands helpers + wrappers -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Sibling `test-system-commands-keymap.el' locks the keymap shape.
+;; This file covers the runtime helpers and commands:
+;;
+;; cj/system-cmd--resolve
+;; cj/system-cmd
+;; cj/system-cmd-exit-emacs
+;; cj/system-cmd-restart-emacs
+;; cj/system-command-menu
+;;
+;; Process and prompt primitives are stubbed.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'system-commands)
+
+;; Top-level defvars so `let' bindings reach `symbol-value' under
+;; lexical scope.
+(defvar test-sc-my-cmd nil
+ "Dynamic test var for `cj/system-cmd--resolve' symbol-resolution test.")
+(defvar test-sc-empty-cmd nil
+ "Dynamic test var for the empty-value test.")
+
+;;; cj/system-cmd--resolve
+
+(ert-deftest test-system-cmd-resolve-string-trims-and-returns ()
+ "Normal: a non-empty string comes back trimmed with a nil symbol slot."
+ (let ((result (cj/system-cmd--resolve " echo hi ")))
+ (should (null (nth 0 result)))
+ (should (equal (nth 1 result) "echo hi"))
+ (should (equal (nth 2 result) "command"))))
+
+(ert-deftest test-system-cmd-resolve-empty-string-errors ()
+ "Error: an empty string signals user-error."
+ (should-error (cj/system-cmd--resolve " ") :type 'user-error))
+
+(ert-deftest test-system-cmd-resolve-symbol-uses-its-value ()
+ "Normal: a symbol whose value is a non-empty string round-trips."
+ (let ((test-sc-my-cmd "echo hello"))
+ (let ((result (cj/system-cmd--resolve 'test-sc-my-cmd)))
+ (should (eq (nth 0 result) 'test-sc-my-cmd))
+ (should (equal (nth 1 result) "echo hello"))
+ (should (equal (nth 2 result) "test-sc-my-cmd")))))
+
+(ert-deftest test-system-cmd-resolve-symbol-with-empty-value-errors ()
+ "Error: a symbol whose value isn't a non-empty string signals user-error."
+ (let ((test-sc-empty-cmd ""))
+ (should-error (cj/system-cmd--resolve 'test-sc-empty-cmd) :type 'user-error)))
+
+(ert-deftest test-system-cmd-resolve-non-string-non-symbol-errors ()
+ "Error: passing a number signals user-error."
+ (should-error (cj/system-cmd--resolve 42) :type 'user-error))
+
+;;; cj/system-cmd
+
+(ert-deftest test-system-cmd-string-runs-shell-process ()
+ "Normal: a plain string is wrapped in nohup and handed to
+`start-process-shell-command'."
+ (let (cmd-line)
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buf c) (setq cmd-line c) 'fake-proc))
+ ((symbol-function 'set-process-query-on-exit-flag) #'ignore)
+ ((symbol-function 'set-process-sentinel) #'ignore)
+ ((symbol-function 'message) #'ignore))
+ (cj/system-cmd "echo hi"))
+ (should (string-match-p "^nohup echo hi" cmd-line))
+ (should (string-match-p "&$" cmd-line))))
+
+(ert-deftest test-system-cmd-confirm-decline-aborts ()
+ "Boundary: a confirm-tagged var with N response signals user-error."
+ (defvar test-sc-confirm-cmd "test-confirm-cmd")
+ (put 'test-sc-confirm-cmd 'cj/system-confirm t)
+ (unwind-protect
+ (cl-letf (((symbol-function 'read-char-choice) (lambda (&rest _) ?n))
+ ((symbol-function 'start-process-shell-command)
+ (lambda (&rest _) (error "shouldn't run"))))
+ (should-error (cj/system-cmd 'test-sc-confirm-cmd) :type 'user-error))
+ (put 'test-sc-confirm-cmd 'cj/system-confirm nil)))
+
+;;; cj/system-cmd-exit-emacs
+
+(ert-deftest test-system-cmd-exit-emacs-decline-aborts ()
+ "Boundary: declining the prompt signals user-error; kill-emacs is not called."
+ (let ((killed nil))
+ (cl-letf (((symbol-function 'read-char-choice) (lambda (&rest _) ?n))
+ ((symbol-function 'kill-emacs)
+ (lambda (&rest _) (setq killed t))))
+ (should-error (cj/system-cmd-exit-emacs) :type 'user-error))
+ (should-not killed)))
+
+(ert-deftest test-system-cmd-exit-emacs-accept-calls-kill-emacs ()
+ "Normal: accepting the prompt calls `kill-emacs'."
+ (let ((killed nil))
+ (cl-letf (((symbol-function 'read-char-choice) (lambda (&rest _) ?y))
+ ((symbol-function 'kill-emacs)
+ (lambda (&rest _) (setq killed t))))
+ (cj/system-cmd-exit-emacs))
+ (should killed)))
+
+;;; cj/system-cmd-restart-emacs
+
+(ert-deftest test-system-cmd-restart-emacs-decline-aborts ()
+ "Boundary: declining the prompt signals user-error before scheduling."
+ (let ((scheduled nil))
+ (cl-letf (((symbol-function 'read-char-choice) (lambda (&rest _) ?n))
+ ((symbol-function 'save-some-buffers) #'ignore)
+ ((symbol-function 'run-at-time)
+ (lambda (&rest _) (setq scheduled t))))
+ (should-error (cj/system-cmd-restart-emacs) :type 'user-error))
+ (should-not scheduled)))
+
+(ert-deftest test-system-cmd-restart-emacs-accept-schedules-restart ()
+ "Normal: accepting the prompt schedules the restart + kill timers."
+ (let ((schedules 0))
+ (cl-letf (((symbol-function 'read-char-choice) (lambda (&rest _) ?y))
+ ((symbol-function 'save-some-buffers) #'ignore)
+ ((symbol-function 'run-at-time)
+ (lambda (&rest _) (cl-incf schedules)))
+ ((symbol-function 'message) #'ignore))
+ (cj/system-cmd-restart-emacs))
+ (should (= schedules 2))))
+
+;;; cj/system-command-menu
+
+(ert-deftest test-system-command-menu-dispatches-by-name ()
+ "Normal: the completing-read selection routes through `call-interactively'."
+ (let ((called nil))
+ (cl-letf (((symbol-function 'completing-read)
+ (lambda (&rest _) "Lock Screen"))
+ ((symbol-function 'call-interactively)
+ (lambda (cmd) (setq called cmd))))
+ (cj/system-command-menu))
+ (should (eq called 'cj/system-cmd-lock))))
+
+(provide 'test-system-commands-resolve-and-run)
+;;; test-system-commands-resolve-and-run.el ends here