aboutsummaryrefslogtreecommitdiff
path: root/tests/test-keybindings--jump-open-var.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-30 08:19:07 -0500
committerCraig Jennings <c@cjennings.net>2026-04-30 08:19:07 -0500
commitf5b04084c238e3bb7b16ea8a9b6f6dbe0d0def40 (patch)
tree31c1cc26ad29fd110e7897b5d6e56699f24bfd43 /tests/test-keybindings--jump-open-var.el
parentbe3e227f3aa75c018fa4f7486226d691765012b5 (diff)
downloaddotemacs-f5b04084c238e3bb7b16ea8a9b6f6dbe0d0def40.tar.gz
dotemacs-f5b04084c238e3bb7b16ea8a9b6f6dbe0d0def40.zip
test(keybindings): cover cj/jump-open-var and the jump-commands wiring
Two test files for keybindings.el. cj/jump-open-var gets full N/B/E coverage (6 tests): existing-file happy path, plus error paths for unbound symbol, nil value, non-string value, empty string, and missing file. The smoke file for the auto-generated cj/jump-to-NAME commands asserts that each spec entry has an fbound command, that the command is bound in cj/jump-map at the spec's key, that calling each command invokes cj/jump-open-var with the spec's var, and that cj/jump-map is mounted under cj/custom-keymap at "j". The test fixture variable is declared at top level. If it were let-bound inside a test under lexical-binding, the let would create a lexical binding that shadows the dynamic one. The production code's symbol-value would then miss what setq writes. find-file is mocked at the boundary so the existing-file test doesn't actually open a buffer. 10 tests pass. No production change in keybindings.el.
Diffstat (limited to 'tests/test-keybindings--jump-open-var.el')
-rw-r--r--tests/test-keybindings--jump-open-var.el92
1 files changed, 92 insertions, 0 deletions
diff --git a/tests/test-keybindings--jump-open-var.el b/tests/test-keybindings--jump-open-var.el
new file mode 100644
index 00000000..bd04f4cf
--- /dev/null
+++ b/tests/test-keybindings--jump-open-var.el
@@ -0,0 +1,92 @@
+;;; test-keybindings--jump-open-var.el --- Tests for cj/jump-open-var -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for `cj/jump-open-var' in keybindings.el. The helper takes a
+;; variable symbol, validates that the variable is bound, holds a
+;; non-empty string, and points at an existing file, then opens it via
+;; `find-file'. Each failure path raises `user-error'.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'keybindings)
+
+(defvar test-keybindings--fixture-var nil
+ "Shared fixture variable for `cj/jump-open-var' tests.
+Declared at top level so `let'-binding inside tests sees it as special
+under lexical-binding.")
+
+(defmacro test-keybindings--with-find-file-mock (capture-var &rest body)
+ "Run BODY with `find-file' replaced by a mock that captures its arg.
+CAPTURE-VAR is set to the path passed to `find-file', or stays nil if
+the mock is never called."
+ (declare (indent 1) (debug t))
+ `(cl-letf (((symbol-function 'find-file)
+ (lambda (path) (setq ,capture-var path))))
+ ,@body))
+
+(defmacro test-keybindings--with-fixture (value &rest body)
+ "Bind `test-keybindings--fixture-var' to VALUE for BODY, then reset."
+ (declare (indent 1) (debug t))
+ `(unwind-protect
+ (progn (setq test-keybindings--fixture-var ,value) ,@body)
+ (setq test-keybindings--fixture-var nil)))
+
+;;; Normal cases
+
+(ert-deftest test-keybindings-jump-open-var-existing-file-calls-find-file ()
+ "Normal: bound var holding a path to an existing file calls `find-file'."
+ (let ((tmp (make-temp-file "jump-test-")))
+ (unwind-protect
+ (test-keybindings--with-fixture tmp
+ (let (captured)
+ (test-keybindings--with-find-file-mock captured
+ (cj/jump-open-var 'test-keybindings--fixture-var)
+ (should (equal captured tmp)))))
+ (when (file-exists-p tmp) (delete-file tmp)))))
+
+;;; Boundary / Error cases
+
+(ert-deftest test-keybindings-jump-open-var-unbound-raises ()
+ "Error: an unbound variable raises `user-error' naming the variable."
+ (let ((sym (make-symbol "test-keybindings--unbound")))
+ (let ((err (should-error (cj/jump-open-var sym) :type 'user-error)))
+ (should (string-match-p (symbol-name sym)
+ (error-message-string err))))))
+
+(ert-deftest test-keybindings-jump-open-var-nil-value-raises ()
+ "Error: a variable bound to nil raises `user-error'."
+ (test-keybindings--with-fixture nil
+ (should-error (cj/jump-open-var 'test-keybindings--fixture-var)
+ :type 'user-error)))
+
+(ert-deftest test-keybindings-jump-open-var-non-string-raises ()
+ "Error: a variable bound to a non-string raises `user-error'."
+ (test-keybindings--with-fixture 42
+ (should-error (cj/jump-open-var 'test-keybindings--fixture-var)
+ :type 'user-error)))
+
+(ert-deftest test-keybindings-jump-open-var-empty-string-raises ()
+ "Error: a variable bound to the empty string raises `user-error'."
+ (test-keybindings--with-fixture ""
+ (should-error (cj/jump-open-var 'test-keybindings--fixture-var)
+ :type 'user-error)))
+
+(ert-deftest test-keybindings-jump-open-var-missing-file-raises ()
+ "Error: a path to a non-existent file raises `user-error' naming the path."
+ (let ((missing-path (concat temporary-file-directory
+ "definitely-not-here-"
+ (number-to-string (random 1000000)) ".org")))
+ (should-not (file-exists-p missing-path))
+ (test-keybindings--with-fixture missing-path
+ (let ((err (should-error
+ (cj/jump-open-var 'test-keybindings--fixture-var)
+ :type 'user-error)))
+ (should (string-match-p (regexp-quote missing-path)
+ (error-message-string err)))))))
+
+(provide 'test-keybindings--jump-open-var)
+;;; test-keybindings--jump-open-var.el ends here