aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-read-key-sequence.el
blob: 672b03486244cbe6a9630c28061e605e03134c4d (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
;;; test-org-drill-read-key-sequence.el --- Tests for input-method-safe key reading  -*- lexical-binding: t; -*-

;;; Commentary:
;; Regression tests for `org-drill--read-key-sequence'.
;;
;; Upstream issues #52 (breadncup, 2023-11-24) and #58 (breadncup,
;; 2024-12-31) reported that running an org-drill session silently
;; nulled out the user's `default-input-method'.
;;
;; Root cause: the wrapper called `(set-input-method nil)' to disable
;; the input method during the key read.  In Emacs, calling
;; `set-input-method' with nil while no input method is active has the
;; documented side effect of clearing `default-input-method' as well —
;; clobbering the user's persistent setting.  The fix is to use the
;; primitive that's specifically scoped to current state:
;; `deactivate-input-method' on the way out, and `activate-input-method'
;; on the way back.

;;; Code:

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

;;;; Helpers

(defmacro with-stubbed-key-sequence (return-value &rest body)
  "Run BODY with `read-key-sequence' replaced by a stub that returns RETURN-VALUE.
Avoids the interactive prompt during batch test runs."
  (declare (indent 1))
  `(cl-letf (((symbol-function 'read-key-sequence)
              (lambda (_prompt) ,return-value)))
     ,@body))

;;;; Normal cases

(ert-deftest test-org-drill-read-key-sequence-normal-no-input-method-set ()
  "When neither default- nor current-input-method is set, both stay nil."
  (let ((default-input-method nil)
        (current-input-method nil))
    (with-stubbed-key-sequence "x"
      (org-drill--read-key-sequence "prompt: "))
    (should (null default-input-method))
    (should (null current-input-method))))

(ert-deftest test-org-drill-read-key-sequence-normal-returns-stubbed-value ()
  "The wrapper returns whatever `read-key-sequence' returns."
  (let ((default-input-method nil)
        (current-input-method nil))
    (should (equal "answer"
                   (with-stubbed-key-sequence "answer"
                     (org-drill--read-key-sequence "prompt: "))))))

;;;; Boundary / regression — issues #52 and #58

(ert-deftest test-org-drill-read-key-sequence-preserves-default-when-no-current ()
  "Issue #52/#58 regression: default-input-method must survive the call.

The reporter (breadncup) had `default-input-method' set to a Korean
input method but no input method active at session start.  Each
org-drill rating prompt would silently clear `default-input-method'."
  (let ((default-input-method "TeX")
        (current-input-method nil))
    (with-stubbed-key-sequence "x"
      (org-drill--read-key-sequence "prompt: "))
    (should (equal "TeX" default-input-method))))

(ert-deftest test-org-drill-read-key-sequence-preserves-default-across-multiple-calls ()
  "Repeated calls during a session don't accumulate damage to default-input-method."
  (let ((default-input-method "TeX")
        (current-input-method nil))
    (with-stubbed-key-sequence "x"
      (dotimes (_ 5)
        (org-drill--read-key-sequence "prompt: ")))
    (should (equal "TeX" default-input-method))))

;;;; Error cases

(ert-deftest test-org-drill-read-key-sequence-error-restores-default-after-throw ()
  "If `read-key-sequence' errors, unwind-protect must still leave default-input-method intact."
  (let ((default-input-method "TeX")
        (current-input-method nil))
    (cl-letf (((symbol-function 'read-key-sequence)
               (lambda (_prompt) (error "simulated read failure"))))
      (should-error (org-drill--read-key-sequence "prompt: ")))
    (should (equal "TeX" default-input-method))))

;;;; Same bug pattern in org-drill-response-get-buffer-create

(ert-deftest test-org-drill-response-get-buffer-create-preserves-default-input-method ()
  "Issue #52/#58 regression in the response-buffer path.

`org-drill-response-get-buffer-create' captures `current-input-method'
from the caller, then propagates it to the new *Org-Drill* buffer via
`set-input-method'.  When the caller has no input method active, the
captured value is nil — and `(set-input-method nil)' clears the global
`default-input-method'.  Same bug pattern, different function."
  (let ((default-input-method "TeX")
        (current-input-method nil))
    (unwind-protect
        (org-drill-response-get-buffer-create)
      (when (get-buffer "*Org-Drill*")
        (kill-buffer "*Org-Drill*")))
    (should (equal "TeX" default-input-method))))

(provide 'test-org-drill-read-key-sequence)

;;; test-org-drill-read-key-sequence.el ends here