aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-27 21:40:43 -0500
committerCraig Jennings <c@cjennings.net>2026-05-27 21:40:43 -0500
commita2a7471f88a8c0f5c710d5ffb90511fc54b432d7 (patch)
treeff48348c21808986e5d196a68246781329c6dda8
parent6e3f2d278d9598c6838428ee510445f51888bb30 (diff)
downloadorg-drill-a2a7471f88a8c0f5c710d5ffb90511fc54b432d7.tar.gz
org-drill-a2a7471f88a8c0f5c710d5ffb90511fc54b432d7.zip
refactor: take card-state in org-drill-determine-next-interval-sm5
Stage 4 of #147. sm5 now takes (state quality of-matrix &optional delta-days) instead of nine positional args, binding the recall fields from the struct at the top so the algorithm body is unchanged. Both call-site branches pass the state they already hold, dropping the per-branch accessor unpacking. The testutil adapter test-scheduler--call-sm5 keeps the sm5 test calls a one-symbol rename per site. I also kept the return as the existing list, matching the stage-3 refinement: the goal is reducing the input signature, and changing the return shape would force the shared return-extractors and every return-read to change for no real gain. Also folds in two stage-3 follow-ons I missed when sm2 landed: a direct sm5 call in tests/test-org-drill-small-branch-coverage.el now uses the new struct API inline, and five direct sm2 calls in the simple-workflow integration test now go through the testutil adapter (the integration file picks up the testutil-scheduler require). Caught by running make test-integration this stage, which I should have run on the sm2 stage.
-rw-r--r--org-drill.el34
-rw-r--r--tests/test-integration-drill-session-simple-workflow-integration-test.el16
-rw-r--r--tests/test-org-drill-determine-next-interval-sm5.el74
-rw-r--r--tests/test-org-drill-small-branch-coverage.el5
-rw-r--r--tests/testutil-scheduler.el9
5 files changed, 75 insertions, 63 deletions
diff --git a/org-drill.el b/org-drill.el
index 7046ade..d772657 100644
--- a/org-drill.el
+++ b/org-drill.el
@@ -1334,10 +1334,18 @@ Returns a list:
of
(* of last-interval))))
-(defun org-drill-determine-next-interval-sm5 (last-interval n ef quality
- failures meanq total-repeats
- of-matrix &optional delta-days)
- "Return next interval."
+(defun org-drill-determine-next-interval-sm5 (state quality of-matrix &optional delta-days)
+ "Return the SM5 schedule for STATE after a review of recall QUALITY (0-5).
+
+STATE is an `org-drill-card-state'. OF-MATRIX is the optimal-factor
+matrix. DELTA-DAYS, when set, adjusts the interval for an early or late
+repetition."
+ (let ((last-interval (org-drill-card-state-last-interval state))
+ (n (org-drill-card-state-repetitions state))
+ (ef (org-drill-card-state-ease state))
+ (failures (org-drill-card-state-failures state))
+ (meanq (org-drill-card-state-meanq state))
+ (total-repeats (org-drill-card-state-total-repeats state)))
(if (zerop n) (setq n 1))
(if (null ef) (setq ef 2.5))
(cl-assert (> n 0))
@@ -1384,7 +1392,7 @@ Returns a list:
failures
meanq
(1+ total-repeats)
- of-matrix)))))
+ of-matrix))))))
;;; Simple8 Algorithm =========================================================
(defun org-drill-simple8-first-interval (failures)
@@ -1518,13 +1526,7 @@ item will be scheduled exactly this many days into the future."
failures meanq total-repeats
&optional new-ofmatrix)
(cl-case org-drill-spaced-repetition-algorithm
- (sm5 (org-drill-determine-next-interval-sm5
- (org-drill-card-state-last-interval state)
- (org-drill-card-state-repetitions state)
- (org-drill-card-state-ease state) quality
- (org-drill-card-state-failures state)
- (org-drill-card-state-meanq state)
- (org-drill-card-state-total-repeats state) ofmatrix))
+ (sm5 (org-drill-determine-next-interval-sm5 state quality ofmatrix))
(sm2 (org-drill-determine-next-interval-sm2 state quality))
(simple8 (org-drill-determine-next-interval-simple8
(org-drill-card-state-last-interval state)
@@ -1582,13 +1584,7 @@ of QUALITY."
&optional _ofmatrix)
(cl-case org-drill-spaced-repetition-algorithm
(sm5 (org-drill-determine-next-interval-sm5
- (org-drill-card-state-last-interval state)
- (org-drill-card-state-repetitions state)
- (org-drill-card-state-ease state) quality
- (org-drill-card-state-failures state)
- (org-drill-card-state-meanq state)
- (org-drill-card-state-total-repeats state)
- org-drill-sm5-optimal-factor-matrix))
+ state quality org-drill-sm5-optimal-factor-matrix))
(sm2 (org-drill-determine-next-interval-sm2 state quality))
(simple8 (org-drill-determine-next-interval-simple8
(org-drill-card-state-last-interval state)
diff --git a/tests/test-integration-drill-session-simple-workflow-integration-test.el b/tests/test-integration-drill-session-simple-workflow-integration-test.el
index e6f0aae..f0335af 100644
--- a/tests/test-integration-drill-session-simple-workflow-integration-test.el
+++ b/tests/test-integration-drill-session-simple-workflow-integration-test.el
@@ -7,7 +7,7 @@
;; 1. Entry detection (org-drill-entry-p)
;; 2. Entry enumeration (org-drill-map-entries)
;; 3. Data retrieval (test-int--state-as-list (org-drill-get-item-data))
-;; 4. Scheduling algorithm (org-drill-determine-next-interval-sm2)
+;; 4. Scheduling algorithm (test-scheduler--call-sm2)
;; 5. Data storage (org-drill-store-item-data)
;;
;; This test uses actual org-mode buffers with drill entries to verify
@@ -19,6 +19,10 @@
(require 'assess)
(require 'org-drill)
+(add-to-list 'load-path
+ (file-name-directory (or load-file-name buffer-file-name)))
+(require 'testutil-scheduler)
+
;;; Helpers
(defun test-int--state-as-list (state)
@@ -195,7 +199,7 @@ Verifies integration between data retrieval and SM2 algorithm."
(test-int--state-as-list (org-drill-get-item-data))
;; Simulate quality rating of 4 (good recall)
(let* ((quality 4)
- (result (org-drill-determine-next-interval-sm2
+ (result (test-scheduler--call-sm2
last-interval repeats ease quality
failures meanq total-repeats))
(next-interval (nth 0 result))
@@ -220,7 +224,7 @@ Verifies that failure handling works correctly in integrated workflow."
(test-int--state-as-list (org-drill-get-item-data))
;; Simulate complete failure (quality 0)
(let* ((quality 0)
- (result (org-drill-determine-next-interval-sm2
+ (result (test-scheduler--call-sm2
last-interval repeats ease quality
failures meanq total-repeats))
(next-interval (nth 0 result))
@@ -249,7 +253,7 @@ Verifies org-drill-store-item-data updates properties correctly."
;; Calculate new scheduling data
(let* ((quality 5) ; Perfect recall
- (result (org-drill-determine-next-interval-sm2
+ (result (test-scheduler--call-sm2
last-interval repeats ease quality
failures meanq total-repeats))
(next-interval (nth 0 result))
@@ -339,7 +343,7 @@ Simulates reviewing a card and verifies all components work together."
;; Step 4: Simulate review with quality 4
(let* ((quality 4)
- (result (org-drill-determine-next-interval-sm2
+ (result (test-scheduler--call-sm2
last-interval repeats ease quality
failures meanq total-repeats))
(next-interval (nth 0 result))
@@ -459,7 +463,7 @@ Question content.
;; Verify scheduling can handle extreme values
(cl-destructuring-bind (last-interval repeats failures total-repeats meanq ease)
data
- (let ((result (org-drill-determine-next-interval-sm2
+ (let ((result (test-scheduler--call-sm2
last-interval repeats ease 4
failures meanq total-repeats)))
(should (listp result)))))))))
diff --git a/tests/test-org-drill-determine-next-interval-sm5.el b/tests/test-org-drill-determine-next-interval-sm5.el
index a7c9a73..01dbf54 100644
--- a/tests/test-org-drill-determine-next-interval-sm5.el
+++ b/tests/test-org-drill-determine-next-interval-sm5.el
@@ -12,7 +12,7 @@
;; repetitions-p is enabled.
;;
;; Function signature:
-;; (org-drill-determine-next-interval-sm5 last-interval n ef quality
+;; (test-scheduler--call-sm5 last-interval n ef quality
;; failures meanq total-repeats
;; of-matrix &optional delta-days)
;;
@@ -42,7 +42,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-first-review-quality-4 ()
"Normal: first successful review with quality 4 returns positive interval and increments repeats."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 0 1 nil 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 0 1 nil 4 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(ef (test-scheduler--extract-ef result)))
@@ -53,7 +53,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-second-review-quality-4 ()
"Normal: second successful review with quality 4 increments repeats to 3."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 1 2 2.5 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 1 2 2.5 4 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result)))
(should (> interval 0))
@@ -62,7 +62,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-third-review-quality-4 ()
"Normal: third successful review uses OF-matrix lookup and returns positive interval."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result)))
(should (> interval 0))
@@ -71,21 +71,21 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-quality-5-perfect-recall ()
"Normal: quality 5 maintains or increases EF on successful path."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 2.5 5 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 2.5 5 0 nil 0 nil nil))
(ef (test-scheduler--extract-ef result)))
(should (>= ef 2.5)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-quality-3-adequate-recall ()
"Normal: quality 3 decreases EF below initial but keeps it above the floor."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 2.5 3 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 2.5 3 0 nil 0 nil nil))
(ef (test-scheduler--extract-ef result)))
(should (> ef test-sm5-min-ef))
(should (< ef 2.5)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-failure-quality-0 ()
"Normal: failed review with quality 0 resets interval to -1, repeats to 1, increments failures."
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 2.5 0 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 2.5 0 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(ef (test-scheduler--extract-ef result))
@@ -97,7 +97,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-failure-quality-1 ()
"Normal: failed review with quality 1 resets interval, preserves input EF, increments failures."
- (let* ((result (org-drill-determine-next-interval-sm5 15 5 2.6 1 2 3.5 10 nil nil))
+ (let* ((result (test-scheduler--call-sm5 15 5 2.6 1 2 3.5 10 nil nil))
(interval (test-scheduler--extract-interval result))
(ef (test-scheduler--extract-ef result))
(failures (test-scheduler--extract-failures result)))
@@ -107,14 +107,14 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-failure-quality-2 ()
"Normal: quality 2 (= default org-drill-failure-quality) triggers failure path."
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 2.5 2 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 2.5 2 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result)))
(should (= interval -1))))
(ert-deftest test-org-drill-determine-next-interval-sm5-normal-failure-preserves-old-ef ()
"Normal: SM5 failure path returns the input EF (OLD-EF), not the modified one."
(let* ((input-ef 2.7)
- (result (org-drill-determine-next-interval-sm5 10 3 input-ef 0 0 nil 0 nil nil))
+ (result (test-scheduler--call-sm5 10 3 input-ef 0 0 nil 0 nil nil))
(returned-ef (test-scheduler--extract-ef result)))
;; modify-e-factor would have computed a different value, but the failure
;; branch returns old-ef, which is the input ef.
@@ -124,7 +124,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-nil-ef-uses-default ()
"Boundary: nil EF defaults to 2.5."
- (let* ((result (org-drill-determine-next-interval-sm5 0 1 nil 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 0 1 nil 4 0 nil 0 nil nil))
(ef (test-scheduler--extract-ef result)))
(should ef)
(should (> ef 0))))
@@ -132,27 +132,27 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-zero-n-becomes-one ()
"Boundary: n=0 is treated as n=1, so returned repeats is 2."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 0 0 2.5 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 0 0 2.5 4 0 nil 0 nil nil))
(repeats (test-scheduler--extract-repeats result)))
(should (= repeats 2)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-nil-meanq-uses-quality ()
"Boundary: nil meanq initializes to current quality."
(let* ((quality 4)
- (result (org-drill-determine-next-interval-sm5 0 1 2.5 quality 0 nil 0 nil nil))
+ (result (test-scheduler--call-sm5 0 1 2.5 quality 0 nil 0 nil nil))
(meanq (test-scheduler--extract-meanq result)))
(should (= meanq quality))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-quality-5-maximum ()
"Boundary: maximum quality 5 is accepted and produces a positive interval."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 1 2 2.5 5 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 1 2 2.5 5 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result)))
(should (> interval 0)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-quality-0-minimum ()
"Boundary: minimum quality 0 triggers the failure path with interval -1."
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 2.5 0 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 2.5 0 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result)))
(should (= interval -1))))
@@ -161,7 +161,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(let* ((quality 4)
(meanq 3.0)
(total-repeats 10)
- (result (org-drill-determine-next-interval-sm5 10 3 2.5 quality 0 meanq total-repeats nil nil))
+ (result (test-scheduler--call-sm5 10 3 2.5 quality 0 meanq total-repeats nil nil))
(new-meanq (test-scheduler--extract-meanq result))
(expected (/ (+ quality (* meanq total-repeats 1.0))
(1+ total-repeats))))
@@ -170,28 +170,28 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-ef-below-floor ()
"Boundary: input EF below 1.3 is raised to 1.3 by org-drill-modify-e-factor."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 1.0 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 1.0 4 0 nil 0 nil nil))
(ef (test-scheduler--extract-ef result)))
(should (>= ef test-sm5-min-ef)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-ef-at-floor ()
"Boundary: EF exactly at floor (1.3) does not crash and remains >= 1.3 with quality 4."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 10 3 1.3 4 0 4.0 10 nil nil))
+ (let* ((result (test-scheduler--call-sm5 10 3 1.3 4 0 4.0 10 nil nil))
(ef (test-scheduler--extract-ef result)))
(should (>= ef test-sm5-min-ef)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-total-repeats-increments ()
"Boundary: total-repeats is always incremented by 1, including on failure."
(let* ((total-repeats 42)
- (result-success (org-drill-determine-next-interval-sm5 10 3 2.5 4 0 3.5 total-repeats nil nil))
- (result-failure (org-drill-determine-next-interval-sm5 10 3 2.5 0 0 3.5 total-repeats nil nil)))
+ (result-success (test-scheduler--call-sm5 10 3 2.5 4 0 3.5 total-repeats nil nil))
+ (result-failure (test-scheduler--call-sm5 10 3 2.5 0 0 3.5 total-repeats nil nil)))
(should (= (test-scheduler--extract-total-repeats result-success) (1+ total-repeats)))
(should (= (test-scheduler--extract-total-repeats result-failure) (1+ total-repeats)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-nil-of-matrix-uses-default ()
"Boundary: nil of-matrix defaults to org-drill-sm5-optimal-factor-matrix and returns a list."
- (let* ((result (org-drill-determine-next-interval-sm5 0 1 2.5 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 0 1 2.5 4 0 nil 0 nil nil))
(matrix (test-scheduler--extract-of-matrix result)))
(should (listp matrix))))
@@ -202,13 +202,13 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
;; silently corrupt the literal across test runs.
(let* ((input-matrix (list (list 10 (cons 1.0 1.0))))
(snapshot (copy-tree input-matrix)))
- (org-drill-determine-next-interval-sm5 0 1 2.5 4 0 nil 0 input-matrix nil)
+ (test-scheduler--call-sm5 0 1 2.5 4 0 nil 0 input-matrix nil)
(should (equal input-matrix snapshot))))
(ert-deftest test-org-drill-determine-next-interval-sm5-boundary-delta-days-nil ()
"Boundary: nil delta-days (the default) skips the early-review adjustment."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil nil))
+ (let* ((result (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil nil))
(interval (test-scheduler--extract-interval result)))
(should (numberp interval))
(should (> interval 0)))))
@@ -217,8 +217,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
"Boundary: positive delta-days (late review) does not trigger the early-adjustment path."
(let ((org-drill-add-random-noise-to-intervals-p nil)
(org-drill-adjust-intervals-for-early-and-late-repetitions-p t))
- (let* ((result-late (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil 5))
- (result-no-delta (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil nil))
+ (let* ((result-late (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil 5))
+ (result-no-delta (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil nil))
(interval-late (test-scheduler--extract-interval result-late))
(interval-no-delta (test-scheduler--extract-interval result-no-delta)))
(should (= interval-late interval-no-delta)))))
@@ -227,8 +227,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
"Boundary: negative delta-days with adjust-flag disabled does not change the interval."
(let ((org-drill-add-random-noise-to-intervals-p nil)
(org-drill-adjust-intervals-for-early-and-late-repetitions-p nil))
- (let* ((result-no-adjust (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil -5))
- (result-no-delta (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil nil))
+ (let* ((result-no-adjust (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil -5))
+ (result-no-delta (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil nil))
(interval-no-adjust (test-scheduler--extract-interval result-no-adjust))
(interval-no-delta (test-scheduler--extract-interval result-no-delta)))
(should (= interval-no-adjust interval-no-delta)))))
@@ -237,7 +237,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.")
"Boundary: negative delta-days with adjust-flag enabled runs the early-interval-factor branch."
(let ((org-drill-add-random-noise-to-intervals-p nil)
(org-drill-adjust-intervals-for-early-and-late-repetitions-p t))
- (let* ((result (org-drill-determine-next-interval-sm5 6 3 2.5 4 0 nil 0 nil -5))
+ (let* ((result (test-scheduler--call-sm5 6 3 2.5 4 0 nil 0 nil -5))
(interval (test-scheduler--extract-interval result)))
(should (numberp interval))
(should (> interval 0)))))
@@ -261,23 +261,23 @@ ERT-29 signal-hook quirk that forces a `skip-unless' on Emacs <30."
(ert-deftest test-org-drill-determine-next-interval-sm5-error-negative-n ()
"Error: n=-1 violates the (cl-assert (> n 0)) precondition."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm5 0 -1 2.5 4 0 nil 0 nil nil)))
+ (test-scheduler--call-sm5 0 -1 2.5 4 0 nil 0 nil nil)))
(ert-deftest test-org-drill-determine-next-interval-sm5-error-quality-below-zero ()
"Error: quality=-1 violates the cl-assert quality range."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm5 0 1 2.5 -1 0 nil 0 nil nil)))
+ (test-scheduler--call-sm5 0 1 2.5 -1 0 nil 0 nil nil)))
(ert-deftest test-org-drill-determine-next-interval-sm5-error-quality-above-five ()
"Error: quality=6 violates the cl-assert quality range."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm5 0 1 2.5 6 0 nil 0 nil nil)))
+ (test-scheduler--call-sm5 0 1 2.5 6 0 nil 0 nil nil)))
;;; Algorithm Verification
(ert-deftest test-org-drill-determine-next-interval-sm5-algorithm-return-value-structure ()
"Algorithm: return value is a 7-element list with the documented field types."
- (let ((result (org-drill-determine-next-interval-sm5 10 3 2.5 4 0 3.5 10 nil nil)))
+ (let ((result (test-scheduler--call-sm5 10 3 2.5 4 0 3.5 10 nil nil)))
(should (listp result))
(should (= (length result) 7))
(should (numberp (nth 0 result))) ; interval
@@ -291,32 +291,32 @@ ERT-29 signal-hook quirk that forces a `skip-unless' on Emacs <30."
(ert-deftest test-org-drill-determine-next-interval-sm5-algorithm-ef-increases-with-quality-5 ()
"Algorithm: quality 5 results in EF >= initial EF on the success path."
(let* ((initial-ef 2.5)
- (result (org-drill-determine-next-interval-sm5 10 3 initial-ef 5 0 nil 0 nil nil))
+ (result (test-scheduler--call-sm5 10 3 initial-ef 5 0 nil 0 nil nil))
(new-ef (test-scheduler--extract-ef result)))
(should (>= new-ef initial-ef))))
(ert-deftest test-org-drill-determine-next-interval-sm5-algorithm-ef-decreases-with-quality-3 ()
"Algorithm: quality 3 results in EF < initial EF on the success path."
(let* ((initial-ef 2.5)
- (result (org-drill-determine-next-interval-sm5 10 3 initial-ef 3 0 nil 0 nil nil))
+ (result (test-scheduler--call-sm5 10 3 initial-ef 3 0 nil 0 nil nil))
(new-ef (test-scheduler--extract-ef result)))
(should (< new-ef initial-ef))))
(ert-deftest test-org-drill-determine-next-interval-sm5-algorithm-interval-grows-over-successive-reviews ()
"Algorithm: successive successful quality-4 reviews produce strictly growing intervals."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result-2 (org-drill-determine-next-interval-sm5 1 2 2.5 4 0 nil 0 nil nil))
+ (let* ((result-2 (test-scheduler--call-sm5 1 2 2.5 4 0 nil 0 nil nil))
(interval-2 (test-scheduler--extract-interval result-2))
(ef-2 (test-scheduler--extract-ef result-2))
(matrix-2 (test-scheduler--extract-of-matrix result-2))
- (result-3 (org-drill-determine-next-interval-sm5 interval-2 3 ef-2 4 0 nil 1 matrix-2 nil))
+ (result-3 (test-scheduler--call-sm5 interval-2 3 ef-2 4 0 nil 1 matrix-2 nil))
(interval-3 (test-scheduler--extract-interval result-3)))
(should (> interval-3 interval-2)))))
(ert-deftest test-org-drill-determine-next-interval-sm5-algorithm-of-matrix-gains-entry ()
"Algorithm: of-matrix gains an entry for n after a successful call, preserving prior entries."
(let* ((input-matrix '((10 (1.0 . 1.0))))
- (result (org-drill-determine-next-interval-sm5 0 1 2.5 4 0 nil 0 input-matrix nil))
+ (result (test-scheduler--call-sm5 0 1 2.5 4 0 nil 0 input-matrix nil))
(output-matrix (test-scheduler--extract-of-matrix result)))
(should (assoc 1 output-matrix)) ; new entry for n=1 was added
(should (assoc 10 output-matrix)))) ; unrelated entry for n=10 preserved
diff --git a/tests/test-org-drill-small-branch-coverage.el b/tests/test-org-drill-small-branch-coverage.el
index 21b67c6..cb0ece7 100644
--- a/tests/test-org-drill-small-branch-coverage.el
+++ b/tests/test-org-drill-small-branch-coverage.el
@@ -21,7 +21,10 @@ the dispersal factor."
(cl-letf (((symbol-function 'org-drill-random-dispersal-factor)
(lambda () 1.5)))
(let* ((result (org-drill-determine-next-interval-sm5
- 4.0 2 2.5 5 0 5.0 1
+ (make-org-drill-card-state
+ :last-interval 4.0 :repetitions 2 :ease 2.5
+ :failures 0 :meanq 5.0 :total-repeats 1)
+ 5
org-drill-sm5-optimal-factor-matrix))
(next (nth 0 result)))
(should (numberp next))
diff --git a/tests/testutil-scheduler.el b/tests/testutil-scheduler.el
index 70204b4..0d28b7a 100644
--- a/tests/testutil-scheduler.el
+++ b/tests/testutil-scheduler.el
@@ -57,5 +57,14 @@ Use this name in Simple8 tests where the field is called `ease' not `ef'."
:failures failures :meanq meanq :total-repeats total-repeats)
quality))
+(defun test-scheduler--call-sm5 (last-interval n ef quality failures meanq
+ total-repeats of-matrix &optional delta-days)
+ "Call the SM5 scheduler from positional args, packing them into a card-state."
+ (org-drill-determine-next-interval-sm5
+ (make-org-drill-card-state
+ :last-interval last-interval :repetitions n :ease ef
+ :failures failures :meanq meanq :total-repeats total-repeats)
+ quality of-matrix delta-days))
+
(provide 'testutil-scheduler)
;;; testutil-scheduler.el ends here