diff options
| author | Craig Jennings <c@cjennings.net> | 2025-10-26 18:14:00 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-10-26 18:14:00 -0500 |
| commit | 65aec47bf3d949f7401d7b00fd1ee1dd3ee26dd0 (patch) | |
| tree | 409d9904e040933fd3096cc2bf6146ca4ce94458 /tests | |
| parent | ef1cb62b2323dec7990da89f2de24746c74d49bf (diff) | |
test+fix:custom-file-buffer: add tests, fix linter warning
Add 58 unit tests for buffer/file utility functions:
- cj/copy-link-to-buffer-file (12 tests)
- cj/copy-path-to-buffer-file-as-kill (12 tests)
- cj/copy-whole-buffer (14 tests)
- cj/clear-to-bottom-of-buffer (10 tests)
- cj/clear-to-top-of-buffer (10 tests)
Tests cover normal cases, boundary cases (unicode, empty buffers, narrowing,
read-only buffers), and error cases.
Production code change:
- Fix linter warning: unused variable 'err' → '_' in cj/move-buffer-and-file
Diffstat (limited to 'tests')
5 files changed, 933 insertions, 0 deletions
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 |
