blob: b3f2375dff0ae708aed1c4c67c7d1152db61c431 (
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
|
;;; test-org-drill-statistics-render-attention.el --- Tests for render-attention statistics -*- lexical-binding: t; -*-
;;; Commentary:
;; ERT tests for the org-drill statistics dashboard render-attention block.
;;; Code:
(require 'ert)
(require 'org-drill)
(require 'cl-lib)
(require 'org)
;;; tests/test-org-drill-statistics-render-attention.el -*- lexical-binding: t; -*-
(defun test-org-drill-stats--attn-fixture ()
"Insert a fixture buffer of drill cards and return today's day number.
Twelve leech candidates so the cap and footer are exercised, plus one
long-overdue card and one forgotten-new card. Dates derive from the
current time so the fixture never hardcodes today."
(let* ((today (org-drill-statistics--today-day))
(old-review (org-drill-time-to-inactive-org-timestamp
(org-time-string-to-time
(format-time-string
"%Y-%m-%d"
(time-subtract (current-time)
(days-to-time 400))))))
(old-added (format-time-string
"%Y-%m-%d"
(time-subtract (current-time) (days-to-time 30)))))
(insert "* Drill cards\n")
(dotimes (i 12)
(insert (format "** Leech %02d :drill:\n" i))
(insert ":PROPERTIES:\n")
(insert (format ":DRILL_FAILURE_COUNT: %d\n"
(+ org-drill-leech-failure-threshold 2)))
(insert (format ":DRILL_AVERAGE_QUALITY: %s\n"
(number-to-string (+ 1.0 (* 0.1 i)))))
(insert ":END:\n"))
(insert "** Overdue card :drill:\n")
(insert ":PROPERTIES:\n")
(insert (format ":DRILL_LAST_REVIEWED: %s\n" old-review))
(insert ":DRILL_FAILURE_COUNT: 0\n")
(insert ":END:\n")
(insert "** Forgotten card :drill:\n")
(insert ":PROPERTIES:\n")
(insert (format ":DATE_ADDED: %s\n" old-added))
(insert ":DRILL_TOTAL_REPEATS: 0\n")
(insert ":END:\n")
(org-mode)
today))
(ert-deftest test-org-drill-statistics-attention-section-heading ()
"The rendered section opens with the Needs attention heading."
(with-temp-buffer
(test-org-drill-stats--attn-fixture)
(let ((out (org-drill-statistics--render-attention 'file)))
(should (string-match-p "^\\*\\* Needs attention$" out))
(should (string-match-p "^\\*\\*\\* Leech candidates$" out))
(should (string-match-p "^\\*\\*\\* Long overdue$" out))
(should (string-match-p "^\\*\\*\\* Forgotten new$" out)))))
(ert-deftest test-org-drill-statistics-attention-leech-rows-as-links ()
"Leech candidates render as org links carrying card headings."
(with-temp-buffer
(test-org-drill-stats--attn-fixture)
(let ((out (org-drill-statistics--render-attention 'file)))
(should (string-match-p "| Card |" out))
(should (string-match-p "\\[\\[org-drill-card:[0-9]+\\]\\[Leech 00\\]\\]"
out)))))
(ert-deftest test-org-drill-statistics-attention-cap-and-footer ()
"Twelve leeches over a 10 cap show 10 rows and a +2 more footer."
(with-temp-buffer
(test-org-drill-stats--attn-fixture)
(let* ((org-drill-statistics-attention-row-limit 10)
(out (org-drill-statistics--render-attention 'file))
(link-count
(cl-count ?\n
(mapconcat #'identity
(seq-filter
(lambda (l) (string-match-p "org-drill-card:" l))
(split-string out "\n"))
"\n"))))
(should (string-match-p "+2 more" out))
;; 10 leech (capped) + 1 overdue + 1 forgotten = 12 link rows.
(should (= 12 (1+ link-count))))))
(ert-deftest test-org-drill-statistics-attention-leech-sort-worst-first ()
"Leech rows are ordered by ascending average quality, worst first."
(with-temp-buffer
(test-org-drill-stats--attn-fixture)
(let* ((out (org-drill-statistics--render-attention 'file))
(leech-00 (string-match "Leech 00" out))
(leech-01 (string-match "Leech 01" out)))
(should leech-00)
(should leech-01)
;; Leech 00 has avg 1.0, Leech 01 has 1.1, so 00 sorts first.
(should (< leech-00 leech-01)))))
(ert-deftest test-org-drill-statistics-attention-empty-category-note ()
"A category with no matches renders a note rather than a table."
(with-temp-buffer
(insert "* Cards\n** Healthy :drill:\n:PROPERTIES:\n")
(insert ":DRILL_FAILURE_COUNT: 0\n:DRILL_TOTAL_REPEATS: 5\n:END:\n")
(org-mode)
(let ((out (org-drill-statistics--render-attention 'file)))
(should (string-match-p "No leech candidates\\." out))
(should (string-match-p "No long-overdue cards\\." out))
(should (string-match-p "No forgotten-new cards\\." out)))))
(ert-deftest test-org-drill-statistics-attention-no-footer-under-cap ()
"With matches at or under the cap, no +N more footer appears."
(with-temp-buffer
(insert "* Cards\n")
(dotimes (i 3)
(insert (format "** Leech %d :drill:\n" i))
(insert ":PROPERTIES:\n")
(insert (format ":DRILL_FAILURE_COUNT: %d\n"
(+ org-drill-leech-failure-threshold 1)))
(insert ":DRILL_AVERAGE_QUALITY: 1.0\n:END:\n"))
(org-mode)
(let* ((org-drill-statistics-attention-row-limit 10)
(out (org-drill-statistics--render-attention 'file)))
(should-not (string-match-p "more" out)))))
(ert-deftest test-org-drill-statistics-card-link-sanitizes-brackets ()
"Closing brackets in a heading cannot terminate the link early."
(let ((link (org-drill-statistics--card-link "a]] b" 42)))
(should (string-prefix-p "[[org-drill-card:42][" link))
(should (string-suffix-p "]]" link))
(should-not (string-match-p "a]] b" link))))
(ert-deftest test-org-drill-statistics-card-link-empty-heading-fallback ()
"An empty heading falls back to a position-based description."
(let ((link (org-drill-statistics--card-link "" 99)))
(should (string-match-p "\\[\\[org-drill-card:99\\]\\[card at 99\\]\\]"
link))))
(provide 'test-org-drill-statistics-render-attention)
;;; test-org-drill-statistics-render-attention.el ends here
|