aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-prompt-and-misc.el
blob: 5b42f6bd56b94fb0459e3b813a0221ab0ea74e3d (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
;;; test-org-drill-prompt-and-misc.el --- Tests for prompt formatting and miscellaneous helpers  -*- lexical-binding: t; -*-

;;; Commentary:
;; Tests for several smaller helpers users see indirectly:
;;
;; - `org-drill--make-minibuffer-prompt': formats the live status line
;;   that appears at the top of every drill prompt — `Y 3 0 5 12 ...'
;;   showing card status / done / failed / mature / new / prompt.
;; - `org-drill-relearn-item': resets the current item's interval to 0
;;   so it gets drilled again.
;; - `org-drill-progress-message': progress bar shown during the
;;   collection scan, only updates every 50 scans.

;;; Code:

(require 'ert)
(require 'cl-lib)
(require 'org)
(require 'org-drill)

;;;; Helpers

(defmacro with-fresh-drill-entry (&rest body)
  (declare (indent 0))
  `(with-temp-buffer
     (let ((org-startup-folded nil))
       (insert "* Question :drill:\nbody\n")
       (org-mode)
       (goto-char (point-min))
       ,@body)))

(defmacro with-fixed-now (&rest body)
  `(cl-letf (((symbol-function 'current-time)
              (lambda () (encode-time 0 0 12 5 5 2026))))
     ,@body))

(defun make-marker-at (pos)
  (let ((m (make-marker))) (set-marker m pos) m))

;;;; org-drill--make-minibuffer-prompt

(ert-deftest test-org-drill--make-minibuffer-prompt-includes-status-character ()
  "A :new entry shows `N' as the leading status char."
  (with-fresh-drill-entry
    (with-fixed-now
      (let* ((session (org-drill-session))
             (prompt (org-drill--make-minibuffer-prompt session "test")))
        (should (string-match-p "\\bN\\b" (substring-no-properties prompt)))))))

(ert-deftest test-org-drill--make-minibuffer-prompt-cram-shows-C ()
  "Cram mode displays `C' regardless of the underlying status."
  (with-fresh-drill-entry
    (with-fixed-now
      (let ((session (org-drill-session)))
        (oset session cram-mode t)
        (let ((prompt (org-drill--make-minibuffer-prompt session "test")))
          (should (string-match-p "\\bC\\b" (substring-no-properties prompt))))))))

(ert-deftest test-org-drill--make-minibuffer-prompt-failed-shows-F ()
  (with-temp-buffer
    (let ((org-startup-folded nil))
      (insert "* Question :drill:\nbody\n")
      (org-mode)
      (goto-char (point-min))
      (org-schedule nil "2026-04-30")
      (org-set-property "DRILL_LAST_QUALITY" "1")
      (org-set-property "DRILL_LAST_INTERVAL" "5")
      (org-set-property "DRILL_TOTAL_REPEATS" "3")
      (with-fixed-now
        (let* ((session (org-drill-session))
               (prompt (org-drill--make-minibuffer-prompt session "test")))
          (should (string-match-p "\\bF\\b" (substring-no-properties prompt))))))))

(ert-deftest test-org-drill--make-minibuffer-prompt-includes-done-count ()
  "Done count appears in the prompt as a numeric field."
  (with-fresh-drill-entry
    (with-fixed-now
      (let ((session (org-drill-session)))
        (oset session done-entries
              (list (make-marker-at 1) (make-marker-at 1) (make-marker-at 1)))
        (let ((prompt (org-drill--make-minibuffer-prompt session "...")))
          ;; 3 done items should appear as " 3 " somewhere
          (should (string-match-p "\\b3\\b" (substring-no-properties prompt))))))))

(ert-deftest test-org-drill--make-minibuffer-prompt-passes-through-prompt-text ()
  "The user's prompt text shows up at the end."
  (with-fresh-drill-entry
    (with-fixed-now
      (let* ((session (org-drill-session))
             (result (org-drill--make-minibuffer-prompt session "type-your-answer")))
        (should (string-match-p "type-your-answer" result))))))

;;;; org-drill-relearn-item

(ert-deftest test-org-drill-relearn-item-resets-interval-to-zero ()
  "Relearning sets DRILL_LAST_INTERVAL back to 0 — the card behaves as new."
  (with-fresh-drill-entry
    (org-drill-store-item-data (make-org-drill-card-state :last-interval 30 :repetitions 5 :failures 0 :total-repeats 5 :meanq 4.0 :ease 2.5))
    (with-fixed-now
      (org-drill-relearn-item))
    ;; After relearn: last-interval should be 0
    (should (= 0 (string-to-number
                  (org-entry-get (point) "DRILL_LAST_INTERVAL"))))))

(ert-deftest test-org-drill-relearn-item-removes-scheduled-stamp ()
  "Relearning unschedules the entry (days-ahead = 0 path)."
  (with-fresh-drill-entry
    (org-drill-store-item-data (make-org-drill-card-state :last-interval 30 :repetitions 5 :failures 0 :total-repeats 5 :meanq 4.0 :ease 2.5))
    (org-schedule nil "2026-06-01")
    (with-fixed-now
      (org-drill-relearn-item))
    (should (null (org-entry-get (point) "SCHEDULED")))))

;;;; org-drill-progress-message

(ert-deftest test-org-drill-progress-message-on-multiple-of-50-emits-message ()
  "Every 50th scan triggers a `Collecting due drill items...' message."
  (let ((message-log-max nil)
        (got-message nil))
    (cl-letf (((symbol-function 'message)
               (lambda (fmt &rest args) (setq got-message (apply #'format fmt args)))))
      (org-drill-progress-message 5 50)
      (should got-message)
      (should (string-match-p "Collecting due drill items" got-message)))))

(ert-deftest test-org-drill-progress-message-on-non-multiple-stays-silent ()
  "Scans that aren't multiples of 50 don't update the message."
  (let ((got-message nil))
    (cl-letf (((symbol-function 'message)
               (lambda (fmt &rest _) (setq got-message fmt))))
      (org-drill-progress-message 5 17)   ; 17 % 50 != 0
      (should (null got-message)))))

(ert-deftest test-org-drill-progress-message-includes-collected-count ()
  "The message includes the COLLECTED count."
  (let ((got-message nil))
    (cl-letf (((symbol-function 'message)
               (lambda (fmt &rest args)
                 (setq got-message (apply #'format fmt args)))))
      (org-drill-progress-message 42 50)
      (should (string-match-p "42" got-message)))))

;;;; org-drill outline path in the drill prompt (m.galimski patch)

(ert-deftest test-org-drill--outline-path-string-nested ()
  "A nested entry yields its ancestor path, bracketed and arrow-joined."
  (with-temp-buffer
    (insert "* Spanish\n** Greetings\n*** Hola :drill:\nhola = hello\n")
    (org-mode)
    (goto-char (point-min))
    (search-forward "Hola")
    (should (equal (org-drill--outline-path-string) "[Spanish > Greetings] "))))

(ert-deftest test-org-drill--outline-path-string-top-level-empty ()
  "A top-level entry has no ancestors, so the path string is empty."
  (with-temp-buffer
    (insert "* Hola :drill:\nhola = hello\n")
    (org-mode)
    (goto-char (point-min))
    (should (equal (org-drill--outline-path-string) ""))))

(ert-deftest test-org-drill--make-minibuffer-prompt-omits-path-by-default ()
  "With the defcustom off, the outline path is absent from the prompt."
  (with-temp-buffer
    (let ((org-startup-folded nil)
          (org-drill-show-outline-path-during-drill nil))
      (insert "* Spanish\n** Greetings\n*** Hola :drill:\nhola = hello\n")
      (org-mode)
      (goto-char (point-min))
      (search-forward "Hola")
      (with-fixed-now
        (let* ((session (org-drill-session))
               (prompt (substring-no-properties
                        (org-drill--make-minibuffer-prompt session "test"))))
          (should-not (string-match-p "Greetings" prompt)))))))

(ert-deftest test-org-drill--make-minibuffer-prompt-shows-path-when-on ()
  "With the defcustom on, the prompt carries the bracketed outline path."
  (with-temp-buffer
    (let ((org-startup-folded nil)
          (org-drill-show-outline-path-during-drill t))
      (insert "* Spanish\n** Greetings\n*** Hola :drill:\nhola = hello\n")
      (org-mode)
      (goto-char (point-min))
      (search-forward "Hola")
      (with-fixed-now
        (let* ((session (org-drill-session))
               (prompt (substring-no-properties
                        (org-drill--make-minibuffer-prompt session "test"))))
          (should (string-match-p "\\[Spanish > Greetings\\]" prompt)))))))

(ert-deftest test-org-drill-show-outline-path-defaults-off ()
  "The outline-path defcustom ships nil so the prompt is unchanged by default."
  (should (eq nil (default-value 'org-drill-show-outline-path-during-drill))))

(provide 'test-org-drill-prompt-and-misc)

;;; test-org-drill-prompt-and-misc.el ends here