auto-update-daily-20260202
  1;;; org-batch-functions-test.el --- Tests for org-batch-functions -*- lexical-binding: t -*-
  2
  3;; Copyright (C) 2026 Vincent Demeester
  4
  5;;; Commentary:
  6
  7;; Comprehensive tests for org-batch-functions.el v2.0 (org-ql based)
  8;; Run with: emacs --batch -l org-batch-functions-test.el -f org-batch-run-all-tests
  9
 10;;; Code:
 11
 12(require 'org-batch-functions)
 13(require 'ert)
 14
 15(defvar org-batch-test-file "/home/vincent/desktop/org/todos.org"
 16  "File to use for testing.")
 17
 18(defvar org-batch-test-results '()
 19  "Accumulator for test results.")
 20
 21(defun org-batch-test-report (name passed &optional message)
 22  "Report test NAME result (PASSED t/nil) with optional MESSAGE."
 23  (push (list name passed message) org-batch-test-results)
 24  (princ (format "%s %s%s\n"
 25                 (if passed "" "")
 26                 name
 27                 (if message (format " - %s" message) ""))))
 28
 29(defun org-batch-test-assert (name condition &optional message)
 30  "Assert CONDITION is true for test NAME."
 31  (org-batch-test-report name condition message))
 32
 33;;; Read Operations Tests
 34
 35(defun org-batch-test-list-todos ()
 36  "Test org-batch-list-todos function."
 37  (let ((results (org-batch-list-todos org-batch-test-file)))
 38    (org-batch-test-assert
 39     "list-todos: returns list"
 40     (listp results)
 41     (format "got %d items" (length results)))
 42    (org-batch-test-assert
 43     "list-todos: items have heading"
 44     (and (car results) (alist-get 'heading (car results)))
 45     (format "first: %s" (alist-get 'heading (car results))))))
 46
 47(defun org-batch-test-list-todos-filter-state ()
 48  "Test state filtering."
 49  (let ((next-items (org-batch-list-todos org-batch-test-file "NEXT"))
 50        (todo-items (org-batch-list-todos org-batch-test-file "TODO")))
 51    (org-batch-test-assert
 52     "list-todos-filter-state: NEXT filter works"
 53     (and (listp next-items)
 54          (or (null next-items)
 55              (string= "NEXT" (alist-get 'todo (car next-items)))))
 56     (format "%d NEXT items" (length next-items)))
 57    (org-batch-test-assert
 58     "list-todos-filter-state: TODO filter works"
 59     (and (listp todo-items)
 60          (or (null todo-items)
 61              (string= "TODO" (alist-get 'todo (car todo-items)))))
 62     (format "%d TODO items" (length todo-items)))))
 63
 64(defun org-batch-test-list-todos-comma-separated ()
 65  "Test comma-separated state filtering."
 66  (let ((results (org-batch-list-todos org-batch-test-file "NEXT,STRT")))
 67    (org-batch-test-assert
 68     "list-todos-comma-separated: works"
 69     (and (listp results)
 70          (or (null results)
 71              (member (alist-get 'todo (car results)) '("NEXT" "STRT"))))
 72     (format "%d items" (length results)))))
 73
 74(defun org-batch-test-scheduled-today ()
 75  "Test org-batch-scheduled-today function."
 76  (let ((results (org-batch-scheduled-today org-batch-test-file)))
 77    (org-batch-test-assert
 78     "scheduled-today: returns list"
 79     (listp results)
 80     (format "%d scheduled today" (length results)))))
 81
 82(defun org-batch-test-by-section ()
 83  "Test org-batch-by-section function."
 84  (let ((results (org-batch-by-section org-batch-test-file "Systems")))
 85    (org-batch-test-assert
 86     "by-section: finds Systems section"
 87     (and (listp results) (> (length results) 0))
 88     (format "%d items in Systems" (length results)))))
 89
 90(defun org-batch-test-count-by-state ()
 91  "Test org-batch-count-by-state function."
 92  (let ((counts (org-batch-count-by-state org-batch-test-file)))
 93    (org-batch-test-assert
 94     "count-by-state: returns alist"
 95     (and (listp counts) (assoc 'total counts))
 96     (format "total: %d" (alist-get 'total counts)))
 97    (org-batch-test-assert
 98     "count-by-state: has TODO count"
 99     (assoc 'TODO counts)
100     (format "TODO: %d" (alist-get 'TODO counts)))))
101
102(defun org-batch-test-search ()
103  "Test org-batch-search function."
104  (let ((results (org-batch-search org-batch-test-file "tekton")))
105    (org-batch-test-assert
106     "search: finds tekton"
107     (and (listp results) (> (length results) 0))
108     (format "%d matches for 'tekton'" (length results)))))
109
110(defun org-batch-test-get-sections ()
111  "Test org-batch-get-sections function."
112  (let ((sections (org-batch-get-sections org-batch-test-file)))
113    (org-batch-test-assert
114     "get-sections: returns list"
115     (and (listp sections) (> (length sections) 0))
116     (format "sections: %s" (string-join (seq-take sections 3) ", ")))))
117
118(defun org-batch-test-get-overdue ()
119  "Test org-batch-get-overdue function."
120  (let ((results (org-batch-get-overdue org-batch-test-file)))
121    (org-batch-test-assert
122     "get-overdue: returns list"
123     (listp results)
124     (format "%d overdue items" (length results)))))
125
126(defun org-batch-test-get-upcoming ()
127  "Test org-batch-get-upcoming function."
128  (let ((results (org-batch-get-upcoming org-batch-test-file 7)))
129    (org-batch-test-assert
130     "get-upcoming: returns list"
131     (listp results)
132     (format "%d items in next 7 days" (length results)))))
133
134(defun org-batch-test-get-recurring-tasks ()
135  "Test org-batch-get-recurring-tasks function."
136  (let ((results (org-batch-get-recurring-tasks org-batch-test-file)))
137    (org-batch-test-assert
138     "get-recurring-tasks: returns list"
139     (listp results)
140     (format "%d recurring tasks" (length results)))
141    (org-batch-test-assert
142     "get-recurring-tasks: has repeater field"
143     (or (null results) (assoc 'repeater (car results)))
144     "repeater field present")))
145
146(defun org-batch-test-get-blocked-tasks ()
147  "Test org-batch-get-blocked-tasks function."
148  (let ((results (org-batch-get-blocked-tasks org-batch-test-file)))
149    (org-batch-test-assert
150     "get-blocked-tasks: returns list"
151     (listp results)
152     (format "%d blocked tasks" (length results)))))
153
154;;; New org-ql Capabilities Tests
155
156(defun org-batch-test-clocked-today ()
157  "Test org-batch-clocked-today function (NEW)."
158  (let ((results (org-batch-clocked-today org-batch-test-file)))
159    (org-batch-test-assert
160     "clocked-today (NEW): returns list"
161     (listp results)
162     (format "%d clocked today" (length results)))))
163
164(defun org-batch-test-habits ()
165  "Test org-batch-habits function (NEW)."
166  (let ((results (org-batch-habits org-batch-test-file)))
167    (org-batch-test-assert
168     "habits (NEW): returns list"
169     (listp results)
170     (format "%d habits" (length results)))))
171
172(defun org-batch-test-priority-items ()
173  "Test org-batch-priority-items function (NEW)."
174  (let ((results (org-batch-priority-items org-batch-test-file 1 2)))
175    (org-batch-test-assert
176     "priority-items (NEW): returns list"
177     (listp results)
178     (format "%d priority 1-2 items" (length results)))))
179
180(defun org-batch-test-with-property ()
181  "Test org-batch-with-property function (NEW)."
182  (let ((results (org-batch-with-property org-batch-test-file "CREATED")))
183    (org-batch-test-assert
184     "with-property (NEW): returns list"
185     (listp results)
186     (format "%d items with CREATED property" (length results)))))
187
188;;; Statistics Tests
189
190(defun org-batch-test-get-statistics ()
191  "Test org-batch-get-statistics function."
192  (let ((stats (org-batch-get-statistics org-batch-test-file)))
193    (org-batch-test-assert
194     "get-statistics: returns alist"
195     (and (listp stats) (assoc 'total stats))
196     (format "total: %d" (alist-get 'total stats)))
197    (org-batch-test-assert
198     "get-statistics: has by_state"
199     (assoc 'by_state stats)
200     "by_state present")
201    (org-batch-test-assert
202     "get-statistics: has overdue_count"
203     (assoc 'overdue_count stats)
204     (format "overdue: %d" (alist-get 'overdue_count stats)))))
205
206(defun org-batch-test-get-priority-distribution ()
207  "Test org-batch-get-priority-distribution function."
208  (let ((dist (org-batch-get-priority-distribution org-batch-test-file)))
209    (org-batch-test-assert
210     "get-priority-distribution: returns alist"
211     (and (listp dist) (= 5 (length dist)))
212     (format "priorities 1-5 present"))))
213
214(defun org-batch-test-get-tag-statistics ()
215  "Test org-batch-get-tag-statistics function."
216  (let ((stats (org-batch-get-tag-statistics org-batch-test-file)))
217    (org-batch-test-assert
218     "get-tag-statistics: returns list"
219     (listp stats)
220     (format "%d unique tags" (length stats)))))
221
222(defun org-batch-test-list-all-tags ()
223  "Test org-batch-list-all-tags function."
224  (let ((tags (org-batch-list-all-tags org-batch-test-file)))
225    (org-batch-test-assert
226     "list-all-tags: returns sorted list"
227     (and (listp tags)
228          (or (null tags)
229              (null (cdr tags))  ; Only 1 tag - nothing to compare
230              (string< (car tags) (cadr tags))))
231     (format "%d tags" (length tags)))))
232
233;;; Output Format Tests
234
235(defun org-batch-test-json-output ()
236  "Test JSON output functions."
237  (let ((json-output (with-output-to-string
238                       (org-batch-output-json t '((test . "value"))))))
239    (org-batch-test-assert
240     "json-output: valid JSON"
241     (string-match-p "success" json-output)
242     "contains success field")))
243
244;;; Integration Tests
245
246(defun org-batch-test-children ()
247  "Test org-batch-get-children with real heading."
248  ;; First find a heading with children
249  (let* ((sections (org-batch-get-sections org-batch-test-file))
250         (results (when sections
251                    (org-batch-get-children org-batch-test-file (car sections)))))
252    (org-batch-test-assert
253     "get-children: works with real data"
254     (listp results)
255     (format "%d children of '%s'" (length results) (car sections)))))
256
257(defun org-batch-test-get-todo-content ()
258  "Test org-batch-get-todo-content with real heading."
259  (let* ((todos (org-batch-list-todos org-batch-test-file "NEXT"))
260         (heading (when todos (alist-get 'heading (car todos))))
261         (content (when heading (org-batch-get-todo-content org-batch-test-file heading))))
262    (org-batch-test-assert
263     "get-todo-content: returns content"
264     (or (null heading) (listp content))
265     (if content "got content" "no NEXT items to test"))))
266
267;;; Run All Tests
268
269(defun org-batch-run-all-tests ()
270  "Run all tests and print summary."
271  (setq org-batch-test-results '())
272
273  (princ "\n=== org-batch-functions.el v2.0 Test Suite ===\n\n")
274  (princ "--- Read Operations ---\n")
275  (org-batch-test-list-todos)
276  (org-batch-test-list-todos-filter-state)
277  (org-batch-test-list-todos-comma-separated)
278  (org-batch-test-scheduled-today)
279  (org-batch-test-by-section)
280  (org-batch-test-count-by-state)
281  (org-batch-test-search)
282  (org-batch-test-get-sections)
283  (org-batch-test-get-overdue)
284  (org-batch-test-get-upcoming)
285  (org-batch-test-get-recurring-tasks)
286  (org-batch-test-get-blocked-tasks)
287
288  (princ "\n--- New org-ql Capabilities ---\n")
289  (org-batch-test-clocked-today)
290  (org-batch-test-habits)
291  (org-batch-test-priority-items)
292  (org-batch-test-with-property)
293
294  (princ "\n--- Statistics ---\n")
295  (org-batch-test-get-statistics)
296  (org-batch-test-get-priority-distribution)
297  (org-batch-test-get-tag-statistics)
298  (org-batch-test-list-all-tags)
299
300  (princ "\n--- Output Format ---\n")
301  (org-batch-test-json-output)
302
303  (princ "\n--- Integration ---\n")
304  (org-batch-test-children)
305  (org-batch-test-get-todo-content)
306
307  ;; Summary
308  (let* ((total (length org-batch-test-results))
309         (passed (length (seq-filter #'cadr org-batch-test-results)))
310         (failed (- total passed)))
311    (princ (format "\n=== Summary: %d/%d passed" passed total))
312    (when (> failed 0)
313      (princ (format ", %d failed" failed)))
314    (princ " ===\n")
315
316    ;; Return exit code
317    (kill-emacs (if (= failed 0) 0 1))))
318
319(provide 'org-batch-functions-test)
320;;; org-batch-functions-test.el ends here