aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-05 14:28:01 -0500
committerCraig Jennings <c@cjennings.net>2026-05-05 14:28:01 -0500
commitac734cfd3208cb3d50c24ff1eb371c75fe71d59c (patch)
treea6c1b69c8dd3c917e662a07782fa8c11a6636661
parentddc4b289a0ad96407746ea267e6b4def33b1503b (diff)
downloadorg-drill-ac734cfd3208cb3d50c24ff1eb371c75fe71d59c.tar.gz
org-drill-ac734cfd3208cb3d50c24ff1eb371c75fe71d59c.zip
test: cover the org-drill main entry and hypothetical-next-review-date dispatch
I added tests for the public `org-drill' command that mock `org-drill-entries' so the orchestrator runs in batch: empty buffer → 'no pending' message, populated buffer → entry loop runs, cram=t flag flips the session's cram-mode slot, resume-p skips entry collection. I also extended the cloze + scheduling helpers file with sm2 and simple8 coverage for `org-drill-hypothetical-next-review-date'. Coverage moved from 89.0% to 89.8%.
-rw-r--r--tests/test-org-drill-cloze-and-scheduling-helpers.el16
-rw-r--r--tests/test-org-drill-main-entry.el113
2 files changed, 129 insertions, 0 deletions
diff --git a/tests/test-org-drill-cloze-and-scheduling-helpers.el b/tests/test-org-drill-cloze-and-scheduling-helpers.el
index ba6503c..1ee4c61 100644
--- a/tests/test-org-drill-cloze-and-scheduling-helpers.el
+++ b/tests/test-org-drill-cloze-and-scheduling-helpers.el
@@ -115,6 +115,22 @@ symbol itself."
(should (equal 0 (org-drill-hypothetical-next-review-date 1)))
(should (equal 0 (org-drill-hypothetical-next-review-date 2)))))
+(ert-deftest test-org-drill-hypothetical-next-review-date-sm2-algorithm ()
+ "With sm2 selected, hypothetical-next-review-date returns a positive number."
+ (with-fresh-drill-entry
+ (let ((org-drill-spaced-repetition-algorithm 'sm2))
+ (let ((days (org-drill-hypothetical-next-review-date 5)))
+ (should (numberp days))
+ (should (>= days 0))))))
+
+(ert-deftest test-org-drill-hypothetical-next-review-date-simple8-algorithm ()
+ "With simple8 selected, hypothetical-next-review-date returns a positive number."
+ (with-fresh-drill-entry
+ (let ((org-drill-spaced-repetition-algorithm 'simple8))
+ (let ((days (org-drill-hypothetical-next-review-date 5)))
+ (should (numberp days))
+ (should (>= days 0))))))
+
(ert-deftest test-org-drill-hypothetical-next-review-date-quality-monotonic ()
"Higher quality means longer next-interval — the curve should be monotonic
non-decreasing across q=3 → q=5 on a virgin card."
diff --git a/tests/test-org-drill-main-entry.el b/tests/test-org-drill-main-entry.el
new file mode 100644
index 0000000..adc1721
--- /dev/null
+++ b/tests/test-org-drill-main-entry.el
@@ -0,0 +1,113 @@
+;;; test-org-drill-main-entry.el --- Tests for the main org-drill orchestrator -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the public `org-drill' command — the main orchestrator that
+;; sets up a session, scans for entries, and dispatches into the entry
+;; loop. We mock the recursive-edit-driven `org-drill-entries' to keep
+;; the tests batch-friendly.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-drill)
+
+(defmacro with-org-drill-tempfile (content &rest body)
+ "Run BODY in a tempfile-backed org buffer with CONTENT."
+ (declare (indent 1))
+ `(let ((tmpfile (make-temp-file "org-drill-main-" nil ".org")))
+ (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-org-drill-empty-buffer-messages-no-pending ()
+ "An empty buffer takes the `queues-empty-p' branch and messages no items."
+ (with-org-drill-tempfile "Plain text, no drill entries.\n"
+ (let ((messages nil)
+ (org-drill-save-buffers-after-drill-sessions-p nil))
+ (cl-letf (((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)
+ ((symbol-function 'org-drill-final-report) #'ignore)
+ ((symbol-function 'org-drill--setup-display) #'ignore)
+ ((symbol-function 'org-drill--restore-display) #'ignore)
+ ((symbol-function 'persist-save) #'ignore))
+ (org-drill 'file))
+ (should (cl-some (lambda (m)
+ (string-match-p "did not find any pending" m))
+ messages)))))
+
+(ert-deftest test-org-drill-with-entries-runs-entry-loop ()
+ "A buffer with a drill entry calls `org-drill-entries' and finishes cleanly."
+ (with-org-drill-tempfile "* Card :drill:\nbody\n"
+ (let ((entries-called nil)
+ (messages nil)
+ (org-drill-save-buffers-after-drill-sessions-p nil))
+ (cl-letf (((symbol-function 'org-drill-entries)
+ (lambda (&rest _) (setq entries-called 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)
+ ((symbol-function 'org-drill-final-report) #'ignore)
+ ((symbol-function 'org-drill--setup-display) #'ignore)
+ ((symbol-function 'org-drill--restore-display) #'ignore)
+ ((symbol-function 'persist-save) #'ignore))
+ (org-drill 'file))
+ (should entries-called)
+ (should (cl-some (lambda (m) (string-match-p "Drill session finished" m))
+ messages)))))
+
+(ert-deftest test-org-drill-cram-flag-sets-session-cram-mode ()
+ "Calling org-drill with cram=t leaves cram-mode bound during the session."
+ (with-org-drill-tempfile "* Card :drill:\nbody\n"
+ (let ((seen-cram nil)
+ (org-drill-save-buffers-after-drill-sessions-p nil))
+ (cl-letf (((symbol-function 'org-drill-entries)
+ (lambda (s &rest _)
+ (setq seen-cram (oref s cram-mode))))
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'org-drill-final-report) #'ignore)
+ ((symbol-function 'org-drill--setup-display) #'ignore)
+ ((symbol-function 'org-drill--restore-display) #'ignore)
+ ((symbol-function 'persist-save) #'ignore))
+ (org-drill 'file nil nil t))
+ (should seen-cram))))
+
+(ert-deftest test-org-drill-resume-p-skips-collection ()
+ "When resume-p is non-nil, the entry collection step is skipped."
+ (with-org-drill-tempfile "* Card :drill:\nbody\n"
+ (let ((collect-called nil)
+ (org-drill-save-buffers-after-drill-sessions-p nil)
+ (org-drill-last-session (org-drill-session)))
+ (oset org-drill-last-session start-time (float-time (current-time)))
+ (oset org-drill-last-session new-entries
+ (list (let ((m (make-marker))) (set-marker m 1 (current-buffer)) m)))
+ (cl-letf (((symbol-function 'org-drill--collect-entries)
+ (lambda (&rest _) (setq collect-called t)))
+ ((symbol-function 'org-drill-entries) #'ignore)
+ ((symbol-function 'message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore)
+ ((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'org-drill-final-report) #'ignore)
+ ((symbol-function 'org-drill--setup-display) #'ignore)
+ ((symbol-function 'org-drill--restore-display) #'ignore)
+ ((symbol-function 'persist-save) #'ignore))
+ (org-drill 'file nil t))
+ (should-not collect-called))))
+
+(provide 'test-org-drill-main-entry)
+;;; test-org-drill-main-entry.el ends here