aboutsummaryrefslogtreecommitdiff
path: root/tests/test-update-text-file.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-update-text-file.el')
-rw-r--r--tests/test-update-text-file.el123
1 files changed, 122 insertions, 1 deletions
diff --git a/tests/test-update-text-file.el b/tests/test-update-text-file.el
index d689274a..fc4f8c36 100644
--- a/tests/test-update-text-file.el
+++ b/tests/test-update-text-file.el
@@ -148,6 +148,25 @@
(should (equal (cj/update-text-file--insert-at-line "a\nb" 2 "X")
"a\nX\nb")))
+(ert-deftest test-update-text-file-insert-at-line-boundary-text-with-trailing-newline ()
+ "Boundary: inserted text that ends in newline is not double-terminated."
+ (should (equal (cj/update-text-file--insert-at-line "a\nb\n" 2 "X\n")
+ "a\nX\nb\n")))
+
+(ert-deftest test-update-text-file-insert-at-line-boundary-multiline-text ()
+ "Boundary: multi-line inserted text is inserted as a block."
+ (should (equal (cj/update-text-file--insert-at-line "a\nb\n" 2 "X\nY")
+ "a\nX\nY\nb\n")))
+
+(ert-deftest test-update-text-file-insert-at-line-boundary-empty-file-line-1 ()
+ "Boundary: inserting at line 1 in an empty file works."
+ (should (equal (cj/update-text-file--insert-at-line "" 1 "X")
+ "X\n")))
+
+(ert-deftest test-update-text-file-insert-at-line-error-empty-file-line-2 ()
+ "Error: line 2 is out of range for an empty file."
+ (should-error (cj/update-text-file--insert-at-line "" 2 "X")))
+
(ert-deftest test-update-text-file-insert-at-line-error-out-of-range ()
"Error: line number beyond file length signals."
(should-error (cj/update-text-file--insert-at-line "a\nb\n" 5 "X")))
@@ -190,6 +209,15 @@
(should (equal (cj/update-text-file--delete-lines "keep\ndrop" "drop")
"keep")))
+(ert-deftest test-update-text-file-delete-lines-boundary-empty-file ()
+ "Boundary: deleting from an empty file returns the empty string."
+ (should (equal (cj/update-text-file--delete-lines "" "anything") "")))
+
+(ert-deftest test-update-text-file-delete-lines-boundary-backslash-literal ()
+ "Boundary: backslashes in the pattern are literal."
+ (should (equal (cj/update-text-file--delete-lines "keep\npath\\name\n" "\\")
+ "keep\n")))
+
(ert-deftest test-update-text-file-delete-lines-error-empty-pattern ()
"Error: empty pattern signals."
(should-error (cj/update-text-file--delete-lines "a\nb\n" "")))
@@ -253,6 +281,61 @@
"Error: a directory signals."
(should-error (cj/update-text-file--validate-path "~")))
+(ert-deftest test-update-text-file-validate-path-error-unreadable ()
+ "Error: an unreadable file signals."
+ (test-update-text-file--in-home
+ "unreadable" "secret\n"
+ (lambda (path)
+ (cl-letf (((symbol-function 'file-readable-p) (lambda (_) nil)))
+ (should-error (cj/update-text-file--validate-path path))))))
+
+(ert-deftest test-update-text-file-validate-path-error-unwritable ()
+ "Error: an unwritable file signals."
+ (test-update-text-file--in-home
+ "unwritable" "locked\n"
+ (lambda (path)
+ (cl-letf (((symbol-function 'file-writable-p) (lambda (_) nil)))
+ (should-error (cj/update-text-file--validate-path path))))))
+
+(ert-deftest test-update-text-file-validate-path-boundary-relative-home-path ()
+ "Boundary: a relative path resolves under HOME."
+ (test-update-text-file--in-home
+ "relative" "ok\n"
+ (lambda (path)
+ (let ((relative (file-relative-name path (expand-file-name "~"))))
+ (should (equal (cj/update-text-file--validate-path relative)
+ (file-truename path)))))))
+
+(ert-deftest test-update-text-file-validate-path-boundary-symlink-inside-home ()
+ "Boundary: a symlink inside HOME resolving inside HOME is accepted."
+ (test-update-text-file--in-home
+ "symlink-target" "ok\n"
+ (lambda (target)
+ (let ((link (expand-file-name
+ (format ".test-update-text-file-link-%s.tmp"
+ (format-time-string "%s%N"))
+ "~")))
+ (unwind-protect
+ (progn
+ (make-symbolic-link target link t)
+ (should (equal (cj/update-text-file--validate-path link)
+ (file-truename target))))
+ (when (file-symlink-p link) (delete-file link)))))))
+
+(ert-deftest test-update-text-file-validate-path-error-symlink-outside-home ()
+ "Error: a symlink inside HOME pointing outside HOME is rejected."
+ (let ((outside (make-temp-file "test-update-text-file-outside-"))
+ (link (expand-file-name
+ (format ".test-update-text-file-outside-link-%s.tmp"
+ (format-time-string "%s%N"))
+ "~")))
+ (unwind-protect
+ (progn
+ (make-symbolic-link outside link t)
+ (should-error (cj/update-text-file--validate-path link)))
+ (when (file-exists-p outside) (delete-file outside))
+ (when (file-symlink-p link) (delete-file link)))))
+
;; ----------------------------------------------------- backup-name
(ert-deftest test-update-text-file-backup-name-shape ()
@@ -291,7 +374,11 @@ Backups (path-TS.bak) are cleaned up after FN returns."
(with-temp-buffer
(insert-file-contents path)
(should (equal (buffer-string) "GAMMA bravo GAMMA\n")))
- (should (file-expand-wildcards (concat path "-*.bak")))))))
+ (let ((backup (car (file-expand-wildcards (concat path "-*.bak")))))
+ (should backup)
+ (with-temp-buffer
+ (insert-file-contents backup)
+ (should (equal (buffer-string) "alpha bravo alpha\n"))))))))
(ert-deftest test-update-text-file-run-no-change-no-backup ()
"Wrapper: no-op operation leaves the file untouched and creates no backup."
@@ -335,6 +422,40 @@ Backups (path-TS.bak) are cleaned up after FN returns."
(insert-file-contents path)
(should (equal (buffer-string) "keep1\nkeep2\n"))))))
+(ert-deftest test-update-text-file-run-error-transform-leaves-file-unchanged ()
+ "Wrapper: transform errors create no backup and leave the file unchanged."
+ (test-update-text-file--in-home
+ "transform-error" "abc\n"
+ (lambda (path)
+ (should-error (cj/update-text-file--run path "replace" "" "x" nil))
+ (with-temp-buffer
+ (insert-file-contents path)
+ (should (equal (buffer-string) "abc\n")))
+ (should-not (file-expand-wildcards (concat path "-*.bak"))))))
+
+(ert-deftest test-update-text-file-run-error-unknown-operation-leaves-file-unchanged ()
+ "Wrapper: unknown operations create no backup and leave the file unchanged."
+ (test-update-text-file--in-home
+ "unknown-operation" "abc\n"
+ (lambda (path)
+ (should-error (cj/update-text-file--run path "frobnicate" "x" nil nil))
+ (with-temp-buffer
+ (insert-file-contents path)
+ (should (equal (buffer-string) "abc\n")))
+ (should-not (file-expand-wildcards (concat path "-*.bak"))))))
+
+(ert-deftest test-update-text-file-run-error-too-large-leaves-file-unchanged ()
+ "Wrapper: the size guard errors before backup/write."
+ (test-update-text-file--in-home
+ "too-large" "abcdef\n"
+ (lambda (path)
+ (let ((cj/update-text-file--size-limit 3))
+ (should-error (cj/update-text-file--run path "append" "x" nil nil)))
+ (with-temp-buffer
+ (insert-file-contents path)
+ (should (equal (buffer-string) "abcdef\n")))
+ (should-not (file-expand-wildcards (concat path "-*.bak"))))))
+
(ert-deftest test-update-text-file-run-error-missing-file ()
"Wrapper: missing file signals."
(let ((path (expand-file-name