aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-refile-config-scan-targets.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-14 04:10:20 -0500
committerCraig Jennings <c@cjennings.net>2026-05-14 04:10:20 -0500
commitca98dfcb46e4d36732b456983eee51cb909c539b (patch)
tree400b6cb18803747f866ac05017a009bc9ffe7e38 /tests/test-org-refile-config-scan-targets.el
parent933622f511cffcbb574444aa6d5f3978ec5ce3ac (diff)
downloaddotemacs-ca98dfcb46e4d36732b456983eee51cb909c539b.tar.gz
dotemacs-ca98dfcb46e4d36732b456983eee51cb909c539b.zip
test(org-refile-config): cover cj/--org-refile-scan-targets disk walker
Diffstat (limited to 'tests/test-org-refile-config-scan-targets.el')
-rw-r--r--tests/test-org-refile-config-scan-targets.el142
1 files changed, 142 insertions, 0 deletions
diff --git a/tests/test-org-refile-config-scan-targets.el b/tests/test-org-refile-config-scan-targets.el
new file mode 100644
index 00000000..71451a29
--- /dev/null
+++ b/tests/test-org-refile-config-scan-targets.el
@@ -0,0 +1,142 @@
+;;; test-org-refile-config-scan-targets.el --- Tests for the refile scanner -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Sibling tests cover `cj/org-refile-refresh-targets', `cj/org-refile',
+;; and `cj/org-refile-in-file'. This file covers
+;; `cj/--org-refile-scan-targets', the disk-walking helper that builds
+;; the targets list.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'org-refile-config)
+
+;; The scanner reads several globals defined by `user-constants'. Provide
+;; top-level defvars so let-binds become dynamic under lexical scope.
+(defvar inbox-file "/tmp/test-inbox.org")
+(defvar reference-file "/tmp/test-reference.org")
+(defvar schedule-file "/tmp/test-schedule.org")
+(defvar code-dir nil)
+(defvar projects-dir nil)
+
+;;; cj/--org-refile-scan-targets
+
+(ert-deftest test-org-refile-scan-targets-builds-base-list ()
+ "Normal: the scanner returns inbox/reference/schedule entries with their
+maxlevel rules when no roam tags and no code/projects todo files exist."
+ (let* ((tmp (file-name-as-directory (make-temp-file "cj-refile-empty-" t)))
+ (inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ (code-dir tmp)
+ (projects-dir tmp))
+ (unwind-protect
+ (let ((result (cj/--org-refile-scan-targets)))
+ (should (member (cons inbox-file '(:maxlevel . 1)) result))
+ (should (member (cons reference-file '(:maxlevel . 2)) result))
+ (should (member (cons schedule-file '(:maxlevel . 1)) result)))
+ (delete-directory tmp t))))
+
+(ert-deftest test-org-refile-scan-targets-picks-up-todo-files ()
+ "Normal: nested `todo.org' files under code-dir / projects-dir are added."
+ (let* ((tmp (file-name-as-directory (make-temp-file "cj-refile-todo-" t)))
+ (sub (expand-file-name "alpha" tmp))
+ (todo (expand-file-name "todo.org" sub))
+ (inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ (code-dir tmp)
+ (projects-dir tmp))
+ (make-directory sub t)
+ (with-temp-file todo (insert "* heading\n"))
+ (unwind-protect
+ (let ((result (cj/--org-refile-scan-targets)))
+ (should (member (cons todo '(:maxlevel . 1)) result)))
+ (delete-directory tmp t))))
+
+(ert-deftest test-org-refile-scan-targets-skips-airootfs-trees ()
+ "Boundary: subtrees named airootfs are pruned during the walk."
+ (let* ((tmp (file-name-as-directory (make-temp-file "cj-refile-airoot-" t)))
+ (skipped-dir (expand-file-name "airootfs" tmp))
+ (skipped-todo (expand-file-name "todo.org" skipped-dir))
+ (kept-dir (expand-file-name "regular" tmp))
+ (kept-todo (expand-file-name "todo.org" kept-dir))
+ (inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ (code-dir tmp)
+ (projects-dir tmp))
+ (make-directory skipped-dir t)
+ (make-directory kept-dir t)
+ (with-temp-file skipped-todo (insert "* skip me\n"))
+ (with-temp-file kept-todo (insert "* keep me\n"))
+ (unwind-protect
+ (let* ((result (cj/--org-refile-scan-targets))
+ (paths (mapcar #'car result)))
+ (should (member kept-todo paths))
+ (should-not (member skipped-todo paths)))
+ (delete-directory tmp t))))
+
+(ert-deftest test-org-refile-scan-targets-deduplicates-todo-paths ()
+ "Boundary: the same `todo.org' reached via two scan dirs appears once."
+ (let* ((tmp (file-name-as-directory (make-temp-file "cj-refile-dup-" t)))
+ (sub (expand-file-name "shared" tmp))
+ (todo (expand-file-name "todo.org" sub))
+ (inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ ;; Point both directory variables at the same root so the walk runs
+ ;; twice over the same todo file.
+ (code-dir tmp)
+ (projects-dir tmp))
+ (make-directory sub t)
+ (with-temp-file todo (insert "* heading\n"))
+ (unwind-protect
+ (let* ((result (cj/--org-refile-scan-targets))
+ (hits (cl-count-if (lambda (entry) (equal (car entry) todo))
+ result)))
+ (should (= 1 hits)))
+ (delete-directory tmp t))))
+
+(ert-deftest test-org-refile-scan-targets-includes-roam-project-and-topic-files ()
+ "Normal: when the roam helpers are available, Project and Topic files
+become additional refile targets."
+ (let* ((tmp (file-name-as-directory (make-temp-file "cj-refile-roam-" t)))
+ (inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ (code-dir tmp)
+ (projects-dir tmp))
+ (unwind-protect
+ (cl-letf (((symbol-function 'cj/org-roam-list-notes-by-tag)
+ (lambda (tag)
+ (cond
+ ((equal tag "Project") '("/notes/alpha.org"))
+ ((equal tag "Topic") '("/notes/topic.org"))
+ (t nil))))
+ ((symbol-function 'org-roam-node-list)
+ (lambda () nil)))
+ (let* ((result (cj/--org-refile-scan-targets))
+ (paths (mapcar #'car result)))
+ (should (member "/notes/alpha.org" paths))
+ (should (member "/notes/topic.org" paths))))
+ (delete-directory tmp t))))
+
+(ert-deftest test-org-refile-scan-targets-survives-permission-denied ()
+ "Boundary: a permission-denied error during `directory-files-recursively'
+is caught and the scan still returns the base list."
+ (let* ((inbox-file "/tmp/test-inbox.org")
+ (reference-file "/tmp/test-reference.org")
+ (schedule-file "/tmp/test-schedule.org")
+ (code-dir "/nope/code")
+ (projects-dir "/nope/projects"))
+ (cl-letf (((symbol-function 'directory-files-recursively)
+ (lambda (&rest _) (signal 'permission-denied nil))))
+ (let ((result (cj/--org-refile-scan-targets)))
+ (should (member (cons inbox-file '(:maxlevel . 1)) result))))))
+
+(provide 'test-org-refile-config-scan-targets)
+;;; test-org-refile-config-scan-targets.el ends here