diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-23 20:12:58 -0400 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-23 20:12:58 -0400 |
| commit | e41c25068d0cec9434895a6d3e3a25d3a26f645f (patch) | |
| tree | 5e30938a3fd6d80f501ffe3e6c1c187c5ddeb2c9 /tests/test-update-text-file.el | |
| parent | a936e081b7270fbd4f1e7e9cb67ca1d4c2291ce6 (diff) | |
| download | dotemacs-e41c25068d0cec9434895a6d3e3a25d3a26f645f.tar.gz dotemacs-e41c25068d0cec9434895a6d3e3a25d3a26f645f.zip | |
chore(ai): archive gptel and remove it from the live config
I archived gptel to archive/gptel/ since I rarely use it. Moved there: the six gptel modules (ai-config, ai-conversations, ai-conversations-browser, ai-mcp, ai-quick-ask, ai-rewrite), the gptel-tools/ directory, custom/gptel-prompts.el, their test files and utilities, and the four gptel-only specs.
Scrubbed from the live config: the ai-config require in init.el, which also drops the whole C-; a keymap; the gptel-mode emojify hook in font-config.el; the gptel-tools entries in the Makefile clean target and the coverage runner; and the gptel feature notes in README. Cancelled the open gptel tasks in todo.org (the AI Open Work issues, the feature-extension brainstorm, the velox gptel-magit bug).
ai-term stays. It is the ghostel Claude launcher, independent of gptel.
Verified: every module loads, a batch init launch reaches completion clean, and the full test suite shows only pre-existing coverage failures unrelated to this change.
Diffstat (limited to 'tests/test-update-text-file.el')
| -rw-r--r-- | tests/test-update-text-file.el | 473 |
1 files changed, 0 insertions, 473 deletions
diff --git a/tests/test-update-text-file.el b/tests/test-update-text-file.el deleted file mode 100644 index fc4f8c36a..000000000 --- a/tests/test-update-text-file.el +++ /dev/null @@ -1,473 +0,0 @@ -;;; test-update-text-file.el --- Tests for update_text_file gptel tool -*- lexical-binding: t; -*- - -;;; Commentary: -;; Normal / Boundary / Error tests for each operation in -;; gptel-tools/update_text_file.el, plus file-level wrapper tests. -;; The pure-string helpers carry most of the coverage; the wrapper -;; only adds the I/O surface (backup, write, validation). - -;;; Code: - -(require 'ert) -(require 'cl-lib) - -(eval-and-compile - (add-to-list 'load-path (expand-file-name "tests" user-emacs-directory)) - (add-to-list 'load-path (expand-file-name "gptel-tools" user-emacs-directory)) - (setq load-prefer-newer t) - ;; Stub gptel so the tool file can be loaded without the real package. - (unless (featurep 'gptel) - (defvar gptel-tools nil) - (defun gptel-make-tool (&rest _args) nil) - (defun gptel-get-tool (&rest _args) nil) - (provide 'gptel))) - -(require 'update_text_file) - -;; ----------------------------------------------------- helpers - -(defun test-update-text-file--with-temp (content fn) - "Write CONTENT to a temp file, call FN with its path, then delete." - (let ((path (make-temp-file "test-update-text-file-"))) - (unwind-protect - (progn - (with-temp-file path (insert content)) - (funcall fn path)) - (when (file-exists-p path) (delete-file path))))) - -;; ----------------------------------------------------- replace - -(ert-deftest test-update-text-file-replace-normal () - "Normal: replace all occurrences of the literal pattern." - (should (equal (cj/update-text-file--replace "foo bar foo" "foo" "BAZ") - "BAZ bar BAZ"))) - -(ert-deftest test-update-text-file-replace-boundary-no-match () - "Boundary: pattern absent returns content unchanged." - (should (equal (cj/update-text-file--replace "abc" "xyz" "QQ") "abc"))) - -(ert-deftest test-update-text-file-replace-boundary-special-chars () - "Boundary: regex metacharacters in pattern are treated as literals." - (should (equal (cj/update-text-file--replace "a.b.c" "." "-") "a-b-c")) - (should (equal (cj/update-text-file--replace "(x)(y)" "(x)" "_") "_(y)")) - (should (equal (cj/update-text-file--replace "a$b" "$" "S") "aSb"))) - -(ert-deftest test-update-text-file-replace-boundary-unicode () - "Boundary: unicode in both pattern and replacement." - (should (equal (cj/update-text-file--replace "café résumé" "café" "thé") - "thé résumé"))) - -(ert-deftest test-update-text-file-replace-boundary-replacement-with-backref-like () - "Boundary: replacement strings with \\1 etc. are literal, not back-refs." - (should (equal (cj/update-text-file--replace "foo" "foo" "\\1bar") - "\\1bar"))) - -(ert-deftest test-update-text-file-replace-error-empty-pattern () - "Error: empty pattern signals." - (should-error (cj/update-text-file--replace "abc" "" "x"))) - -(ert-deftest test-update-text-file-replace-error-nil-pattern () - "Error: nil pattern signals." - (should-error (cj/update-text-file--replace "abc" nil "x"))) - -(ert-deftest test-update-text-file-replace-error-nil-replacement () - "Error: nil replacement signals." - (should-error (cj/update-text-file--replace "abc" "a" nil))) - -;; ----------------------------------------------------- append - -(ert-deftest test-update-text-file-append-normal () - "Normal: append adds text plus a trailing newline." - (should (equal (cj/update-text-file--append "line1\n" "line2") - "line1\nline2\n"))) - -(ert-deftest test-update-text-file-append-boundary-no-trailing-newline () - "Boundary: appends still produce a newline when content has none." - (should (equal (cj/update-text-file--append "abc" "def") - "abc\ndef\n"))) - -(ert-deftest test-update-text-file-append-boundary-empty-content () - "Boundary: appending to empty content yields just the new text + newline." - (should (equal (cj/update-text-file--append "" "hello") "hello\n"))) - -(ert-deftest test-update-text-file-append-boundary-text-with-trailing-newline () - "Boundary: text that already ends in newline isn't duplicated." - (should (equal (cj/update-text-file--append "a\n" "b\n") "a\nb\n"))) - -(ert-deftest test-update-text-file-append-error-empty-text () - "Error: empty text signals." - (should-error (cj/update-text-file--append "foo" ""))) - -(ert-deftest test-update-text-file-append-error-nil-text () - "Error: nil text signals." - (should-error (cj/update-text-file--append "foo" nil))) - -;; ----------------------------------------------------- prepend - -(ert-deftest test-update-text-file-prepend-normal () - "Normal: prepend adds text plus a separator newline." - (should (equal (cj/update-text-file--prepend "line1\n" "line0") - "line0\nline1\n"))) - -(ert-deftest test-update-text-file-prepend-boundary-empty-content () - "Boundary: prepending to empty content keeps just the new text + sep." - (should (equal (cj/update-text-file--prepend "" "hello") "hello\n"))) - -(ert-deftest test-update-text-file-prepend-boundary-text-with-trailing-newline () - "Boundary: text already terminated by newline is not double-broken." - (should (equal (cj/update-text-file--prepend "rest" "first\n") - "first\nrest"))) - -(ert-deftest test-update-text-file-prepend-error-empty-text () - "Error: empty text signals." - (should-error (cj/update-text-file--prepend "foo" ""))) - -(ert-deftest test-update-text-file-prepend-error-nil-text () - "Error: nil text signals." - (should-error (cj/update-text-file--prepend "foo" nil))) - -;; ----------------------------------------------------- insert-at-line - -(ert-deftest test-update-text-file-insert-at-line-normal () - "Normal: insert before line 2 of a 3-line file." - (should (equal (cj/update-text-file--insert-at-line "a\nb\nc\n" 2 "X") - "a\nX\nb\nc\n"))) - -(ert-deftest test-update-text-file-insert-at-line-boundary-first-line () - "Boundary: inserting at line 1 prepends." - (should (equal (cj/update-text-file--insert-at-line "a\nb\n" 1 "X") - "X\na\nb\n"))) - -(ert-deftest test-update-text-file-insert-at-line-boundary-one-past-end () - "Boundary: inserting one past the last line appends." - (should (equal (cj/update-text-file--insert-at-line "a\nb\n" 3 "X") - "a\nb\nX\n"))) - -(ert-deftest test-update-text-file-insert-at-line-boundary-no-trailing-newline () - "Boundary: works on content without a trailing newline." - (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"))) - -(ert-deftest test-update-text-file-insert-at-line-error-zero () - "Error: line number 0 signals." - (should-error (cj/update-text-file--insert-at-line "a\n" 0 "X"))) - -(ert-deftest test-update-text-file-insert-at-line-error-negative () - "Error: negative line number signals." - (should-error (cj/update-text-file--insert-at-line "a\n" -1 "X"))) - -(ert-deftest test-update-text-file-insert-at-line-error-empty-text () - "Error: empty text signals." - (should-error (cj/update-text-file--insert-at-line "a\n" 1 ""))) - -;; ----------------------------------------------------- delete-lines - -(ert-deftest test-update-text-file-delete-lines-normal () - "Normal: removes lines containing the literal pattern." - (should (equal (cj/update-text-file--delete-lines "keep\nkill me\nkeep\n" "kill") - "keep\nkeep\n"))) - -(ert-deftest test-update-text-file-delete-lines-boundary-no-match () - "Boundary: pattern matches nothing returns content unchanged." - (should (equal (cj/update-text-file--delete-lines "a\nb\nc\n" "z") - "a\nb\nc\n"))) - -(ert-deftest test-update-text-file-delete-lines-boundary-all-lines-match () - "Boundary: every line removed yields the empty string." - (should (equal (cj/update-text-file--delete-lines "x\nx\nx\n" "x") ""))) - -(ert-deftest test-update-text-file-delete-lines-boundary-special-chars-literal () - "Boundary: regex metacharacters in pattern are treated as literals." - (should (equal (cj/update-text-file--delete-lines "a.b\naxb\n" ".") - "axb\n"))) - -(ert-deftest test-update-text-file-delete-lines-boundary-no-trailing-newline () - "Boundary: content without trailing newline keeps that shape." - (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" ""))) - -(ert-deftest test-update-text-file-delete-lines-error-nil-pattern () - "Error: nil pattern signals." - (should-error (cj/update-text-file--delete-lines "a\nb\n" nil))) - -;; ----------------------------------------------------- apply-operation - -(ert-deftest test-update-text-file-apply-operation-dispatch () - "Each operation name dispatches to its transform." - (should (equal (cj/update-text-file--apply-operation "abc" "replace" "b" "B" nil) - "aBc")) - (should (equal (cj/update-text-file--apply-operation "a" "append" "b" nil nil) - "a\nb\n")) - (should (equal (cj/update-text-file--apply-operation "a" "prepend" "b" nil nil) - "b\na")) - (should (equal (cj/update-text-file--apply-operation "a\nb\n" "insert-at-line" "X" nil 2) - "a\nX\nb\n")) - (should (equal (cj/update-text-file--apply-operation "a\nb\n" "delete-lines" "a" nil nil) - "b\n"))) - -(ert-deftest test-update-text-file-apply-operation-error-unknown () - "Unknown operation signals." - (should-error (cj/update-text-file--apply-operation "x" "frobnicate" nil nil nil))) - -;; ----------------------------------------------------- validate-path - -(ert-deftest test-update-text-file-validate-path-normal () - "Normal: an existing readable+writable file under HOME passes." - (let* ((file (make-temp-file "test-update-text-file-"))) - (unwind-protect - (progn - ;; make-temp-file may land in /tmp; rebase to HOME for the test. - (let* ((home-file (expand-file-name - (concat ".test-update-text-file-" (format-time-string "%s") ".tmp") - "~"))) - (unwind-protect - (progn - (copy-file file home-file t) - (should (equal (cj/update-text-file--validate-path home-file) - (file-truename home-file)))) - (when (file-exists-p home-file) (delete-file home-file))))) - (when (file-exists-p file) (delete-file file))))) - -(ert-deftest test-update-text-file-validate-path-error-missing () - "Error: a missing file under HOME signals." - (let ((path (expand-file-name - (concat ".test-update-text-file-missing-" - (format-time-string "%s") ".tmp") - "~"))) - (when (file-exists-p path) (delete-file path)) - (should-error (cj/update-text-file--validate-path path)))) - -(ert-deftest test-update-text-file-validate-path-error-outside-home () - "Error: a path outside HOME signals." - (should-error (cj/update-text-file--validate-path "/etc/hostname"))) - -(ert-deftest test-update-text-file-validate-path-error-directory () - "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 () - "Backup names append a timestamped .bak suffix." - (let ((name (cj/update-text-file--backup-name "/home/user/foo.txt"))) - (should (string-prefix-p "/home/user/foo.txt-" name)) - (should (string-suffix-p ".bak" name)) - ;; Format is YYYY-MM-DD-HHMMSS. - (should (string-match-p "-[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{6\\}\\.bak\\'" - name)))) - -;; ----------------------------------------------------- file-level wrapper - -(defun test-update-text-file--in-home (suffix content fn) - "Write CONTENT to a temp file under HOME with SUFFIX, call FN, then delete. -Backups (path-TS.bak) are cleaned up after FN returns." - (let* ((name (format ".test-update-text-file-%s-%s.tmp" - suffix (format-time-string "%s%N"))) - (path (expand-file-name name "~"))) - (unwind-protect - (progn - (with-temp-file path (insert content)) - (funcall fn path)) - (when (file-exists-p path) (delete-file path)) - (dolist (b (file-expand-wildcards (concat path "-*.bak"))) - (when (file-exists-p b) (delete-file b)))))) - -(ert-deftest test-update-text-file-run-replace-normal () - "Wrapper: replace operation rewrites the file and creates a backup." - (test-update-text-file--in-home - "replace" "alpha bravo alpha\n" - (lambda (path) - (let ((result (cj/update-text-file--run path "replace" "alpha" "GAMMA" nil))) - (should (string-match-p "Updated" result)) - (should (string-match-p "backup:" result)) - (with-temp-buffer - (insert-file-contents path) - (should (equal (buffer-string) "GAMMA bravo GAMMA\n"))) - (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." - (test-update-text-file--in-home - "noop" "abc\n" - (lambda (path) - (let ((result (cj/update-text-file--run path "replace" "zzz" "QQ" nil))) - (should (string-match-p "No changes" result)) - (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-append-normal () - "Wrapper: append operation adds a line to the file." - (test-update-text-file--in-home - "append" "first\n" - (lambda (path) - (cj/update-text-file--run path "append" "second" nil nil) - (with-temp-buffer - (insert-file-contents path) - (should (equal (buffer-string) "first\nsecond\n")))))) - -(ert-deftest test-update-text-file-run-insert-at-line-normal () - "Wrapper: insert-at-line inserts and rewrites the file." - (test-update-text-file--in-home - "insert" "a\nb\nc\n" - (lambda (path) - (cj/update-text-file--run path "insert-at-line" "X" nil 2) - (with-temp-buffer - (insert-file-contents path) - (should (equal (buffer-string) "a\nX\nb\nc\n")))))) - -(ert-deftest test-update-text-file-run-delete-lines-normal () - "Wrapper: delete-lines removes matching lines." - (test-update-text-file--in-home - "delete" "keep1\nkill\nkeep2\nkill\n" - (lambda (path) - (cj/update-text-file--run path "delete-lines" "kill" nil nil) - (with-temp-buffer - (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 - (concat ".test-update-text-file-absent-" - (format-time-string "%s") ".tmp") - "~"))) - (when (file-exists-p path) (delete-file path)) - (should-error (cj/update-text-file--run path "append" "x" nil nil)))) - -(ert-deftest test-update-text-file-run-error-outside-home () - "Wrapper: path outside home signals." - (should-error (cj/update-text-file--run "/etc/hostname" "append" "x" nil nil))) - -(provide 'test-update-text-file) -;;; test-update-text-file.el ends here |
