aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-refile-config-scan-targets.el
blob: 71451a29a9eb893c843cb0993c8e2d8b44b3e590 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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