aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--org-drill.el37
-rw-r--r--tests/test-org-drill-determine-next-interval-sm2.el92
-rw-r--r--tests/testutil-scheduler.el14
3 files changed, 75 insertions, 68 deletions
diff --git a/org-drill.el b/org-drill.el
index fd6f24e..7046ade 100644
--- a/org-drill.el
+++ b/org-drill.el
@@ -1232,13 +1232,12 @@ caller passes the scheduler's next-interval there)."
(org-drill-round-float (org-drill-card-state-ease state) 3))))
;;; SM2 Algorithm =============================================================
-(defun org-drill-determine-next-interval-sm2 (last-interval n ef quality
- failures meanq total-repeats)
- "Arguments:
-- LAST-INTERVAL -- the number of days since the item was last reviewed.
-- REPEATS -- the number of times the item has been successfully reviewed
-- EF -- the \\='easiness factor\\='
-- QUALITY -- 0 to 5
+(defun org-drill-determine-next-interval-sm2 (state quality)
+ "Return the SM2 schedule for STATE after a review of recall QUALITY (0-5).
+
+STATE is an `org-drill-card-state' carrying LAST-INTERVAL, REPETITIONS,
+EASE (the \\='easiness factor\\='), FAILURES, MEANQ and TOTAL-REPEATS.
+QUALITY is the rating just entered.
Returns a list:
(INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), where:
@@ -1246,6 +1245,12 @@ Returns a list:
- REPEATS is incremented by 1.
- EF is modified based on the recall quality for the item.
- OF-MATRIX is not modified."
+ (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))
(setq meanq (if meanq
@@ -1282,7 +1287,7 @@ Returns a list:
(1+ n)
next-ef
failures meanq (1+ total-repeats)
- org-drill-sm5-optimal-factor-matrix))))
+ org-drill-sm5-optimal-factor-matrix)))))
;;; SM5 Algorithm =============================================================
(defun org-drill-modify-e-factor (ef quality)
@@ -1520,13 +1525,7 @@ item will be scheduled exactly this many days into the future."
(org-drill-card-state-failures state)
(org-drill-card-state-meanq state)
(org-drill-card-state-total-repeats state) ofmatrix))
- (sm2 (org-drill-determine-next-interval-sm2
- (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)))
+ (sm2 (org-drill-determine-next-interval-sm2 state quality))
(simple8 (org-drill-determine-next-interval-simple8
(org-drill-card-state-last-interval state)
(org-drill-card-state-repetitions state)
@@ -1590,13 +1589,7 @@ of QUALITY."
(org-drill-card-state-meanq state)
(org-drill-card-state-total-repeats state)
org-drill-sm5-optimal-factor-matrix))
- (sm2 (org-drill-determine-next-interval-sm2
- (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)))
+ (sm2 (org-drill-determine-next-interval-sm2 state quality))
(simple8 (org-drill-determine-next-interval-simple8
(org-drill-card-state-last-interval state)
(org-drill-card-state-repetitions state)
diff --git a/tests/test-org-drill-determine-next-interval-sm2.el b/tests/test-org-drill-determine-next-interval-sm2.el
index 8405968..b367f33 100644
--- a/tests/test-org-drill-determine-next-interval-sm2.el
+++ b/tests/test-org-drill-determine-next-interval-sm2.el
@@ -12,7 +12,7 @@
;; - Failure count and statistics
;;
;; Function signature:
-;; (org-drill-determine-next-interval-sm2 last-interval n ef quality
+;; (test-scheduler--call-sm2 last-interval n ef quality
;; failures meanq total-repeats)
;;
;; Returns: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX)
@@ -41,7 +41,7 @@
(ert-deftest test-org-drill-determine-next-interval-sm2-normal-first-review-quality-4 ()
"Test first successful review with quality 4.
First review (n=1) should return interval of 1 day."
- (let* ((result (org-drill-determine-next-interval-sm2 0 1 nil 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 0 1 nil 4 0 nil 0))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(ef (test-scheduler--extract-ef result)))
@@ -53,7 +53,7 @@ First review (n=1) should return interval of 1 day."
"Test second successful review with quality 4.
Second review (n=2) should return interval of 6 days (no random noise)."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 1 2 2.5 4 0 nil 0))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result)))
(should (= interval 6))
@@ -65,7 +65,7 @@ Third review (n=3) uses formula: last-interval * EF."
(let ((org-drill-add-random-noise-to-intervals-p nil))
(let* ((ef 2.5)
(last-interval 6)
- (result (org-drill-determine-next-interval-sm2 last-interval 3 ef 4 0 nil 0))
+ (result (test-scheduler--call-sm2 last-interval 3 ef 4 0 nil 0))
(interval (test-scheduler--extract-interval result))
(new-ef (test-scheduler--extract-ef result)))
;; Interval should be approximately last-interval * new-ef
@@ -76,7 +76,7 @@ Third review (n=3) uses formula: last-interval * EF."
"Test review with perfect recall (quality 5).
Quality 5 should increase EF and result in longer intervals."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 5 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 5 0 nil 0))
(ef (test-scheduler--extract-ef result)))
;; Quality 5 should maintain or increase EF
(should (>= ef 2.5)))))
@@ -85,7 +85,7 @@ Quality 5 should increase EF and result in longer intervals."
"Test review with adequate recall (quality 3).
Quality 3 should maintain relatively stable EF."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 3 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 3 0 nil 0))
(ef (test-scheduler--extract-ef result)))
;; Quality 3 should result in moderate EF
(should (> ef test-sm2-min-ef))
@@ -96,7 +96,7 @@ Quality 3 should maintain relatively stable EF."
(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-0 ()
"Test failed review with quality 0.
Quality 0 (<= org-drill-failure-quality) should reset interval to -1."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 0 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 0 0 nil 0))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(ef (test-scheduler--extract-ef result))
@@ -109,7 +109,7 @@ Quality 0 (<= org-drill-failure-quality) should reset interval to -1."
(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-1 ()
"Test failed review with quality 1.
Quality 1 (<= org-drill-failure-quality) should reset interval."
- (let* ((result (org-drill-determine-next-interval-sm2 15 5 2.6 1 2 3.5 10))
+ (let* ((result (test-scheduler--call-sm2 15 5 2.6 1 2 3.5 10))
(interval (test-scheduler--extract-interval result))
(ef (test-scheduler--extract-ef result))
(failures (test-scheduler--extract-failures result)))
@@ -120,7 +120,7 @@ Quality 1 (<= org-drill-failure-quality) should reset interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-2 ()
"Test failed review with quality 2.
Quality 2 (= org-drill-failure-quality default) should reset interval."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 2 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 2 0 nil 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval -1))))
@@ -128,14 +128,14 @@ Quality 2 (= org-drill-failure-quality default) should reset interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-nil-ef-uses-default ()
"Test that nil EF defaults to 2.5."
- (let* ((result (org-drill-determine-next-interval-sm2 0 1 nil 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 0 1 nil 4 0 nil 0))
(ef (test-scheduler--extract-ef result)))
(should ef) ; EF should be set (modified from default 2.5)
(should (> ef 0))))
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-zero-n-becomes-one ()
"Test that n=0 is treated as n=1."
- (let* ((result (org-drill-determine-next-interval-sm2 0 0 2.5 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 0 0 2.5 4 0 nil 0))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result)))
(should (= interval 1)) ; First review interval
@@ -144,7 +144,7 @@ Quality 2 (= org-drill-failure-quality default) should reset interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-nil-meanq-uses-quality ()
"Test that nil meanq initializes to current quality."
(let* ((quality 4)
- (result (org-drill-determine-next-interval-sm2 0 1 2.5 quality 0 nil 0))
+ (result (test-scheduler--call-sm2 0 1 2.5 quality 0 nil 0))
(meanq (test-scheduler--extract-meanq result)))
(should (= meanq quality))))
@@ -153,13 +153,13 @@ Quality 2 (= org-drill-failure-quality default) should reset interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-quality-5-maximum ()
"Test maximum quality (5) - perfect recall."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 5 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 1 2 2.5 5 0 nil 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval 6))))) ; Second review with quality 5
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-quality-0-minimum ()
"Test minimum quality (0) - complete failure."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 0 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 0 0 nil 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval -1)))) ; Failed review
@@ -167,7 +167,7 @@ Quality 2 (= org-drill-failure-quality default) should reset interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-1 ()
"Test first successful review (n=1) returns interval of 1."
- (let* ((result (org-drill-determine-next-interval-sm2 0 1 2.5 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 0 1 2.5 4 0 nil 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval 1))))
@@ -175,7 +175,7 @@ Quality 2 (= org-drill-failure-quality default) should reset interval."
"Test second review (n=2) with no random noise.
Should return interval of 6 days regardless of quality (if passing)."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 1 2 2.5 4 0 nil 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval 6)))))
@@ -183,9 +183,9 @@ Should return interval of 6 days regardless of quality (if passing)."
"Test second review (n=2) with random noise enabled.
Interval should vary by quality, with quality 5 having highest base interval (6)."
(let ((org-drill-add-random-noise-to-intervals-p t))
- (let* ((result-q5 (org-drill-determine-next-interval-sm2 1 2 2.5 5 0 nil 0))
- (result-q4 (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
- (result-q3 (org-drill-determine-next-interval-sm2 1 2 2.5 3 0 nil 0))
+ (let* ((result-q5 (test-scheduler--call-sm2 1 2 2.5 5 0 nil 0))
+ (result-q4 (test-scheduler--call-sm2 1 2 2.5 4 0 nil 0))
+ (result-q3 (test-scheduler--call-sm2 1 2 2.5 3 0 nil 0))
(interval-q5 (test-scheduler--extract-interval result-q5))
(interval-q4 (test-scheduler--extract-interval result-q4))
(interval-q3 (test-scheduler--extract-interval result-q3)))
@@ -206,7 +206,7 @@ meanq = (quality + meanq * total-repeats) / (total-repeats + 1)"
(let* ((quality 4)
(meanq 3.0)
(total-repeats 10)
- (result (org-drill-determine-next-interval-sm2 10 3 2.5 quality 0 meanq total-repeats))
+ (result (test-scheduler--call-sm2 10 3 2.5 quality 0 meanq total-repeats))
(new-meanq (test-scheduler--extract-meanq result))
(expected-meanq (/ (+ quality (* meanq total-repeats 1.0))
(1+ total-repeats))))
@@ -217,7 +217,7 @@ meanq = (quality + meanq * total-repeats) / (total-repeats + 1)"
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-ef-minimum-floor ()
"Test that EF floor of 1.3 is applied to input EF when it's below 1.3.
If input EF < 1.3, org-drill-modify-e-factor returns 1.3 exactly."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 1.0 4 0 nil 0))
+ (let* ((result (test-scheduler--call-sm2 10 3 1.0 4 0 nil 0))
(ef (test-scheduler--extract-ef result)))
;; Input EF was 1.0 < 1.3, so it should be raised to 1.3 first,
;; then modified based on quality 4 (which increases EF)
@@ -228,7 +228,7 @@ If input EF < 1.3, org-drill-modify-e-factor returns 1.3 exactly."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-total-repeats-increments ()
"Test that total-repeats is always incremented by 1."
(let* ((total-repeats 42)
- (result (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 3.5 total-repeats))
+ (result (test-scheduler--call-sm2 10 3 2.5 4 0 3.5 total-repeats))
(new-total (test-scheduler--extract-total-repeats result)))
(should (= new-total (1+ total-repeats)))))
@@ -237,7 +237,7 @@ If input EF < 1.3, org-drill-modify-e-factor returns 1.3 exactly."
(ert-deftest test-org-drill-determine-next-interval-sm2-normal-return-value-structure ()
"Test that return value has correct structure.
Should return 7-element list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX)"
- (let ((result (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 3.5 10)))
+ (let ((result (test-scheduler--call-sm2 10 3 2.5 4 0 3.5 10)))
(should (listp result))
(should (= (length result) 7))
;; Verify first 6 elements are numbers
@@ -257,7 +257,7 @@ Should return 7-element list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS O
"Test that higher quality results in higher EF (or maintains it).
Quality 5 should result in EF >= initial EF."
(let* ((initial-ef 2.5)
- (result (org-drill-determine-next-interval-sm2 10 3 initial-ef 5 0 nil 0))
+ (result (test-scheduler--call-sm2 10 3 initial-ef 5 0 nil 0))
(new-ef (test-scheduler--extract-ef result)))
(should (>= new-ef initial-ef))))
@@ -265,7 +265,7 @@ Quality 5 should result in EF >= initial EF."
"Test that low quality results in decreased EF.
Quality 3 should result in EF < initial EF."
(let* ((initial-ef 2.5)
- (result (org-drill-determine-next-interval-sm2 10 3 initial-ef 3 0 nil 0))
+ (result (test-scheduler--call-sm2 10 3 initial-ef 3 0 nil 0))
(new-ef (test-scheduler--extract-ef result)))
(should (< new-ef initial-ef))))
@@ -274,10 +274,10 @@ Quality 3 should result in EF < initial EF."
Third review interval should be significantly larger than second."
(let ((org-drill-add-random-noise-to-intervals-p nil))
(let* ((ef 2.5)
- (result-2nd (org-drill-determine-next-interval-sm2 1 2 ef 4 0 nil 0))
+ (result-2nd (test-scheduler--call-sm2 1 2 ef 4 0 nil 0))
(interval-2nd (test-scheduler--extract-interval result-2nd))
(ef-2nd (test-scheduler--extract-ef result-2nd))
- (result-3rd (org-drill-determine-next-interval-sm2 interval-2nd 3 ef-2nd 4 0 nil 1))
+ (result-3rd (test-scheduler--call-sm2 interval-2nd 3 ef-2nd 4 0 nil 1))
(interval-3rd (test-scheduler--extract-interval result-3rd)))
(should (> interval-3rd (* interval-2nd 1.5)))))) ; Significant growth
@@ -287,7 +287,7 @@ Third review interval should be significantly larger than second."
"Test SM2 with very high repeat count (1000 reviews).
Algorithm should remain stable with extreme n values."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 365 1000 2.5 4 0 4.0 1000))
+ (let* ((result (test-scheduler--call-sm2 365 1000 2.5 4 0 4.0 1000))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(ef (test-scheduler--extract-ef result)))
@@ -300,7 +300,7 @@ Algorithm should remain stable with extreme n values."
"Test SM2 with very long last interval (10 years = 3650 days).
Algorithm should handle extreme intervals without overflow."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result (org-drill-determine-next-interval-sm2 3650 100 2.5 4 0 4.0 100))
+ (let* ((result (test-scheduler--call-sm2 3650 100 2.5 4 0 4.0 100))
(interval (test-scheduler--extract-interval result)))
(should (numberp interval))
(should (> interval 0)))))
@@ -309,7 +309,7 @@ Algorithm should handle extreme intervals without overflow."
"Test SM2 with very high failure count (100+ failures).
Failure count should be tracked correctly even at extreme values."
(let* ((failures 100)
- (result (org-drill-determine-next-interval-sm2 10 3 2.5 0 failures 3.0 150))
+ (result (test-scheduler--call-sm2 10 3 2.5 0 failures 3.0 150))
(new-failures (test-scheduler--extract-failures result)))
(should (= new-failures (1+ failures)))))
@@ -317,21 +317,21 @@ Failure count should be tracked correctly even at extreme values."
"Test SM2 with very high total-repeats (10000+).
Total repeats should increment correctly even at extreme values."
(let* ((total-repeats 10000)
- (result (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 4.0 total-repeats))
+ (result (test-scheduler--call-sm2 10 3 2.5 4 0 4.0 total-repeats))
(new-total (test-scheduler--extract-total-repeats result)))
(should (= new-total (1+ total-repeats)))))
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-ef-just-above-floor ()
"Test SM2 with EF just above minimum floor (1.31).
EF should be maintained or modified normally, not clamped."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 1.31 4 0 4.0 10))
+ (let* ((result (test-scheduler--call-sm2 10 3 1.31 4 0 4.0 10))
(ef (test-scheduler--extract-ef result)))
(should (>= ef test-sm2-min-ef))))
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-ef-at-floor ()
"Test SM2 with EF exactly at minimum floor (1.3).
EF at floor with quality 4 should increase slightly."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 1.3 4 0 4.0 10))
+ (let* ((result (test-scheduler--call-sm2 10 3 1.3 4 0 4.0 10))
(ef (test-scheduler--extract-ef result)))
(should (>= ef test-sm2-min-ef))))
@@ -340,7 +340,7 @@ EF at floor with quality 4 should increase slightly."
Perfect recall should not reset failures, but should calculate normal interval."
(let ((org-drill-add-random-noise-to-intervals-p nil))
(let* ((failures 50)
- (result (org-drill-determine-next-interval-sm2 10 3 2.5 5 failures 3.0 100))
+ (result (test-scheduler--call-sm2 10 3 2.5 5 failures 3.0 100))
(interval (test-scheduler--extract-interval result))
(new-failures (test-scheduler--extract-failures result)))
(should (> interval 0))
@@ -349,7 +349,7 @@ Perfect recall should not reset failures, but should calculate normal interval."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-failure-after-long-streak ()
"Test complete failure (quality 0) after long successful streak.
Failure should reset interval to -1 regardless of previous success."
- (let* ((result (org-drill-determine-next-interval-sm2 365 100 2.8 0 0 4.5 100))
+ (let* ((result (test-scheduler--call-sm2 365 100 2.8 0 0 4.5 100))
(interval (test-scheduler--extract-interval result))
(repeats (test-scheduler--extract-repeats result))
(failures (test-scheduler--extract-failures result)))
@@ -360,7 +360,7 @@ Failure should reset interval to -1 regardless of previous success."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-meanq-at-maximum ()
"Test SM2 with meanq at maximum (5.0).
High quality review with already-perfect meanq."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 5 0 5.0 100))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 5 0 5.0 100))
(meanq (test-scheduler--extract-meanq result)))
(should (<= meanq 5.0))
(should (>= meanq 4.5)))) ; Should remain very high
@@ -368,7 +368,7 @@ High quality review with already-perfect meanq."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-meanq-at-minimum ()
"Test SM2 with meanq at minimum (0.0).
Low quality history with poor current recall."
- (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 3 5 0.0 100))
+ (let* ((result (test-scheduler--call-sm2 10 3 2.5 3 5 0.0 100))
(meanq (test-scheduler--extract-meanq result)))
(should (>= meanq 0.0))
(should (<= meanq 1.0)))) ; Should remain low with quality 3
@@ -378,7 +378,7 @@ Low quality history with poor current recall."
Indicates item reviewed many times but poorly recalled."
(let* ((total-repeats 1000)
(meanq 2.0)
- (result (org-drill-determine-next-interval-sm2 5 10 1.5 3 20 meanq total-repeats))
+ (result (test-scheduler--call-sm2 5 10 1.5 3 20 meanq total-repeats))
(new-meanq (test-scheduler--extract-meanq result)))
(should (numberp new-meanq))
;; meanq should remain low given poor history
@@ -387,7 +387,7 @@ Indicates item reviewed many times but poorly recalled."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-zero-last-interval ()
"Test SM2 with zero last-interval.
Should handle as first review (n=1 case)."
- (let* ((result (org-drill-determine-next-interval-sm2 0 1 2.5 4 0 4.0 0))
+ (let* ((result (test-scheduler--call-sm2 0 1 2.5 4 0 4.0 0))
(interval (test-scheduler--extract-interval result)))
(should (= interval 1))))
@@ -395,8 +395,8 @@ Should handle as first review (n=1 case)."
"Test SM2 with float last-interval vs integer.
Algorithm should handle both correctly."
(let ((org-drill-add-random-noise-to-intervals-p nil))
- (let* ((result-float (org-drill-determine-next-interval-sm2 10.5 3 2.5 4 0 4.0 10))
- (result-int (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 4.0 10))
+ (let* ((result-float (test-scheduler--call-sm2 10.5 3 2.5 4 0 4.0 10))
+ (result-int (test-scheduler--call-sm2 10 3 2.5 4 0 4.0 10))
(interval-float (test-scheduler--extract-interval result-float))
(interval-int (test-scheduler--extract-interval result-int)))
(should (numberp interval-float))
@@ -408,9 +408,9 @@ Algorithm should handle both correctly."
(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-alternating-quality-pattern ()
"Test SM2 behavior with alternating quality (5, 0, 5, 0 pattern).
Simulates inconsistent learning."
- (let* ((result-1 (org-drill-determine-next-interval-sm2 1 2 2.5 5 0 5.0 1))
+ (let* ((result-1 (test-scheduler--call-sm2 1 2 2.5 5 0 5.0 1))
(ef-1 (test-scheduler--extract-ef result-1))
- (result-2 (org-drill-determine-next-interval-sm2 6 3 ef-1 0 0 4.5 2))
+ (result-2 (test-scheduler--call-sm2 6 3 ef-1 0 0 4.5 2))
(interval-2 (test-scheduler--extract-interval result-2))
(failures-2 (test-scheduler--extract-failures result-2)))
;; After perfect then fail, should reset interval
@@ -442,18 +442,18 @@ quirk drops into a blocking debugger in batch mode, so a bare
(ert-deftest test-org-drill-determine-next-interval-sm2-error-quality-above-max ()
"Quality above the 0-5 range trips the quality assertion."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm2 1 2 2.5 6 0 4.0 1)))
+ (test-scheduler--call-sm2 1 2 2.5 6 0 4.0 1)))
(ert-deftest test-org-drill-determine-next-interval-sm2-error-quality-below-min ()
"Quality below the 0-5 range trips the quality assertion."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm2 1 2 2.5 -1 0 4.0 1)))
+ (test-scheduler--call-sm2 1 2 2.5 -1 0 4.0 1)))
(ert-deftest test-org-drill-determine-next-interval-sm2-error-negative-n ()
"A negative repeat count trips the (> n 0) assertion. Note n=0 is
normalized to 1 before the assert, so zero is not an error case."
(test-scheduler--should-cl-assert
- (org-drill-determine-next-interval-sm2 1 -1 2.5 4 0 4.0 1)))
+ (test-scheduler--call-sm2 1 -1 2.5 4 0 4.0 1)))
(provide 'test-org-drill-determine-next-interval-sm2)
;;; test-org-drill-determine-next-interval-sm2.el ends here
diff --git a/tests/testutil-scheduler.el b/tests/testutil-scheduler.el
index 72811e8..70204b4 100644
--- a/tests/testutil-scheduler.el
+++ b/tests/testutil-scheduler.el
@@ -43,5 +43,19 @@ Use this name in Simple8 tests where the field is called `ease' not `ef'."
"Extract the optimal-factor matrix (position 6) from an SM5 RESULT list."
(nth 6 result))
+;;;; Call adapters
+;; The schedulers now take an `org-drill-card-state' plus QUALITY rather than a
+;; long positional list (org-drill #147). These adapters pack the positional
+;; args into the struct so the test call sites keep reading as the documented
+;; algorithm inputs, making each migration a one-symbol rename at the call.
+
+(defun test-scheduler--call-sm2 (last-interval n ef quality failures meanq total-repeats)
+ "Call the SM2 scheduler from positional args, packing them into a card-state."
+ (org-drill-determine-next-interval-sm2
+ (make-org-drill-card-state
+ :last-interval last-interval :repetitions n :ease ef
+ :failures failures :meanq meanq :total-repeats total-repeats)
+ quality))
+
(provide 'testutil-scheduler)
;;; testutil-scheduler.el ends here