diff options
| -rw-r--r-- | tests/test-org-drill-determine-next-interval-sm2.el | 148 | ||||
| -rw-r--r-- | tests/test-org-drill-determine-next-interval-sm5.el | 118 | ||||
| -rw-r--r-- | tests/testutil-scheduler.el | 47 |
3 files changed, 156 insertions, 157 deletions
diff --git a/tests/test-org-drill-determine-next-interval-sm2.el b/tests/test-org-drill-determine-next-interval-sm2.el index a895ccd..622744d 100644 --- a/tests/test-org-drill-determine-next-interval-sm2.el +++ b/tests/test-org-drill-determine-next-interval-sm2.el @@ -23,6 +23,10 @@ (require 'assess) (require 'org-drill) +(add-to-list 'load-path + (file-name-directory (or load-file-name buffer-file-name))) +(require 'testutil-scheduler) + ;;; Test Data and Constants ;; Default SM2 parameters @@ -32,41 +36,15 @@ (defconst test-sm2-min-ef 1.3 "Minimum easiness factor (SM2 floor).") -;;; Helper Functions - -(defun test-sm2--extract-interval (result) - "Extract interval from SM2 result list." - (nth 0 result)) - -(defun test-sm2--extract-repeats (result) - "Extract repeats from SM2 result list." - (nth 1 result)) - -(defun test-sm2--extract-ef (result) - "Extract easiness factor from SM2 result list." - (nth 2 result)) - -(defun test-sm2--extract-failures (result) - "Extract failures from SM2 result list." - (nth 3 result)) - -(defun test-sm2--extract-meanq (result) - "Extract mean quality from SM2 result list." - (nth 4 result)) - -(defun test-sm2--extract-total-repeats (result) - "Extract total repeats from SM2 result list." - (nth 5 result)) - ;;; Normal Cases - Successful Reviews (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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result)) - (ef (test-sm2--extract-ef result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (ef (test-scheduler--extract-ef result))) (should (= interval 1)) (should (= repeats 2)) (should ef))) ; EF should be calculated @@ -76,8 +54,8 @@ First review (n=1) should return interval of 1 day." 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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result))) (should (= interval 6)) (should (= repeats 3))))) @@ -88,18 +66,18 @@ Third review (n=3) uses formula: last-interval * EF." (let* ((ef 2.5) (last-interval 6) (result (org-drill-determine-next-interval-sm2 last-interval 3 ef 4 0 nil 0)) - (interval (test-sm2--extract-interval result)) - (new-ef (test-sm2--extract-ef result))) + (interval (test-scheduler--extract-interval result)) + (new-ef (test-scheduler--extract-ef result))) ;; Interval should be approximately last-interval * new-ef (should (> interval last-interval)) - (should (= (test-sm2--extract-repeats result) 4))))) + (should (= (test-scheduler--extract-repeats result) 4))))) (ert-deftest test-org-drill-determine-next-interval-sm2-normal-quality-5-perfect-recall () "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)) - (ef (test-sm2--extract-ef result))) + (ef (test-scheduler--extract-ef result))) ;; Quality 5 should maintain or increase EF (should (>= ef 2.5))))) @@ -108,7 +86,7 @@ Quality 5 should increase EF and result in longer intervals." 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)) - (ef (test-sm2--extract-ef result))) + (ef (test-scheduler--extract-ef result))) ;; Quality 3 should result in moderate EF (should (> ef test-sm2-min-ef)) (should (< ef 2.5))))) ; EF likely decreases slightly @@ -119,10 +97,10 @@ Quality 3 should maintain relatively stable EF." "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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result)) - (ef (test-sm2--extract-ef result)) - (failures (test-sm2--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (ef (test-scheduler--extract-ef result)) + (failures (test-scheduler--extract-failures result))) (should (= interval -1)) (should (= repeats 1)) ; Reset to 1 (should (= ef 2.5)) ; EF unchanged on failure @@ -132,9 +110,9 @@ Quality 0 (<= org-drill-failure-quality) should reset interval to -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)) - (interval (test-sm2--extract-interval result)) - (ef (test-sm2--extract-ef result)) - (failures (test-sm2--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (ef (test-scheduler--extract-ef result)) + (failures (test-scheduler--extract-failures result))) (should (= interval -1)) (should (= ef 2.6)) ; EF unchanged (should (= failures 3)))) ; Previous failures + 1 @@ -143,7 +121,7 @@ Quality 1 (<= org-drill-failure-quality) should reset interval." "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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval -1)))) ;;; Boundary Cases - Default Values @@ -151,15 +129,15 @@ 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)) - (ef (test-sm2--extract-ef result))) + (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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result))) (should (= interval 1)) ; First review interval (should (= repeats 2)))) ; n incremented from 1 to 2 @@ -167,7 +145,7 @@ Quality 2 (= org-drill-failure-quality default) should reset interval." "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)) - (meanq (test-sm2--extract-meanq result))) + (meanq (test-scheduler--extract-meanq result))) (should (= meanq quality)))) ;;; Boundary Cases - Quality Extremes @@ -176,13 +154,13 @@ Quality 2 (= org-drill-failure-quality default) should reset interval." "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)) - (interval (test-sm2--extract-interval result))) + (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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval -1)))) ; Failed review ;;; Boundary Cases - Repeat Count @@ -190,7 +168,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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval 1)))) (ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-2-no-noise () @@ -198,7 +176,7 @@ Quality 2 (= org-drill-failure-quality default) should reset interval." 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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval 6))))) (ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-2-with-noise () @@ -208,9 +186,9 @@ Interval should vary by quality, with quality 5 having highest base interval (6) (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)) - (interval-q5 (test-sm2--extract-interval result-q5)) - (interval-q4 (test-sm2--extract-interval result-q4)) - (interval-q3 (test-sm2--extract-interval result-q3))) + (interval-q5 (test-scheduler--extract-interval result-q5)) + (interval-q4 (test-scheduler--extract-interval result-q4)) + (interval-q3 (test-scheduler--extract-interval result-q3))) ;; Base intervals before noise are: Q5=6, Q4=4, Q3=3 ;; After random noise, verify intervals are positive and roughly in expected ranges (should (> interval-q5 0)) @@ -229,7 +207,7 @@ meanq = (quality + meanq * total-repeats) / (total-repeats + 1)" (meanq 3.0) (total-repeats 10) (result (org-drill-determine-next-interval-sm2 10 3 2.5 quality 0 meanq total-repeats)) - (new-meanq (test-sm2--extract-meanq result)) + (new-meanq (test-scheduler--extract-meanq result)) (expected-meanq (/ (+ quality (* meanq total-repeats 1.0)) (1+ total-repeats)))) (should (< (abs (- new-meanq expected-meanq)) 0.0001)))) ; Floating point comparison @@ -240,7 +218,7 @@ meanq = (quality + meanq * total-repeats) / (total-repeats + 1)" "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)) - (ef (test-sm2--extract-ef result))) + (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) (should (>= ef 1.3)))) @@ -251,7 +229,7 @@ If input EF < 1.3, org-drill-modify-e-factor returns 1.3 exactly." "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)) - (new-total (test-sm2--extract-total-repeats result))) + (new-total (test-scheduler--extract-total-repeats result))) (should (= new-total (1+ total-repeats))))) ;;; Return Value Structure @@ -280,7 +258,7 @@ Should return 7-element list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS O 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)) - (new-ef (test-sm2--extract-ef result))) + (new-ef (test-scheduler--extract-ef result))) (should (>= new-ef initial-ef)))) (ert-deftest test-org-drill-determine-next-interval-sm2-algorithm-ef-decreases-with-low-quality () @@ -288,7 +266,7 @@ Quality 5 should result in EF >= initial 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)) - (new-ef (test-sm2--extract-ef result))) + (new-ef (test-scheduler--extract-ef result))) (should (< new-ef initial-ef)))) (ert-deftest test-org-drill-determine-next-interval-sm2-algorithm-interval-grows-exponentially () @@ -297,10 +275,10 @@ 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)) - (interval-2nd (test-sm2--extract-interval result-2nd)) - (ef-2nd (test-sm2--extract-ef result-2nd)) + (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)) - (interval-3rd (test-sm2--extract-interval result-3rd))) + (interval-3rd (test-scheduler--extract-interval result-3rd))) (should (> interval-3rd (* interval-2nd 1.5)))))) ; Significant growth ;;; Aggressive Boundary Cases @@ -310,9 +288,9 @@ Third review interval should be significantly larger than second." 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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result)) - (ef (test-sm2--extract-ef result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (ef (test-scheduler--extract-ef result))) (should (numberp interval)) (should (> interval 0)) (should (= repeats 1001)) @@ -323,7 +301,7 @@ Algorithm should remain stable with extreme n values." 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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (numberp interval)) (should (> interval 0))))) @@ -332,7 +310,7 @@ Algorithm should handle extreme intervals without overflow." 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)) - (new-failures (test-sm2--extract-failures result))) + (new-failures (test-scheduler--extract-failures result))) (should (= new-failures (1+ failures))))) (ert-deftest test-org-drill-determine-next-interval-sm2-boundary-very-high-total-repeats () @@ -340,21 +318,21 @@ Failure count should be tracked correctly even at extreme values." 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)) - (new-total (test-sm2--extract-total-repeats result))) + (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)) - (ef (test-sm2--extract-ef result))) + (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)) - (ef (test-sm2--extract-ef result))) + (ef (test-scheduler--extract-ef result))) (should (>= ef test-sm2-min-ef)))) (ert-deftest test-org-drill-determine-next-interval-sm2-boundary-perfect-recall-after-many-failures () @@ -363,8 +341,8 @@ 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)) - (interval (test-sm2--extract-interval result)) - (new-failures (test-sm2--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (new-failures (test-scheduler--extract-failures result))) (should (> interval 0)) (should (= new-failures failures))))) ; Failures unchanged on success @@ -372,9 +350,9 @@ Perfect recall should not reset failures, but should calculate normal interval." "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)) - (interval (test-sm2--extract-interval result)) - (repeats (test-sm2--extract-repeats result)) - (failures (test-sm2--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (failures (test-scheduler--extract-failures result))) (should (= interval -1)) (should (= repeats 1)) ; Reset to 1 (should (= failures 1)))) @@ -383,7 +361,7 @@ Failure should reset interval to -1 regardless of previous success." "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)) - (meanq (test-sm2--extract-meanq result))) + (meanq (test-scheduler--extract-meanq result))) (should (<= meanq 5.0)) (should (>= meanq 4.5)))) ; Should remain very high @@ -391,7 +369,7 @@ High quality review with already-perfect meanq." "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)) - (meanq (test-sm2--extract-meanq result))) + (meanq (test-scheduler--extract-meanq result))) (should (>= meanq 0.0)) (should (<= meanq 1.0)))) ; Should remain low with quality 3 @@ -401,7 +379,7 @@ 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)) - (new-meanq (test-sm2--extract-meanq result))) + (new-meanq (test-scheduler--extract-meanq result))) (should (numberp new-meanq)) ;; meanq should remain low given poor history (should (< new-meanq 3.0)))) @@ -410,7 +388,7 @@ Indicates item reviewed many times but poorly recalled." "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)) - (interval (test-sm2--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval 1)))) (ert-deftest test-org-drill-determine-next-interval-sm2-boundary-float-vs-int-intervals () @@ -419,8 +397,8 @@ 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)) - (interval-float (test-sm2--extract-interval result-float)) - (interval-int (test-sm2--extract-interval result-int))) + (interval-float (test-scheduler--extract-interval result-float)) + (interval-int (test-scheduler--extract-interval result-int))) (should (numberp interval-float)) (should (numberp interval-int)) ;; Both should produce reasonable intervals @@ -431,10 +409,10 @@ Algorithm should handle both correctly." "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)) - (ef-1 (test-sm2--extract-ef result-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)) - (interval-2 (test-sm2--extract-interval result-2)) - (failures-2 (test-sm2--extract-failures result-2))) + (interval-2 (test-scheduler--extract-interval result-2)) + (failures-2 (test-scheduler--extract-failures result-2))) ;; After perfect then fail, should reset interval (should (= interval-2 -1)) (should (= failures-2 1)))) diff --git a/tests/test-org-drill-determine-next-interval-sm5.el b/tests/test-org-drill-determine-next-interval-sm5.el index dc64c7d..4e4cb7e 100644 --- a/tests/test-org-drill-determine-next-interval-sm5.el +++ b/tests/test-org-drill-determine-next-interval-sm5.el @@ -24,6 +24,10 @@ (require 'assess) (require 'org-drill) +(add-to-list 'load-path + (file-name-directory (or load-file-name buffer-file-name))) +(require 'testutil-scheduler) + ;;; Test Data and Constants (defconst test-sm5-default-ef 2.5 @@ -33,45 +37,15 @@ "Minimum easiness factor. The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") -;;; Helper Functions - -(defun test-sm5--extract-interval (result) - "Extract interval from SM5 result list." - (nth 0 result)) - -(defun test-sm5--extract-repeats (result) - "Extract repeats from SM5 result list." - (nth 1 result)) - -(defun test-sm5--extract-ef (result) - "Extract easiness factor from SM5 result list." - (nth 2 result)) - -(defun test-sm5--extract-failures (result) - "Extract failures from SM5 result list." - (nth 3 result)) - -(defun test-sm5--extract-meanq (result) - "Extract mean quality from SM5 result list." - (nth 4 result)) - -(defun test-sm5--extract-total-repeats (result) - "Extract total repeats from SM5 result list." - (nth 5 result)) - -(defun test-sm5--extract-of-matrix (result) - "Extract optimal-factor matrix from SM5 result list." - (nth 6 result)) - ;;; Normal Cases - Successful Reviews (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)) - (interval (test-sm5--extract-interval result)) - (repeats (test-sm5--extract-repeats result)) - (ef (test-sm5--extract-ef result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (ef (test-scheduler--extract-ef result))) (should (> interval 0)) (should (= repeats 2)) (should ef)))) @@ -80,8 +54,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (interval (test-sm5--extract-interval result)) - (repeats (test-sm5--extract-repeats result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result))) (should (> interval 0)) (should (= repeats 3))))) @@ -89,8 +63,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (interval (test-sm5--extract-interval result)) - (repeats (test-sm5--extract-repeats result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result))) (should (> interval 0)) (should (= repeats 4))))) @@ -98,24 +72,24 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (ef (test-sm5--extract-ef result))) + (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)) - (ef (test-sm5--extract-ef result))) + (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)) - (interval (test-sm5--extract-interval result)) - (repeats (test-sm5--extract-repeats result)) - (ef (test-sm5--extract-ef result)) - (failures (test-sm5--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (repeats (test-scheduler--extract-repeats result)) + (ef (test-scheduler--extract-ef result)) + (failures (test-scheduler--extract-failures result))) (should (= interval -1)) (should (= repeats 1)) (should (= ef 2.5)) @@ -124,9 +98,9 @@ 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)) - (interval (test-sm5--extract-interval result)) - (ef (test-sm5--extract-ef result)) - (failures (test-sm5--extract-failures result))) + (interval (test-scheduler--extract-interval result)) + (ef (test-scheduler--extract-ef result)) + (failures (test-scheduler--extract-failures result))) (should (= interval -1)) (should (= ef 2.6)) (should (= failures 3)))) @@ -134,14 +108,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)) - (interval (test-sm5--extract-interval result))) + (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)) - (returned-ef (test-sm5--extract-ef result))) + (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. (should (= returned-ef input-ef)))) @@ -151,7 +125,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)) - (ef (test-sm5--extract-ef result))) + (ef (test-scheduler--extract-ef result))) (should ef) (should (> ef 0)))) @@ -159,27 +133,27 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (repeats (test-sm5--extract-repeats result))) + (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)) - (meanq (test-sm5--extract-meanq result))) + (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)) - (interval (test-sm5--extract-interval result))) + (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)) - (interval (test-sm5--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (= interval -1)))) (ert-deftest test-org-drill-determine-next-interval-sm5-boundary-meanq-weighted-average () @@ -188,7 +162,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") (meanq 3.0) (total-repeats 10) (result (org-drill-determine-next-interval-sm5 10 3 2.5 quality 0 meanq total-repeats nil nil)) - (new-meanq (test-sm5--extract-meanq result)) + (new-meanq (test-scheduler--extract-meanq result)) (expected (/ (+ quality (* meanq total-repeats 1.0)) (1+ total-repeats)))) (should (< (abs (- new-meanq expected)) 0.0001)))) @@ -197,14 +171,14 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (ef (test-sm5--extract-ef result))) + (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)) - (ef (test-sm5--extract-ef result))) + (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 () @@ -212,13 +186,13 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") (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))) - (should (= (test-sm5--extract-total-repeats result-success) (1+ total-repeats))) - (should (= (test-sm5--extract-total-repeats result-failure) (1+ total-repeats))))) + (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)) - (matrix (test-sm5--extract-of-matrix result))) + (matrix (test-scheduler--extract-of-matrix result))) (should (listp matrix)))) (ert-deftest test-org-drill-determine-next-interval-sm5-boundary-input-matrix-not-mutated () @@ -235,7 +209,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (interval (test-sm5--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (numberp interval)) (should (> interval 0))))) @@ -245,8 +219,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") (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)) - (interval-late (test-sm5--extract-interval result-late)) - (interval-no-delta (test-sm5--extract-interval result-no-delta))) + (interval-late (test-scheduler--extract-interval result-late)) + (interval-no-delta (test-scheduler--extract-interval result-no-delta))) (should (= interval-late interval-no-delta))))) (ert-deftest test-org-drill-determine-next-interval-sm5-boundary-delta-days-negative-flag-disabled () @@ -255,8 +229,8 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") (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)) - (interval-no-adjust (test-sm5--extract-interval result-no-adjust)) - (interval-no-delta (test-sm5--extract-interval result-no-delta))) + (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))))) (ert-deftest test-org-drill-determine-next-interval-sm5-boundary-delta-days-negative-flag-enabled () @@ -264,7 +238,7 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") (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)) - (interval (test-sm5--extract-interval result))) + (interval (test-scheduler--extract-interval result))) (should (numberp interval)) (should (> interval 0))))) @@ -304,32 +278,32 @@ The SM5 floor is shared with SM2 via `org-drill-modify-e-factor'.") "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)) - (new-ef (test-sm5--extract-ef result))) + (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)) - (new-ef (test-sm5--extract-ef result))) + (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)) - (interval-2 (test-sm5--extract-interval result-2)) - (ef-2 (test-sm5--extract-ef result-2)) - (matrix-2 (test-sm5--extract-of-matrix result-2)) + (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)) - (interval-3 (test-sm5--extract-interval result-3))) + (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)) - (output-matrix (test-sm5--extract-of-matrix result))) + (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/testutil-scheduler.el b/tests/testutil-scheduler.el new file mode 100644 index 0000000..72811e8 --- /dev/null +++ b/tests/testutil-scheduler.el @@ -0,0 +1,47 @@ +;;; testutil-scheduler.el --- Shared extractors for scheduler tests -*- lexical-binding: t; -*- + +;;; Commentary: +;; Common result-list element extractors used by the SM2, SM5, and Simple8 +;; scheduler test files. Each algorithm's result list shares the same layout +;; for INTERVAL / REPEATS / FAILURES / MEAN / TOTAL-REPEATS. Position 2 holds +;; either the EF (SM2, SM5) or the EASE (Simple8); both names are exposed as +;; aliases pointing at the same `nth' position so each call site reads +;; accurately. + +;;; Code: + +(defsubst test-scheduler--extract-interval (result) + "Extract the next-interval (position 0) from a scheduler RESULT list." + (nth 0 result)) + +(defsubst test-scheduler--extract-repeats (result) + "Extract the repeats count (position 1) from a scheduler RESULT list." + (nth 1 result)) + +(defsubst test-scheduler--extract-ef (result) + "Extract the easiness factor (position 2) from an SM2 or SM5 RESULT list." + (nth 2 result)) + +(defsubst test-scheduler--extract-ease (result) + "Alias for `test-scheduler--extract-ef' (same `nth' position). +Use this name in Simple8 tests where the field is called `ease' not `ef'." + (nth 2 result)) + +(defsubst test-scheduler--extract-failures (result) + "Extract the failure count (position 3) from a scheduler RESULT list." + (nth 3 result)) + +(defsubst test-scheduler--extract-meanq (result) + "Extract the mean quality (position 4) from a scheduler RESULT list." + (nth 4 result)) + +(defsubst test-scheduler--extract-total-repeats (result) + "Extract the total repeats count (position 5) from a scheduler RESULT list." + (nth 5 result)) + +(defsubst test-scheduler--extract-of-matrix (result) + "Extract the optimal-factor matrix (position 6) from an SM5 RESULT list." + (nth 6 result)) + +(provide 'testutil-scheduler) +;;; testutil-scheduler.el ends here |
