aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/test-org-drill-leitner-orchestrator.el106
1 files changed, 106 insertions, 0 deletions
diff --git a/tests/test-org-drill-leitner-orchestrator.el b/tests/test-org-drill-leitner-orchestrator.el
new file mode 100644
index 0000000..e2d3f75
--- /dev/null
+++ b/tests/test-org-drill-leitner-orchestrator.el
@@ -0,0 +1,106 @@
+;;; test-org-drill-leitner-orchestrator.el --- Tests for the leitner main entry -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for `org-drill-leitner', the public Leitner-learning command. The
+;; orchestrator captures all leitner-tagged entries, fills box 1 if there
+;; aren't enough boxed entries, then runs the per-entry loop until the
+;; user quits or asks to edit.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-drill)
+
+(defmacro with-leitner-orch-tempfile (content &rest body)
+ "Run BODY in a tempfile-backed org buffer with CONTENT and clean leitner queues."
+ (declare (indent 1))
+ `(let ((tmpfile (make-temp-file "org-drill-leitner-orch-" nil ".org"))
+ (org-drill-leitner-boxed-entries nil)
+ (org-drill-leitner-unboxed-entries nil))
+ (unwind-protect
+ (with-current-buffer (find-file-noselect tmpfile)
+ (let ((org-startup-folded nil))
+ (insert ,content)
+ (org-mode)
+ (goto-char (point-min))
+ ,@body))
+ (when (file-exists-p tmpfile) (delete-file tmpfile)))))
+
+(ert-deftest test-leitner-finishes-cleanly-when-loop-returns-t-each-step ()
+ "When every leitner-entry returns t, the loop completes and the
+'Finished Leitner Learning' summary is printed."
+ (with-leitner-orch-tempfile
+ "* A :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 1\n:END:\n* B :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 2\n:END:\n"
+ (let ((messages nil)
+ (org-drill-leitner-completed 0))
+ (cl-letf (((symbol-function 'org-drill-leitner-entry)
+ (lambda (&rest _) t))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (when fmt (push (apply #'format fmt args) messages))))
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore))
+ (org-drill-leitner))
+ (should (cl-some (lambda (m) (string-match-p "Finished Leitner" m))
+ messages)))))
+
+(ert-deftest test-leitner-quit-short-circuits-the-loop ()
+ "When leitner-entry returns (quit ,_), the pcase matches the quit branch
+and the function returns t without running further entries."
+ (with-leitner-orch-tempfile
+ "* A :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 1\n:END:\n* B :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 2\n:END:\n"
+ (let ((calls 0))
+ (cl-letf (((symbol-function 'org-drill-leitner-entry)
+ (lambda (&rest _)
+ (cl-incf calls)
+ 'quit))
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore))
+ (should (eq t (org-drill-leitner)))
+ (should (= 1 calls))))))
+
+(ert-deftest test-leitner-edit-jumps-to-marker ()
+ "When leitner-entry returns (edit MARKER), the orchestrator jumps to MARKER."
+ (with-leitner-orch-tempfile
+ "* A :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 1\n:END:\nbody\n"
+ (let ((jumped-to nil)
+ (entry-marker nil))
+ (cl-letf (((symbol-function 'org-drill-leitner-entry)
+ (lambda (&rest _) 'edit))
+ ((symbol-function 'org-drill-goto-entry)
+ (lambda (m)
+ (setq jumped-to m)
+ (when (markerp m) (goto-char m))))
+ ((symbol-function 'org-reveal) #'ignore)
+ ((symbol-function 'org-fold-show-entry) #'ignore)
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore))
+ (setq entry-marker (point-marker))
+ (org-drill-leitner)
+ ;; goto-entry was called twice — once to navigate to the entry,
+ ;; once again on the edit branch. We just check it was called.
+ (should jumped-to)))))
+
+(ert-deftest test-leitner-fills-box-when-boxed-queue-is-too-small ()
+ "If fewer boxed entries than maximum-items-per-session, leitner-start-box
+runs to fill box 1 from the unboxed queue."
+ (with-leitner-orch-tempfile
+ "* A :leitner:\nbody\n* B :leitner:\nbody\n"
+ (let ((start-box-called nil))
+ (cl-letf (((symbol-function 'org-drill-leitner-start-box)
+ (lambda (&rest _) (setq start-box-called t)))
+ ((symbol-function 'org-drill-leitner-entry)
+ (lambda (&rest _) t))
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore))
+ (let ((org-drill-maximum-items-per-session 5))
+ (org-drill-leitner)))
+ (should start-box-called))))
+
+(provide 'test-org-drill-leitner-orchestrator)
+;;; test-org-drill-leitner-orchestrator.el ends here