diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-05 14:06:48 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-05 14:06:48 -0500 |
| commit | 0d32f8f6df9406c12306d97592446408ba7984e3 (patch) | |
| tree | becff5fbd172082fba54ed95a20f3133918c4118 | |
| parent | 63713acf8238aceee199a5f595fda6470c633939 (diff) | |
| download | org-drill-0d32f8f6df9406c12306d97592446408ba7984e3.tar.gz org-drill-0d32f8f6df9406c12306d97592446408ba7984e3.zip | |
test: cover map-leitner-capture, response-mode, timer, sm2/simple8 dispatch
I added direct tests for `org-drill-map-leitner-capture' (route by
DRILL_LEITNER_BOX), the response-mode exit-kind handlers (quit/edit/skip/
tags/rtn), `org-drill-presentation-timer-cancel', and the sm2/simple8
branches of `org-drill-smart-reschedule''s algorithm dispatcher.
Coverage moved from 80.6% to 81.8%.
| -rw-r--r-- | tests/test-org-drill-map-leitner-capture.el | 84 | ||||
| -rw-r--r-- | tests/test-org-drill-response-and-timer.el | 108 | ||||
| -rw-r--r-- | tests/test-org-drill-smart-reschedule.el | 18 |
3 files changed, 210 insertions, 0 deletions
diff --git a/tests/test-org-drill-map-leitner-capture.el b/tests/test-org-drill-map-leitner-capture.el new file mode 100644 index 0000000..bc43c7d --- /dev/null +++ b/tests/test-org-drill-map-leitner-capture.el @@ -0,0 +1,84 @@ +;;; test-org-drill-map-leitner-capture.el --- Tests for map-leitner-capture -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `org-drill-map-leitner-capture', the per-entry callback that +;; routes a leitner-tagged heading into either `org-drill-leitner-boxed-entries' +;; (when DRILL_LEITNER_BOX is set 0-5) or `org-drill-leitner-unboxed-entries' +;; (when the property is missing). Box values >5 are graduates and are +;; ignored. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'org) +(require 'org-drill) + +(defmacro with-leitner-tempfile (content &rest body) + "Run BODY in a tempfile-backed org buffer with CONTENT, with empty leitner queues." + (declare (indent 1)) + `(let ((tmpfile (make-temp-file "org-drill-leitner-test-" 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-map-leitner-capture-no-box-property-pushes-unboxed () + "Entry with no DRILL_LEITNER_BOX lands in the unboxed queue." + (with-leitner-tempfile "* Card :leitner:\nbody\n" + (let ((session (org-drill-session)) + (org-drill-question-tag org-drill-leitner-tag)) + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (org-drill-map-leitner-capture session)) + (should (= 1 (length org-drill-leitner-unboxed-entries))) + (should (= 0 (length org-drill-leitner-boxed-entries)))))) + +(ert-deftest test-map-leitner-capture-box-in-range-pushes-boxed () + "Entry with DRILL_LEITNER_BOX 0-5 lands in the boxed queue." + (dolist (box '("0" "1" "2" "3" "4" "5")) + (with-leitner-tempfile (format "* Card :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: %s\n:END:\nbody\n" box) + (let ((session (org-drill-session)) + (org-drill-question-tag org-drill-leitner-tag)) + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (org-drill-map-leitner-capture session)) + (should (= 1 (length org-drill-leitner-boxed-entries))) + (should (= 0 (length org-drill-leitner-unboxed-entries))))))) + +(ert-deftest test-map-leitner-capture-graduate-box-skipped () + "Entry with DRILL_LEITNER_BOX > 5 is ignored — already graduated." + (with-leitner-tempfile "* Card :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: 6\n:END:\nbody\n" + (let ((session (org-drill-session)) + (org-drill-question-tag org-drill-leitner-tag)) + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (org-drill-map-leitner-capture session)) + (should (= 0 (length org-drill-leitner-boxed-entries))) + (should (= 0 (length org-drill-leitner-unboxed-entries)))))) + +(ert-deftest test-map-leitner-capture-non-drill-entry-skipped () + "Non-drill heading is skipped entirely." + (with-leitner-tempfile "Just text, no headlines\n" + (let ((session (org-drill-session)) + (org-drill-question-tag org-drill-leitner-tag)) + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (org-drill-map-leitner-capture session)) + (should (= 0 (length org-drill-leitner-boxed-entries))) + (should (= 0 (length org-drill-leitner-unboxed-entries)))))) + +(ert-deftest test-map-leitner-capture-increments-session-counter () + "Each call bumps the session's `cnt' slot." + (with-leitner-tempfile "* Card :leitner:\nbody\n" + (let ((session (org-drill-session))) + (oset session cnt 0) + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (org-drill-map-leitner-capture session) + (org-drill-map-leitner-capture session)) + (should (= 2 (oref session cnt)))))) + +(provide 'test-org-drill-map-leitner-capture) +;;; test-org-drill-map-leitner-capture.el ends here diff --git a/tests/test-org-drill-response-and-timer.el b/tests/test-org-drill-response-and-timer.el new file mode 100644 index 0000000..4da8e9a --- /dev/null +++ b/tests/test-org-drill-response-and-timer.el @@ -0,0 +1,108 @@ +;;; test-org-drill-response-and-timer.el --- Tests for response-mode and timer -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the response-mode helpers and the presentation-timer cancel +;; helper. These are all small functions whose only job is to flip a +;; session slot or clear a global timer. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'org) +(require 'org-drill) + +;;;; org-drill-presentation-timer-cancel + +(ert-deftest test-presentation-timer-cancel-with-no-timer-clears-counter () + "Cancel called with no timer just resets the counter." + (let ((org-drill-presentation-timer nil) + (org-drill-presentation-timer-calls 7)) + (org-drill-presentation-timer-cancel) + (should (null org-drill-presentation-timer)) + (should (= 0 org-drill-presentation-timer-calls)))) + +(ert-deftest test-presentation-timer-cancel-with-active-timer-cancels-and-clears () + "Cancel called with an active timer cancels it and zeroes the counter." + (let ((cancelled nil)) + (cl-letf (((symbol-function 'cancel-timer) + (lambda (_) (setq cancelled t)))) + (let ((org-drill-presentation-timer 'fake-timer) + (org-drill-presentation-timer-calls 5)) + (org-drill-presentation-timer-cancel) + (should cancelled) + (should (null org-drill-presentation-timer)) + (should (= 0 org-drill-presentation-timer-calls)))))) + +;;;; Response-mode exit kinds + +(defmacro with-fake-response-buffer (&rest body) + "Run BODY in a buffer where org-drill-current-session is bound and +exit-recursive-edit and kill-buffer are stubbed." + (declare (indent 0)) + `(let ((session (org-drill-session)) + (exited nil)) + (with-temp-buffer + (setq-local org-drill-current-session session) + (cl-letf (((symbol-function 'kill-buffer) #'ignore) + ((symbol-function 'exit-recursive-edit) + (lambda () (setq exited t)))) + ,@body) + (cons session exited)))) + +(ert-deftest test-response-quit-sets-exit-kind-quit () + (let* ((result (with-fake-response-buffer + (org-drill-response-quit))) + (session (car result))) + (should (eq 'quit (oref session exit-kind))) + (should (cdr result)))) + +(ert-deftest test-response-edit-sets-exit-kind-edit () + (let* ((result (with-fake-response-buffer + (org-drill-response-edit))) + (session (car result))) + (should (eq 'edit (oref session exit-kind))) + (should (cdr result)))) + +(ert-deftest test-response-skip-sets-exit-kind-skip () + (let* ((result (with-fake-response-buffer + (org-drill-response-skip))) + (session (car result))) + (should (eq 'skip (oref session exit-kind))) + (should (cdr result)))) + +(ert-deftest test-response-tags-sets-exit-kind-tags () + (let* ((result (with-fake-response-buffer + (org-drill-response-tags))) + (session (car result))) + (should (eq 'tags (oref session exit-kind))) + (should (cdr result)))) + +(ert-deftest test-response-rtn-stores-typed-answer-and-exits () + "Return key captures buffer text into typed-answer and sets exit-kind t." + (let ((session (org-drill-session)) + (exited nil)) + (with-temp-buffer + (insert "my-answer") + (setq-local org-drill-current-session session) + (cl-letf (((symbol-function 'kill-buffer) #'ignore) + ((symbol-function 'exit-recursive-edit) + (lambda () (setq exited t)))) + (org-drill-response-rtn))) + (should (equal "my-answer" (oref session typed-answer))) + (should (eq t (oref session exit-kind))) + (should exited))) + +;;;; Response buffer creation + +(ert-deftest test-response-get-buffer-create-returns-fresh-buffer () + "The helper returns a buffer in `org-drill-response-mode' with empty content." + (let ((buf (org-drill-response-get-buffer-create))) + (unwind-protect + (with-current-buffer buf + (should (eq major-mode 'org-drill-response-mode)) + (should (= (point-min) (point-max)))) + (kill-buffer buf)))) + +(provide 'test-org-drill-response-and-timer) +;;; test-org-drill-response-and-timer.el ends here diff --git a/tests/test-org-drill-smart-reschedule.el b/tests/test-org-drill-smart-reschedule.el index 49eddb0..6fbf3d6 100644 --- a/tests/test-org-drill-smart-reschedule.el +++ b/tests/test-org-drill-smart-reschedule.el @@ -91,6 +91,24 @@ because the cond compared nil with `=' before the type-guard." (let ((scheduled (current-scheduled-time-string))) (should scheduled))))) +;;;; Algorithm dispatch (covers the cl-case branches in smart-reschedule) + +(ert-deftest test-org-drill-smart-reschedule-sm2-algorithm-schedules () + "With sm2 selected, smart-reschedule still produces a SCHEDULED stamp." + (with-fresh-drill-entry + (with-fixed-now + (let ((org-drill-spaced-repetition-algorithm 'sm2)) + (org-drill-smart-reschedule 5)) + (should (current-scheduled-time-string))))) + +(ert-deftest test-org-drill-smart-reschedule-simple8-algorithm-schedules () + "With simple8 selected, smart-reschedule still produces a SCHEDULED stamp." + (with-fresh-drill-entry + (with-fixed-now + (let ((org-drill-spaced-repetition-algorithm 'simple8)) + (org-drill-smart-reschedule 5)) + (should (current-scheduled-time-string))))) + ;;;; Property side-effects (ert-deftest test-org-drill-smart-reschedule-writes-drill-properties () |
