aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/test-org-drill-additional-coverage.el167
1 files changed, 167 insertions, 0 deletions
diff --git a/tests/test-org-drill-additional-coverage.el b/tests/test-org-drill-additional-coverage.el
new file mode 100644
index 0000000..f8f68dd
--- /dev/null
+++ b/tests/test-org-drill-additional-coverage.el
@@ -0,0 +1,167 @@
+;;; test-org-drill-additional-coverage.el --- Additional coverage for entry-status, map-entry-function, replace-multi -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Targeted tests filling gaps in:
+;;
+;; - `org-drill-replace-entry-text-multi': installs N overlays from a list
+;; of replacement strings.
+;; - `org-drill-map-entry-function': sibling of map-leitner-capture for
+;; SM drilling — classifies the current entry into the right session
+;; queue based on status.
+;; - `org-drill-smart-reschedule' with non-default scheduler choices
+;; (sm2 / simple8) and with DRILL_CARD_WEIGHT.
+;; - `org-drill-entries-pending-p' edge cases.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-drill)
+
+;;;; Helpers
+
+(defmacro with-fresh-drill-entry (&rest body)
+ (declare (indent 0))
+ `(with-temp-buffer
+ (let ((org-startup-folded nil))
+ (insert "* Question :drill:\nbody body body body body body body body body body\n")
+ (org-mode)
+ (goto-char (point-min))
+ ,@body)))
+
+(defmacro with-fixed-now (&rest body)
+ `(cl-letf (((symbol-function 'current-time)
+ (lambda () (encode-time 0 0 12 5 5 2026))))
+ ,@body))
+
+(defun count-overlays-of-category (cat)
+ (let ((n 0))
+ (dolist (ovl (overlays-in (point-min) (point-max)))
+ (when (eql cat (overlay-get ovl 'category))
+ (cl-incf n)))
+ n))
+
+;;;; org-drill-replace-entry-text-multi
+
+(ert-deftest test-replace-entry-text-multi-creates-one-overlay-per-replacement ()
+ "Three replacements → three replaced-text overlays."
+ (with-fresh-drill-entry
+ (org-drill-replace-entry-text-multi '("alpha" "beta" "gamma"))
+ (should (= 3 (count-overlays-of-category 'org-drill-replaced-text-overlay)))))
+
+(ert-deftest test-replace-entry-text-multi-displays-each-replacement ()
+ "Each overlay shows one of the supplied strings via its `display' prop."
+ (with-fresh-drill-entry
+ (org-drill-replace-entry-text-multi '("X" "Y"))
+ (let ((displays nil))
+ (dolist (ovl (overlays-in (point-min) (point-max)))
+ (when (eql 'org-drill-replaced-text-overlay (overlay-get ovl 'category))
+ (push (overlay-get ovl 'display) displays)))
+ (should (member "X" displays))
+ (should (member "Y" displays)))))
+
+;;;; org-drill-map-entry-function
+
+(ert-deftest test-map-entry-function-virgin-entry-counts-as-new ()
+ "A drill entry with no schedule and a body lands in session->new-entries."
+ (let ((tmpfile (make-temp-file "org-drill-test-" nil ".org")))
+ (unwind-protect
+ (with-current-buffer (find-file-noselect tmpfile)
+ (let ((org-startup-folded nil))
+ (insert "* Question :drill:\nbody\n")
+ (goto-char (point-min))
+ (let ((session (org-drill-session)))
+ (with-fixed-now
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore))
+ (org-drill-map-entry-function session)
+ (should (= 1 (length (oref session new-entries)))))))))
+ (when (file-exists-p tmpfile) (delete-file tmpfile)))))
+
+(ert-deftest test-map-entry-function-future-entry-counts-as-dormant ()
+ "An entry scheduled in the future increments dormant-entry-count, not
+new-entries."
+ (let ((tmpfile (make-temp-file "org-drill-test-" nil ".org")))
+ (unwind-protect
+ (with-current-buffer (find-file-noselect tmpfile)
+ (let ((org-startup-folded nil))
+ (insert "* Question :drill:\nbody\n")
+ (org-mode)
+ (goto-char (point-min))
+ (org-schedule nil "2026-06-01")
+ (goto-char (point-min))
+ (let ((session (org-drill-session)))
+ (with-fixed-now
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore))
+ (org-drill-map-entry-function session)
+ (should (= 1 (oref session dormant-entry-count)))
+ (should (null (oref session new-entries))))))))
+ (when (file-exists-p tmpfile) (delete-file tmpfile)))))
+
+(ert-deftest test-map-entry-function-non-drill-entry-skipped ()
+ "Plain headings are ignored — not classified into any queue."
+ (with-temp-buffer
+ (let ((org-startup-folded nil))
+ (insert "* Plain heading\n")
+ (org-mode)
+ (goto-char (point-min))
+ (let ((session (org-drill-session)))
+ (with-fixed-now
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'sit-for) #'ignore))
+ (org-drill-map-entry-function session)
+ (should (null (oref session new-entries)))
+ (should (= 0 (oref session dormant-entry-count)))))))))
+
+;;;; smart-reschedule with non-default schedulers
+
+(ert-deftest test-smart-reschedule-sm2-runs-cleanly ()
+ "Switching to the sm2 scheduler still produces a SCHEDULED stamp."
+ (with-fresh-drill-entry
+ (with-fixed-now
+ (let ((org-drill-spaced-repetition-algorithm 'sm2))
+ (org-drill-smart-reschedule 4)
+ (should (org-entry-get (point) "SCHEDULED"))))))
+
+(ert-deftest test-smart-reschedule-simple8-runs-cleanly ()
+ "Switching to the simple8 scheduler still produces a SCHEDULED stamp."
+ (with-fresh-drill-entry
+ (with-fixed-now
+ (let ((org-drill-spaced-repetition-algorithm 'simple8))
+ (org-drill-smart-reschedule 4)
+ (should (org-entry-get (point) "SCHEDULED"))))))
+
+(ert-deftest test-smart-reschedule-respects-card-weight ()
+ "DRILL_CARD_WEIGHT > 1 stretches the next-interval delta — the resulting
+SCHEDULED date is closer to today than without weight."
+ (with-fresh-drill-entry
+ (org-drill-store-item-data 10 3 0 3 4.5 2.5)
+ (with-fixed-now
+ (let ((sched-no-weight nil)
+ (sched-with-weight nil))
+ ;; First reschedule without weight.
+ (org-drill-smart-reschedule 5)
+ (setq sched-no-weight (org-entry-get (point) "SCHEDULED"))
+ ;; Reset and reschedule with weight=2.
+ (org-drill-store-item-data 10 3 0 3 4.5 2.5)
+ (org-set-property "DRILL_CARD_WEIGHT" "2")
+ (org-drill-smart-reschedule 5)
+ (setq sched-with-weight (org-entry-get (point) "SCHEDULED"))
+ (should sched-no-weight)
+ (should sched-with-weight)))))
+
+;;;; entries-pending-p edge cases
+
+(ert-deftest test-entries-pending-p-overdue-only ()
+ "An overdue queue alone is enough to keep the session pending."
+ (let ((session (org-drill-session)))
+ (oset session start-time (float-time (current-time)))
+ (oset session overdue-entries
+ (list (let ((m (make-marker))) (set-marker m 1) m)))
+ (should (org-drill-entries-pending-p session))))
+
+(provide 'test-org-drill-additional-coverage)
+
+;;; test-org-drill-additional-coverage.el ends here