aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-resume-nil-session.el
blob: a2b2e7ce4e2521dd71536ac921fc256be2d0fa4c (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
;;; test-org-drill-resume-nil-session.el --- Regression for nil last-session  -*- lexical-binding: t; -*-

;;; Commentary:
;; `org-drill-again' and `org-drill-resume' bind a local `session' to
;; `org-drill-last-session' without checking for nil.  On the first
;; ever invocation (or after Emacs restart with no active session),
;; org-drill-last-session is nil and both functions throw — `again'
;; on `(setf (oref session cram-mode) nil)' (eieio-oset on nil),
;; `resume' on `org-drill-entries-pending-p' walking nil's slots.
;;
;; Fixed by adding an early `(unless session (user-error ...))' to
;; both.  A clear user-visible message replaces the obscure type
;; errors.

;;; Code:

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

;;;; Regression — org-drill-again

(ert-deftest test-org-drill-again-nil-last-session-raises-user-error ()
  "Calling org-drill-again with no prior session triggers a user-error,
not an obscure eieio type error."
  (let ((org-drill-last-session nil))
    (should-error (org-drill-again) :type 'user-error)))

;;;; Regression — org-drill-resume

(ert-deftest test-org-drill-resume-nil-last-session-raises-user-error ()
  "Calling org-drill-resume with no prior session triggers a user-error."
  (let ((org-drill-last-session nil))
    (should-error (org-drill-resume) :type 'user-error)))

;;;; org-drill-resume — happy paths

(ert-deftest test-org-drill-resume-with-pending-entries-resumes ()
  "When the prior session has pending entries, resume calls org-drill with resume-p=t."
  (let* ((session (org-drill-session))
         (org-drill-last-session session)
         (resume-args nil))
    (cl-letf (((symbol-function 'org-drill-entries-pending-p) (lambda (_) t))
              ((symbol-function 'org-drill)
               (lambda (&rest args) (setq resume-args args))))
      (org-drill-resume))
    (should resume-args)
    (should (nth 2 resume-args))))

(ert-deftest test-org-drill-resume-finished-with-no-pending-says-finished ()
  "When the session is done with no remaining pending count, prints the
'finished' message."
  (let* ((session (org-drill-session))
         (org-drill-last-session session)
         (messages nil))
    (cl-letf (((symbol-function 'message)
               (lambda (fmt &rest args)
                 (when fmt (push (apply #'format fmt args) messages)))))
      (org-drill-resume))
    (should (cl-some (lambda (m) (string-match-p "finished" m)) messages))))

(ert-deftest test-org-drill-resume-finished-with-y-starts-new ()
  "When session is done but pending count is positive and user answers y,
org-drill-again runs."
  (let* ((session (org-drill-session))
         (org-drill-last-session session)
         (m (let ((mk (make-marker))) (set-marker mk 1) mk))
         (again-called nil))
    ;; Done-entries non-empty + new-entries non-empty + done-entries reaches limit
    ;; tricky to set up cleanly.  Easier: stub the predicates.
    (cl-letf (((symbol-function 'org-drill-entries-pending-p)
               (lambda (_) nil))
              ((symbol-function 'org-drill-pending-entry-count)
               (lambda (_) 5))
              ((symbol-function 'y-or-n-p) (lambda (&rest _) t))
              ((symbol-function 'org-drill-again)
               (lambda (&rest _) (setq again-called t)))
              ((symbol-function 'message) #'ignore))
      (org-drill-resume))
    (should again-called)))

(provide 'test-org-drill-resume-nil-session)

;;; test-org-drill-resume-nil-session.el ends here