summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/custom-file-buffer.el2
-rw-r--r--tests/test-custom-file-buffer-clear-to-bottom-of-buffer.el163
-rw-r--r--tests/test-custom-file-buffer-clear-to-top-of-buffer.el162
-rw-r--r--tests/test-custom-file-buffer-copy-link-to-buffer-file.el209
-rw-r--r--tests/test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el205
-rw-r--r--tests/test-custom-file-buffer-copy-whole-buffer.el194
6 files changed, 934 insertions, 1 deletions
diff --git a/modules/custom-file-buffer.el b/modules/custom-file-buffer.el
index a56edf18..e0224a32 100644
--- a/modules/custom-file-buffer.el
+++ b/modules/custom-file-buffer.el
@@ -108,7 +108,7 @@ Returns t on success, nil if buffer not visiting a file."
When called interactively, prompts for confirmation if target file exists."
(interactive (list (read-directory-name "Move buffer and file (to new directory): ")))
(let* ((target (expand-file-name (buffer-name) (expand-file-name dir))))
- (condition-case err
+ (condition-case _
(cj/--move-buffer-and-file dir nil)
(file-already-exists
(if (yes-or-no-p (format "File %s exists; overwrite? " target))
diff --git a/tests/test-custom-file-buffer-clear-to-bottom-of-buffer.el b/tests/test-custom-file-buffer-clear-to-bottom-of-buffer.el
new file mode 100644
index 00000000..969f9bb7
--- /dev/null
+++ b/tests/test-custom-file-buffer-clear-to-bottom-of-buffer.el
@@ -0,0 +1,163 @@
+;;; test-custom-file-buffer-clear-to-bottom-of-buffer.el --- Tests for cj/clear-to-bottom-of-buffer -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/clear-to-bottom-of-buffer function from custom-file-buffer.el
+;;
+;; This function deletes all text from point to the end of the current buffer.
+;; It does not save the deleted text in the kill ring.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub ps-print package
+(provide 'ps-print)
+
+;; Now load the actual production module
+(require 'custom-file-buffer)
+
+;;; Setup and Teardown
+
+(defun test-clear-to-bottom-setup ()
+ "Set up test environment."
+ (setq kill-ring nil))
+
+(defun test-clear-to-bottom-teardown ()
+ "Clean up test environment."
+ (setq kill-ring nil))
+
+;;; Normal Cases
+
+(ert-deftest test-clear-to-bottom-point-in-middle ()
+ "Should delete from point to end when point in middle."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (forward-line 1) ; Point at start of "Line 2"
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "Line 1\n")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-empty-buffer ()
+ "Should do nothing in empty buffer."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "")))
+ (test-clear-to-bottom-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-clear-to-bottom-point-at-beginning ()
+ "Should delete entire buffer when point at beginning."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-point-at-end ()
+ "Should delete nothing when point at end."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-max))
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "Line 1\nLine 2\nLine 3")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-point-second-to-last-char ()
+ "Should delete last character when point at second-to-last."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello")
+ (goto-char (1- (point-max))) ; Before 'o'
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "Hell")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-unicode-content ()
+ "Should handle unicode content."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello 👋\nمرحبا\nWorld")
+ (goto-char (point-min))
+ (forward-line 1)
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "Hello 👋\n")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-narrowed-buffer ()
+ "Should respect narrowing."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3\nLine 4")
+ (goto-char (point-min))
+ (forward-line 1)
+ (let ((start (point)))
+ (forward-line 2)
+ (narrow-to-region start (point))
+ (goto-char (point-min))
+ (forward-line 1) ; Point at "Line 3"
+ (cj/clear-to-bottom-of-buffer)
+ (should (equal (buffer-string) "Line 2\n"))))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-multiple-windows ()
+ "Should update all windows showing buffer."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (forward-line 1)
+ (cj/clear-to-bottom-of-buffer)
+ ;; Just verify content changed
+ (should (equal (buffer-string) "Line 1\n")))
+ (test-clear-to-bottom-teardown)))
+
+(ert-deftest test-clear-to-bottom-does-not-affect-kill-ring ()
+ "Should not add deleted text to kill ring."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (setq kill-ring nil)
+ (cj/clear-to-bottom-of-buffer)
+ (should (null kill-ring)))
+ (test-clear-to-bottom-teardown)))
+
+;;; Error Cases
+
+(ert-deftest test-clear-to-bottom-read-only-buffer ()
+ "Should signal error in read-only buffer."
+ (test-clear-to-bottom-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Read-only content")
+ (read-only-mode 1)
+ (goto-char (point-min))
+ (should-error (cj/clear-to-bottom-of-buffer)))
+ (test-clear-to-bottom-teardown)))
+
+(provide 'test-custom-file-buffer-clear-to-bottom-of-buffer)
+;;; test-custom-file-buffer-clear-to-bottom-of-buffer.el ends here
diff --git a/tests/test-custom-file-buffer-clear-to-top-of-buffer.el b/tests/test-custom-file-buffer-clear-to-top-of-buffer.el
new file mode 100644
index 00000000..18e3f71b
--- /dev/null
+++ b/tests/test-custom-file-buffer-clear-to-top-of-buffer.el
@@ -0,0 +1,162 @@
+;;; test-custom-file-buffer-clear-to-top-of-buffer.el --- Tests for cj/clear-to-top-of-buffer -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/clear-to-top-of-buffer function from custom-file-buffer.el
+;;
+;; This function deletes all text from point to the beginning of the current buffer.
+;; It does not save the deleted text in the kill ring.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub ps-print package
+(provide 'ps-print)
+
+;; Now load the actual production module
+(require 'custom-file-buffer)
+
+;;; Setup and Teardown
+
+(defun test-clear-to-top-setup ()
+ "Set up test environment."
+ (setq kill-ring nil))
+
+(defun test-clear-to-top-teardown ()
+ "Clean up test environment."
+ (setq kill-ring nil))
+
+;;; Normal Cases
+
+(ert-deftest test-clear-to-top-point-in-middle ()
+ "Should delete from beginning to point when point in middle."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (forward-line 2) ; Point at start of "Line 3"
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "Line 3")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-empty-buffer ()
+ "Should do nothing in empty buffer."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "")))
+ (test-clear-to-top-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-clear-to-top-point-at-beginning ()
+ "Should delete nothing when point at beginning."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-min))
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "Line 1\nLine 2\nLine 3")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-point-at-end ()
+ "Should delete entire buffer when point at end."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-max))
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-point-at-second-char ()
+ "Should delete first character when point at second."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello")
+ (goto-char (1+ (point-min))) ; After 'H'
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "ello")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-unicode-content ()
+ "Should handle unicode content."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello 👋\nمرحبا\nWorld")
+ (goto-char (point-min))
+ (forward-line 2)
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "World")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-narrowed-buffer ()
+ "Should respect narrowing."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3\nLine 4")
+ (goto-char (point-min))
+ (forward-line 1)
+ (let ((start (point)))
+ (forward-line 2)
+ (narrow-to-region start (point))
+ (goto-char (point-min))
+ (forward-line 1) ; Point at "Line 3"
+ (cj/clear-to-top-of-buffer)
+ (should (equal (buffer-string) "Line 3\n"))))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-multiple-windows ()
+ "Should update all windows showing buffer."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-max))
+ (cj/clear-to-top-of-buffer)
+ ;; Just verify content changed
+ (should (equal (buffer-string) "")))
+ (test-clear-to-top-teardown)))
+
+(ert-deftest test-clear-to-top-does-not-affect-kill-ring ()
+ "Should not add deleted text to kill ring."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (goto-char (point-max))
+ (setq kill-ring nil)
+ (cj/clear-to-top-of-buffer)
+ (should (null kill-ring)))
+ (test-clear-to-top-teardown)))
+
+;;; Error Cases
+
+(ert-deftest test-clear-to-top-read-only-buffer ()
+ "Should signal error in read-only buffer."
+ (test-clear-to-top-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Read-only content")
+ (read-only-mode 1)
+ (goto-char (point-max))
+ (should-error (cj/clear-to-top-of-buffer)))
+ (test-clear-to-top-teardown)))
+
+(provide 'test-custom-file-buffer-clear-to-top-of-buffer)
+;;; test-custom-file-buffer-clear-to-top-of-buffer.el ends here
diff --git a/tests/test-custom-file-buffer-copy-link-to-buffer-file.el b/tests/test-custom-file-buffer-copy-link-to-buffer-file.el
new file mode 100644
index 00000000..94d1e01e
--- /dev/null
+++ b/tests/test-custom-file-buffer-copy-link-to-buffer-file.el
@@ -0,0 +1,209 @@
+;;; test-custom-file-buffer-copy-link-to-buffer-file.el --- Tests for cj/copy-link-to-buffer-file -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/copy-link-to-buffer-file function from custom-file-buffer.el
+;;
+;; This function copies the full file:// path of the current buffer's file to
+;; the kill ring. For non-file buffers, it does nothing (no error).
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub ps-print package
+(provide 'ps-print)
+
+;; Now load the actual production module
+(require 'custom-file-buffer)
+
+;;; Setup and Teardown
+
+(defun test-copy-link-setup ()
+ "Set up test environment."
+ (setq kill-ring nil))
+
+(defun test-copy-link-teardown ()
+ "Clean up test environment."
+ ;; Kill all buffers visiting files in the test directory
+ (dolist (buf (buffer-list))
+ (when (buffer-file-name buf)
+ (when (string-prefix-p cj/test-base-dir (buffer-file-name buf))
+ (with-current-buffer buf
+ (set-buffer-modified-p nil)
+ (kill-buffer buf)))))
+ (cj/delete-test-base-dir)
+ (setq kill-ring nil))
+
+;;; Normal Cases
+
+(ert-deftest test-copy-link-simple-file ()
+ "Should copy file:// link for simple file buffer."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-non-file-buffer ()
+ "Should do nothing for non-file buffer without error."
+ (test-copy-link-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (setq kill-ring nil)
+ (cj/copy-link-to-buffer-file)
+ (should (null kill-ring)))
+ (test-copy-link-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-copy-link-unicode-filename ()
+ "Should handle unicode in filename."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "café.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-spaces-in-filename ()
+ "Should handle spaces in filename."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "my file.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-special-chars-filename ()
+ "Should handle special characters in filename."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "[test]-(1).txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-very-long-path ()
+ "Should handle very long path."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (long-name (make-string 200 ?x))
+ (test-file (expand-file-name (concat long-name ".txt") test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-hidden-file ()
+ "Should handle hidden file."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name ".hidden" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-no-extension ()
+ "Should handle file with no extension."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "README" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-symlink-file ()
+ "Should use buffer's filename for symlink."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (target-file (expand-file-name "target.txt" test-dir))
+ (link-file (expand-file-name "link.txt" test-dir)))
+ (with-temp-file target-file
+ (insert "content"))
+ (make-symbolic-link target-file link-file)
+ (with-current-buffer (find-file link-file)
+ (cj/copy-link-to-buffer-file)
+ ;; Should use the link name (what buffer-file-name returns)
+ (should (equal (car kill-ring) (concat "file://" (buffer-file-name))))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-kill-ring-has-content ()
+ "Should add to kill ring when it already has content."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (kill-new "existing content")
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))
+ (should (equal (cadr kill-ring) "existing content"))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-empty-kill-ring ()
+ "Should populate empty kill ring."
+ (test-copy-link-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (setq kill-ring nil)
+ (with-current-buffer (find-file test-file)
+ (cj/copy-link-to-buffer-file)
+ (should (equal (car kill-ring) (concat "file://" test-file)))
+ (should (= (length kill-ring) 1))))
+ (test-copy-link-teardown)))
+
+(ert-deftest test-copy-link-scratch-buffer ()
+ "Should do nothing for *scratch* buffer."
+ (test-copy-link-setup)
+ (unwind-protect
+ (progn
+ (setq kill-ring nil)
+ (with-current-buffer "*scratch*"
+ (cj/copy-link-to-buffer-file)
+ (should (null kill-ring))))
+ (test-copy-link-teardown)))
+
+(provide 'test-custom-file-buffer-copy-link-to-buffer-file)
+;;; test-custom-file-buffer-copy-link-to-buffer-file.el ends here
diff --git a/tests/test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el b/tests/test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el
new file mode 100644
index 00000000..e7a6f64b
--- /dev/null
+++ b/tests/test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el
@@ -0,0 +1,205 @@
+;;; test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el --- Tests for cj/copy-path-to-buffer-file-as-kill -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/copy-path-to-buffer-file-as-kill function from custom-file-buffer.el
+;;
+;; This function copies the full path of the current buffer's file to the kill ring
+;; and returns the path. It signals an error if the buffer is not visiting a file.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub ps-print package
+(provide 'ps-print)
+
+;; Now load the actual production module
+(require 'custom-file-buffer)
+
+;;; Setup and Teardown
+
+(defun test-copy-path-setup ()
+ "Set up test environment."
+ (setq kill-ring nil))
+
+(defun test-copy-path-teardown ()
+ "Clean up test environment."
+ ;; Kill all buffers visiting files in the test directory
+ (dolist (buf (buffer-list))
+ (when (buffer-file-name buf)
+ (when (string-prefix-p cj/test-base-dir (buffer-file-name buf))
+ (with-current-buffer buf
+ (set-buffer-modified-p nil)
+ (kill-buffer buf)))))
+ (cj/delete-test-base-dir)
+ (setq kill-ring nil))
+
+;;; Normal Cases
+
+(ert-deftest test-copy-path-simple-file ()
+ "Should copy absolute path for simple file buffer."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (let ((result (cj/copy-path-to-buffer-file-as-kill)))
+ (should (equal result test-file))
+ (should (equal (car kill-ring) test-file)))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-returns-path ()
+ "Should return the path value."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (let ((result (cj/copy-path-to-buffer-file-as-kill)))
+ (should (stringp result))
+ (should (equal result test-file)))))
+ (test-copy-path-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-copy-path-unicode-filename ()
+ "Should handle unicode in filename."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "café.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-spaces-in-filename ()
+ "Should handle spaces in filename."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "my file.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-special-chars-filename ()
+ "Should handle special characters in filename."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "[test]-(1).txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-very-long-path ()
+ "Should handle very long path."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (long-name (make-string 200 ?x))
+ (test-file (expand-file-name (concat long-name ".txt") test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-hidden-file ()
+ "Should handle hidden file."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name ".hidden" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-no-extension ()
+ "Should handle file with no extension."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "README" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-symlink-file ()
+ "Should use buffer's filename for symlink."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (target-file (expand-file-name "target.txt" test-dir))
+ (link-file (expand-file-name "link.txt" test-dir)))
+ (with-temp-file target-file
+ (insert "content"))
+ (make-symbolic-link target-file link-file)
+ (with-current-buffer (find-file link-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) (buffer-file-name)))))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-kill-ring-has-content ()
+ "Should add to kill ring when it already has content."
+ (test-copy-path-setup)
+ (unwind-protect
+ (let* ((test-dir (cj/create-test-subdirectory "test"))
+ (test-file (expand-file-name "test.txt" test-dir)))
+ (with-temp-file test-file
+ (insert "content"))
+ (kill-new "existing content")
+ (with-current-buffer (find-file test-file)
+ (cj/copy-path-to-buffer-file-as-kill)
+ (should (equal (car kill-ring) test-file))
+ (should (equal (cadr kill-ring) "existing content"))))
+ (test-copy-path-teardown)))
+
+;;; Error Cases
+
+(ert-deftest test-copy-path-non-file-buffer ()
+ "Should signal user-error for non-file buffer."
+ (test-copy-path-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (should-error (cj/copy-path-to-buffer-file-as-kill) :type 'user-error))
+ (test-copy-path-teardown)))
+
+(ert-deftest test-copy-path-scratch-buffer ()
+ "Should signal user-error for *scratch* buffer."
+ (test-copy-path-setup)
+ (unwind-protect
+ (with-current-buffer "*scratch*"
+ (should-error (cj/copy-path-to-buffer-file-as-kill) :type 'user-error))
+ (test-copy-path-teardown)))
+
+(provide 'test-custom-file-buffer-copy-path-to-buffer-file-as-kill)
+;;; test-custom-file-buffer-copy-path-to-buffer-file-as-kill.el ends here
diff --git a/tests/test-custom-file-buffer-copy-whole-buffer.el b/tests/test-custom-file-buffer-copy-whole-buffer.el
new file mode 100644
index 00000000..a0546b18
--- /dev/null
+++ b/tests/test-custom-file-buffer-copy-whole-buffer.el
@@ -0,0 +1,194 @@
+;;; test-custom-file-buffer-copy-whole-buffer.el --- Tests for cj/copy-whole-buffer -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the cj/copy-whole-buffer function from custom-file-buffer.el
+;;
+;; This function copies the entire contents of the current buffer to the kill ring.
+;; Point and mark are left exactly where they were. No transient region is created.
+
+;;; Code:
+
+(require 'ert)
+(require 'testutil-general)
+
+;; Add modules directory to load path
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub ps-print package
+(provide 'ps-print)
+
+;; Now load the actual production module
+(require 'custom-file-buffer)
+
+;;; Setup and Teardown
+
+(defun test-copy-whole-buffer-setup ()
+ "Set up test environment."
+ (setq kill-ring nil))
+
+(defun test-copy-whole-buffer-teardown ()
+ "Clean up test environment."
+ (setq kill-ring nil))
+
+;;; Normal Cases
+
+(ert-deftest test-copy-whole-buffer-simple-text ()
+ "Should copy simple text content to kill ring."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello, world!")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "Hello, world!")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-preserves-point ()
+ "Should preserve point position."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello, world!")
+ (goto-char 7) ; Position in middle
+ (cj/copy-whole-buffer)
+ (should (= (point) 7)))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-preserves-mark ()
+ "Should preserve mark position."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello, world!")
+ (push-mark 5)
+ (goto-char 10)
+ (cj/copy-whole-buffer)
+ (should (= (mark) 5))
+ (should (= (point) 10)))
+ (test-copy-whole-buffer-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-copy-whole-buffer-empty ()
+ "Should handle empty buffer."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-large ()
+ "Should handle very large buffer."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (let ((large-content (make-string 100000 ?x)))
+ (insert large-content)
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) large-content))))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-unicode ()
+ "Should handle unicode content (emoji, RTL text)."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Hello 👋 مرحبا")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "Hello 👋 مرحبا")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-binary ()
+ "Should handle binary content."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert (string 0 1 2 255))
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) (string 0 1 2 255))))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-only-whitespace ()
+ "Should handle buffer with only whitespace."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert " \t\n ")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) " \t\n ")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-newlines-at-boundaries ()
+ "Should handle newlines at start/end."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "\n\nHello\n\n")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "\n\nHello\n\n")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-narrowed ()
+ "Should copy only visible region in narrowed buffer."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3\n")
+ (goto-char (point-min))
+ (forward-line 1)
+ (narrow-to-region (point) (progn (forward-line 1) (point)))
+ (cj/copy-whole-buffer)
+ ;; Should copy only the narrowed region
+ (should (equal (car kill-ring) "Line 2\n")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-read-only ()
+ "Should work in read-only buffer."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Read-only content")
+ (read-only-mode 1)
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "Read-only content")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-kill-ring-has-content ()
+ "Should add to kill ring when it already has content."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "New content")
+ (kill-new "existing content")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "New content"))
+ (should (equal (cadr kill-ring) "existing content")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-multiline ()
+ "Should preserve multiline content."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert "Line 1\nLine 2\nLine 3")
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "Line 1\nLine 2\nLine 3")))
+ (test-copy-whole-buffer-teardown)))
+
+(ert-deftest test-copy-whole-buffer-no-properties ()
+ "Should strip text properties."
+ (test-copy-whole-buffer-setup)
+ (unwind-protect
+ (with-temp-buffer
+ (insert (propertize "Hello" 'face 'bold))
+ (cj/copy-whole-buffer)
+ (should (equal (car kill-ring) "Hello"))
+ (should (null (text-properties-at 0 (car kill-ring)))))
+ (test-copy-whole-buffer-teardown)))
+
+(provide 'test-custom-file-buffer-copy-whole-buffer)
+;;; test-custom-file-buffer-copy-whole-buffer.el ends here