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 | 10fa6f4e2e7150ad99827721ada1ae4badcc5e90 (patch) | |
| tree | 960065c8e69f1e7a4150ecf522e2f813c239b5ee /archive/gptel/tests/test-gptel-tools-move-to-trash.el | |
| parent | f4cc70c69e7707dd4a686637e14885f5443fcca6 (diff) | |
| download | dotemacs-10fa6f4e2e7150ad99827721ada1ae4badcc5e90.tar.gz dotemacs-10fa6f4e2e7150ad99827721ada1ae4badcc5e90.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 'archive/gptel/tests/test-gptel-tools-move-to-trash.el')
| -rw-r--r-- | archive/gptel/tests/test-gptel-tools-move-to-trash.el | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/archive/gptel/tests/test-gptel-tools-move-to-trash.el b/archive/gptel/tests/test-gptel-tools-move-to-trash.el new file mode 100644 index 00000000..77f88627 --- /dev/null +++ b/archive/gptel/tests/test-gptel-tools-move-to-trash.el @@ -0,0 +1,219 @@ +;;; test-gptel-tools-move-to-trash.el --- Tests for move_to_trash gptel tool -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the helpers in move_to_trash.el. + +;;; 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) + (unless (featurep 'gptel) + (defvar gptel-tools nil) + (defun gptel-make-tool (&rest _args) nil) + (defun gptel-get-tool (&rest _args) nil) + (provide 'gptel))) + +(require 'move_to_trash) + +;; -------------------------- helpers + +(defun test-gptel-tools-trash--with-tmp-tree (fn) + "Create a temp source dir and trash dir; run FN with both; clean up." + (let* ((src (make-temp-file "test-gptel-tools-trash-src-" t)) + (trash (make-temp-file "test-gptel-tools-trash-dst-" t))) + (unwind-protect + (funcall fn src trash) + (when (file-exists-p src) (delete-directory src t)) + (when (file-exists-p trash) (delete-directory trash t))))) + +;; -------------------------- generate-unique-name + +(ert-deftest test-gptel-tools-trash-generate-unique-name-no-conflict () + "No conflict: returns the plain base name in trash." + (test-gptel-tools-trash--with-tmp-tree + (lambda (_src trash) + (let ((out (gptel--move-to-trash-generate-unique-name + "/anywhere/foo.txt" trash))) + (should (equal (file-name-nondirectory out) "foo.txt")))))) + +(ert-deftest test-gptel-tools-trash-generate-unique-name-conflict-timestamps () + "Name conflict: returns a name with a timestamp suffix." + (test-gptel-tools-trash--with-tmp-tree + (lambda (_src trash) + (with-temp-file (expand-file-name "foo.txt" trash) (insert "")) + (let* ((out (gptel--move-to-trash-generate-unique-name + "/anywhere/foo.txt" trash)) + (name (file-name-nondirectory out))) + (should-not (equal name "foo.txt")) + (should (string-match-p "\\`foo-[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\.txt\\'" + name)))))) + +(ert-deftest test-gptel-tools-trash-generate-unique-name-no-extension () + "Conflict on a name without extension: timestamp appended to the bare name." + (test-gptel-tools-trash--with-tmp-tree + (lambda (_src trash) + (with-temp-file (expand-file-name "noext" trash) (insert "")) + (let* ((out (gptel--move-to-trash-generate-unique-name + "/anywhere/noext" trash)) + (name (file-name-nondirectory out))) + (should-not (equal name "noext")) + (should (string-match-p "\\`noext-[0-9]" name)))))) + +;; -------------------------- validate-path + +(ert-deftest test-gptel-tools-trash-validate-path-normal-home () + "Normal: an existing path under HOME validates." + (let ((path (expand-file-name + (format ".test-gptel-tools-trash-home-%s.tmp" + (format-time-string "%s%N")) + "~"))) + (unwind-protect + (progn + (with-temp-file path (insert "")) + (should (equal (gptel--move-to-trash-validate-path path) + (expand-file-name path)))) + (when (file-exists-p path) (delete-file path))))) + +(ert-deftest test-gptel-tools-trash-validate-path-normal-tmp () + "Normal: an existing path under /tmp validates." + (let ((path (make-temp-file "test-gptel-tools-trash-tmpvalidate-"))) + (unwind-protect + (should (equal (gptel--move-to-trash-validate-path path) + (expand-file-name path))) + (when (file-exists-p path) (delete-file path))))) + +(ert-deftest test-gptel-tools-trash-validate-path-error-outside-allowed () + "Error: a path outside HOME or /tmp signals." + (should-error (gptel--move-to-trash-validate-path "/etc/hostname"))) + +(ert-deftest test-gptel-tools-trash-validate-path-error-tmp-prefix-trick () + "Error: paths that merely start with /tmp are not treated as /tmp children." + (should-error (gptel--move-to-trash-validate-path "/tmpnotreally/file"))) + +(ert-deftest test-gptel-tools-trash-validate-path-error-critical-dir () + "Error: critical directories (home root, .emacs.d, .config, /tmp) signal." + (should-error (gptel--move-to-trash-validate-path "~")) + (should-error (gptel--move-to-trash-validate-path "~/.emacs.d")) + (should-error (gptel--move-to-trash-validate-path "~/.config")) + (should-error (gptel--move-to-trash-validate-path "/tmp"))) + +(ert-deftest test-gptel-tools-trash-validate-path-error-missing () + "Error: missing path signals." + (let ((path (expand-file-name + (format ".test-gptel-tools-trash-missing-%s.tmp" + (format-time-string "%s%N")) + "~"))) + (when (file-exists-p path) (delete-file path)) + (should-error (gptel--move-to-trash-validate-path path)))) + +(ert-deftest test-gptel-tools-trash-validate-path-error-symlink-outside-allowed () + "Error: allowed-location symlinks resolving outside allowed roots are rejected." + (let ((link (expand-file-name + (format ".test-gptel-tools-trash-outside-link-%s.tmp" + (format-time-string "%s%N")) + "~"))) + (unwind-protect + (progn + (make-symbolic-link "/etc/hostname" link t) + (should-error (gptel--move-to-trash-validate-path link))) + (when (file-symlink-p link) (delete-file link))))) + +;; -------------------------- perform + +(ert-deftest test-gptel-tools-trash-perform-moves-file () + "Perform: moves the file out of the source dir into the trash dir." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((file (expand-file-name "doomed.txt" src))) + (with-temp-file file (insert "trash me")) + (let ((status (gptel--move-to-trash-perform file trash))) + (should (string-match-p "moved to trash" status)) + (should-not (file-exists-p file)) + (should (file-exists-p (expand-file-name "doomed.txt" trash)))))))) + +(ert-deftest test-gptel-tools-trash-perform-handles-directory () + "Perform: moves a directory as a unit." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((dir (expand-file-name "subdir" src))) + (make-directory dir) + (with-temp-file (expand-file-name "inside.txt" dir) (insert "x")) + (let ((status (gptel--move-to-trash-perform dir trash))) + (should (string-match-p "Directory moved to trash" status)) + (should-not (file-exists-p dir)) + (should (file-exists-p (expand-file-name "subdir/inside.txt" trash)))))))) + +(ert-deftest test-gptel-tools-trash-perform-handles-symlink () + "Perform: moving a symlink moves the link, not its target." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((target (expand-file-name "target.txt" src)) + (link (expand-file-name "link.txt" src))) + (with-temp-file target (insert "target")) + (make-symbolic-link target link t) + (let ((status (gptel--move-to-trash-perform link trash))) + (should (string-match-p "Symlink moved to trash" status)) + (should (file-exists-p target)) + (should-not (file-symlink-p link)) + (should (file-symlink-p (expand-file-name "link.txt" trash)))))))) + +(ert-deftest test-gptel-tools-trash-perform-error-rename-failure () + "Error: rename failures are reported with context." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((file (expand-file-name "doomed.txt" src))) + (with-temp-file file (insert "trash me")) + (cl-letf (((symbol-function 'rename-file) + (lambda (&rest _args) (error "rename failed")))) + (should-error (gptel--move-to-trash-perform file trash))) + (should (file-exists-p file)))))) + +(ert-deftest test-gptel-tools-trash-perform-error-permission-denied () + "Error: permission-denied rename failures get a specific message." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((file (expand-file-name "denied.txt" src))) + (with-temp-file file (insert "trash me")) + (cl-letf (((symbol-function 'rename-file) + (lambda (&rest _args) + (signal 'permission-denied '("denied"))))) + (should-error (gptel--move-to-trash-perform file trash) + :type 'error)) + (should (file-exists-p file)))))) + +(ert-deftest test-gptel-tools-trash-perform-error-original-still-exists () + "Error: post-move verification catches a source path that remains." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((file (expand-file-name "still-there.txt" src))) + (with-temp-file file (insert "trash me")) + (cl-letf (((symbol-function 'rename-file) + (lambda (&rest _args) nil))) + (should-error (gptel--move-to-trash-perform file trash))) + (should (file-exists-p file)))))) + +(ert-deftest test-gptel-tools-trash-perform-error-trash-missing-after-move () + "Error: post-move verification catches a missing trash target." + (test-gptel-tools-trash--with-tmp-tree + (lambda (src trash) + (let ((file (expand-file-name "missing-trash.txt" src)) + (real-file-exists-p (symbol-function 'file-exists-p))) + (with-temp-file file (insert "trash me")) + (cl-letf (((symbol-function 'rename-file) + (lambda (&rest _args) nil)) + ((symbol-function 'file-exists-p) + (lambda (path) + (cond + ((equal path file) nil) + ((string-prefix-p trash path) nil) + (t (funcall real-file-exists-p path)))))) + (should-error (gptel--move-to-trash-perform file trash))) + (should (funcall real-file-exists-p file)))))) + +(provide 'test-gptel-tools-move-to-trash) +;;; test-gptel-tools-move-to-trash.el ends here |
