blob: a4492d5afd6d85b50da977b094d087ba1e063a40 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
;;; test-org-drill-statistics-shell.el --- Tests for shell statistics -*- lexical-binding: t; -*-
;;; Commentary:
;; ERT tests for the org-drill statistics dashboard shell block.
;;; Code:
(require 'ert)
(require 'org-drill)
(require 'cl-lib)
(require 'org)
;;; Tests for the statistics dashboard shell (step 2).
(defun org-drill-statistics-test--record (start-offset-days algorithm qualities)
"Build a session record START-OFFSET-DAYS before now.
ALGORITHM is the algorithm symbol. QUALITIES is a vector of int. The
session lasts ten minutes. Offsets are relative to `current-time' so the
fixture never hardcodes a date."
(let* ((start (- (float-time) (* start-offset-days 86400.0)))
(end (+ start 600.0)))
(make-org-drill-session-record
:start-time start
:end-time end
:scope 'file
:algorithm algorithm
:qualities qualities
:pass-percent 50
:new-count 1
:mature-count 2
:failed-count 0
:cram-mode nil)))
(ert-deftest test-org-drill-statistics-shell-range-cutoff-known-label ()
"A range preset with a day count yields a cutoff that many days back."
(let ((now (float-time)))
(let ((cutoff (org-drill-statistics--range-cutoff-float "last 7d")))
(should cutoff)
;; Cutoff is roughly seven days before now, within a generous slop.
(should (< (abs (- cutoff (- now (* 7 86400.0)))) 5.0)))))
(ert-deftest test-org-drill-statistics-shell-range-cutoff-all-time-nil ()
"The all-time preset (nil days) yields no cutoff."
(should (null (org-drill-statistics--range-cutoff-float "all time")))
(should (null (org-drill-statistics--range-cutoff-float "no such label"))))
(ert-deftest test-org-drill-statistics-shell-filtered-log-by-algorithm ()
"Filtering the log by algorithm keeps only matching records."
(let ((org-drill-session-log
(list (org-drill-statistics-test--record 1 'simple8 [4 5])
(org-drill-statistics-test--record 2 'sm5 [3 2]))))
(let ((only-sm5 (org-drill-statistics--filtered-log "all time" 'sm5)))
(should (= 1 (length only-sm5)))
(should (eq 'sm5 (org-drill-session-record-algorithm
(car only-sm5)))))
(should (= 2 (length (org-drill-statistics--filtered-log
"all time" nil))))))
(ert-deftest test-org-drill-statistics-shell-filtered-log-by-range ()
"An old record falls outside a short range window."
(let ((org-drill-session-log
(list (org-drill-statistics-test--record 1 'simple8 [4])
(org-drill-statistics-test--record 40 'simple8 [3]))))
(should (= 1 (length (org-drill-statistics--filtered-log
"last 7d" nil))))
(should (= 2 (length (org-drill-statistics--filtered-log
"last 90d" nil))))))
(ert-deftest test-org-drill-statistics-shell-header-line-format ()
"The header line names all three active filters."
(let ((line (org-drill-statistics--header-line 'file "last 90d" 'simple8)))
(should (string-match-p "Scope: file" line))
(should (string-match-p "Range: last 90d" line))
(should (string-match-p "Algorithm: simple8" line)))
;; nil scope falls back to org-drill-scope, nil algorithm reads "all".
(let* ((org-drill-scope 'directory)
(line (org-drill-statistics--header-line nil "last 7d" nil)))
(should (string-match-p "Scope: directory" line))
(should (string-match-p "Algorithm: all" line))))
(ert-deftest test-org-drill-statistics-shell-cycle-range-wraps ()
"Cycling range advances through presets and wraps to the first."
(with-temp-buffer
(let ((org-drill-statistics-range-presets
'(("last 90d" . 90) ("last 30d" . 30) ("all time" . nil)))
;; Stub the in-place re-render so the cycle command stays pure
;; with respect to buffer contents and the renderers.
(org-drill-session-log nil))
(cl-letf (((symbol-function 'org-drill-statistics-refresh)
(lambda () nil)))
(setq org-drill-statistics--range "last 90d")
(org-drill-statistics-cycle-range)
(should (equal "last 30d" org-drill-statistics--range))
(org-drill-statistics-cycle-range)
(should (equal "all time" org-drill-statistics--range))
(org-drill-statistics-cycle-range)
(should (equal "last 90d" org-drill-statistics--range))))))
(ert-deftest test-org-drill-statistics-shell-cycle-algorithm-from-log ()
"Cycling algorithm walks nil then each algorithm seen in the log."
(with-temp-buffer
(let ((org-drill-session-log
(list (org-drill-statistics-test--record 1 'simple8 [4])
(org-drill-statistics-test--record 2 'sm5 [3]))))
(cl-letf (((symbol-function 'org-drill-statistics-refresh)
(lambda () nil)))
(setq org-drill-statistics--algorithm nil)
(org-drill-statistics-cycle-algorithm)
(should (memq org-drill-statistics--algorithm '(simple8 sm5)))
(org-drill-statistics-cycle-algorithm)
(should (memq org-drill-statistics--algorithm '(simple8 sm5)))
;; Third cycle wraps back to all-algorithms (nil).
(org-drill-statistics-cycle-algorithm)
(should (null org-drill-statistics--algorithm))))))
(ert-deftest test-org-drill-statistics-shell-integration-assembles-sections ()
"The assembled dashboard body contains every section's output.
Components integrated:
- org-drill-statistics--render-all (entry point, real)
- the five org-drill-statistics--render-* helpers (real)
- org-drill-session-log fixture (real, let-bound)
The card-scanning helpers are exercised against an empty current buffer,
so the card population is zero, but every section header must still
appear in the assembled string."
(with-temp-buffer
(org-mode)
(let ((org-drill-session-log
(list (org-drill-statistics-test--record 1 'simple8 [4 5 2])
(org-drill-statistics-test--record 3 'simple8 [3 4])
(org-drill-statistics-test--record 8 'sm5 [5 5 1]))))
;; Use 'file scope: the buffer has no headline, and 'tree errors
;; when point is before the first headline. 'file scans the
;; whole (empty) buffer and yields a zero card population.
(let ((body (org-drill-statistics--render-all
'file (caar org-drill-statistics-range-presets) nil)))
(should (stringp body))
;; The header line is always present.
(should (string-match-p "Scope:" body))
(should (string-match-p "Range:" body))
(should (string-match-p "Algorithm:" body))
;; Each render section contributes recognizable text. The exact
;; header wording lives in the render helpers; assert on the
;; section keywords the spec fixes rather than full prose.
(should (string-match-p "[Oo]verview" body))
(should (string-match-p "[Tt]rend" body))
(should (string-match-p "[Dd]istribution" body))
(should (string-match-p "[Aa]ttention" body))
(should (string-match-p "[Ff]orecast" body))))))
(provide 'test-org-drill-statistics-shell)
;;; test-org-drill-statistics-shell.el ends here
|