aboutsummaryrefslogtreecommitdiff
path: root/tests/test-custom-buffer-file-copy-buffer-source.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-15 00:23:14 -0500
committerCraig Jennings <c@cjennings.net>2026-05-15 00:23:14 -0500
commite3e904b33ed714d74fae01ae1b631d889b39003b (patch)
tree42f3da91db16ee763569d9ecd8e85685f032046e /tests/test-custom-buffer-file-copy-buffer-source.el
parentd79ede35e63b8c227886266dc9f00cc10291dfcb (diff)
downloaddotemacs-e3e904b33ed714d74fae01ae1b631d889b39003b.tar.gz
dotemacs-e3e904b33ed714d74fae01ae1b631d889b39003b.zip
feat(custom-buffer-file): make C-; b p dispatch by major-mode, with tests
Old behavior: `C-; b p' called `cj/copy-path-to-buffer-file-as-kill', which only worked in file-visiting buffers and errored otherwise. That meant the most useful "give me a clickable handle on this buffer" key did nothing in eww, elfeed, dired (file-at-point ≠ buffer's default-directory), and other browsing-shaped modes. Replace with a `major-mode'-aware dispatch: - `cj/buffer-source-functions' alist maps major-mode → thunk returning a string (or nil to fall through). - `cj/copy-buffer-source-as-kill' looks up the current mode, calls the thunk, falls back to `buffer-file-name', errors only when both yield nil. - `cj/copy-path-to-buffer-file-as-kill' kept as a `defalias' for backwards compat (the old name is referenced in adjacent tests). First-batch dispatches: - eww-mode -> (eww-current-url) - elfeed-show-mode -> (elfeed-entry-link elfeed-show-entry) - dired-mode -> (dired-get-filename nil t) - dirvish-mode -> same - doc-view / pdf-view: covered by the buffer-file-name fallback (they already set buffer-file-name correctly). 10 new ERT tests cover the dispatch paths, the buffer-file-name fallback, the user-error on nil source, the alias target, and the `C-; b p' keymap entry. which-key label flipped from "copy file path" to "copy buffer source" to match. Deferred to a follow-up task: mu4e-view-mode, org-mode at a heading, help-mode, Info-mode, magit-log/commit/status, xref/grep/ compilation, image-mode, archive-mode -- each needs a format decision before implementation.
Diffstat (limited to 'tests/test-custom-buffer-file-copy-buffer-source.el')
-rw-r--r--tests/test-custom-buffer-file-copy-buffer-source.el144
1 files changed, 144 insertions, 0 deletions
diff --git a/tests/test-custom-buffer-file-copy-buffer-source.el b/tests/test-custom-buffer-file-copy-buffer-source.el
new file mode 100644
index 00000000..c4e073ae
--- /dev/null
+++ b/tests/test-custom-buffer-file-copy-buffer-source.el
@@ -0,0 +1,144 @@
+;;; test-custom-buffer-file-copy-buffer-source.el --- Tests for cj/copy-buffer-source-as-kill -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests the dispatch behavior of `cj/copy-buffer-source-as-kill', the
+;; major-mode-aware extension of the old
+;; `cj/copy-path-to-buffer-file-as-kill' (which is kept as a
+;; `defalias' for backwards compat).
+;;
+;; Dispatch tiers:
+;; eww-mode -> (eww-current-url)
+;; elfeed-show-mode -> (elfeed-entry-link elfeed-show-entry)
+;; dired-mode -> (dired-get-filename nil t)
+;; dirvish-mode -> (dired-get-filename nil t)
+;; doc-view-mode -> buffer-file-name
+;; pdf-view-mode -> buffer-file-name
+;; anything else -> buffer-file-name fallback (errors if nil)
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'custom-buffer-file)
+
+;; Top-level defvars so let-bindings reach the dynamic var under
+;; lexical scope (and stand-ins for vars defined in modes we don't
+;; require here).
+(defvar elfeed-show-entry nil)
+
+;;; Fallback to buffer-file-name
+
+(ert-deftest test-copy-buffer-source-falls-back-to-buffer-file-name ()
+ "Normal: a file-visiting buffer with no special dispatch falls back
+to `buffer-file-name'."
+ (let (kill-ring)
+ (with-temp-buffer
+ (setq buffer-file-name "/tmp/notes.txt")
+ (fundamental-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "/tmp/notes.txt")))))
+
+(ert-deftest test-copy-buffer-source-errors-on-nil-source ()
+ "Error: a buffer with no file and no mode dispatch signals a user-error."
+ (with-temp-buffer
+ (fundamental-mode)
+ (setq buffer-file-name nil)
+ (should-error (cj/copy-buffer-source-as-kill) :type 'user-error)))
+
+;;; eww-mode dispatch
+
+(ert-deftest test-copy-buffer-source-eww-copies-current-url ()
+ "Normal: in eww-mode, copy `(eww-current-url)'."
+ (let (kill-ring)
+ (cl-letf (((symbol-function 'eww-current-url)
+ (lambda () "https://example.org/article")))
+ (with-temp-buffer
+ (setq major-mode 'eww-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "https://example.org/article"))))))
+
+;;; elfeed-show-mode dispatch
+
+(ert-deftest test-copy-buffer-source-elfeed-copies-entry-link ()
+ "Normal: in elfeed-show-mode, copy the entry's link."
+ (let ((kill-ring nil)
+ (elfeed-show-entry (list :link "https://feed.test/post/42")))
+ (cl-letf (((symbol-function 'elfeed-entry-link)
+ (lambda (entry) (plist-get entry :link))))
+ (with-temp-buffer
+ (setq major-mode 'elfeed-show-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "https://feed.test/post/42"))))))
+
+;;; dired-mode dispatch
+
+(ert-deftest test-copy-buffer-source-dired-copies-file-at-point ()
+ "Normal: in dired-mode, copy the absolute path of the file at point
+(not the dired buffer's `default-directory')."
+ (let (kill-ring)
+ (cl-letf (((symbol-function 'dired-get-filename)
+ (lambda (&optional _localp _no-error)
+ "/home/u/projects/notes.org")))
+ (with-temp-buffer
+ (setq major-mode 'dired-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "/home/u/projects/notes.org"))))))
+
+(ert-deftest test-copy-buffer-source-dirvish-copies-file-at-point ()
+ "Normal: dirvish-mode dispatches identically to dired-mode."
+ (let (kill-ring)
+ (cl-letf (((symbol-function 'dired-get-filename)
+ (lambda (&optional _localp _no-error)
+ "/home/u/books/the-book.epub")))
+ (with-temp-buffer
+ (setq major-mode 'dirvish-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "/home/u/books/the-book.epub"))))))
+
+;;; doc-view / pdf-view dispatch
+
+(ert-deftest test-copy-buffer-source-doc-view-copies-buffer-file ()
+ "Normal: doc-view-mode copies the underlying file path
+(`buffer-file-name')."
+ (let (kill-ring)
+ (with-temp-buffer
+ (setq buffer-file-name "/home/u/papers/paper.pdf"
+ major-mode 'doc-view-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "/home/u/papers/paper.pdf")))))
+
+(ert-deftest test-copy-buffer-source-pdf-view-copies-buffer-file ()
+ "Normal: pdf-view-mode copies the underlying file path."
+ (let (kill-ring)
+ (with-temp-buffer
+ (setq buffer-file-name "/home/u/books/manual.pdf"
+ major-mode 'pdf-view-mode)
+ (cl-letf (((symbol-function 'message) #'ignore))
+ (cj/copy-buffer-source-as-kill))
+ (should (equal (car kill-ring) "/home/u/books/manual.pdf")))))
+
+;;; Backwards-compat alias
+
+(ert-deftest test-copy-path-old-name-aliases-new-command ()
+ "Backwards compat: `cj/copy-path-to-buffer-file-as-kill' still
+resolves to the new `cj/copy-buffer-source-as-kill' via defalias."
+ (should (eq (symbol-function 'cj/copy-path-to-buffer-file-as-kill)
+ 'cj/copy-buffer-source-as-kill)))
+
+;;; Keybinding
+
+(ert-deftest test-copy-buffer-source-bound-on-b-p ()
+ "Normal: `p' in `cj/buffer-and-file-map' invokes the new command."
+ (should (eq (keymap-lookup cj/buffer-and-file-map "p")
+ #'cj/copy-buffer-source-as-kill)))
+
+(provide 'test-custom-buffer-file-copy-buffer-source)
+;;; test-custom-buffer-file-copy-buffer-source.el ends here