|
@@ -3,92 +3,7 @@
|
|
|
(require 'ido-completing-read+)
|
|
|
(require 'ert)
|
|
|
(require 'cl-lib)
|
|
|
-(require 'seq)
|
|
|
-
|
|
|
-;; This is a series of macros to facilitate the non-interactive
|
|
|
-;; testing of interactive functions by simulating user input.
|
|
|
-
|
|
|
-(defmacro with-simulated-input (keys &rest body)
|
|
|
- "Eval body with KEYS as simulated input.
|
|
|
-
|
|
|
-This macro is intended for testing normally interactive functions
|
|
|
-by simulating input. If BODY tries to read more input events than
|
|
|
-KEYS provides, `keyboard-quit' is invoked (by means of appending
|
|
|
-multple C-g keys to KEYS). This is to ensure that BODY will never
|
|
|
-block waiting for input, since this macro is intended for
|
|
|
-noninteractive use. As such, BODY should not invoke
|
|
|
-`keyboard-quit' under normal operation, and KEYS should not
|
|
|
-include C-g, or this macro will interpret it as reading past the
|
|
|
-end of input."
|
|
|
- (declare (indent 1))
|
|
|
- (let ((temp-cmd (cl-gensym "temp-cmd"))
|
|
|
- (cmd-finished-tag (cl-gensym "cmd-finished"))
|
|
|
- (canary-sym (cl-gensym "canary")))
|
|
|
- `(cl-letf*
|
|
|
- (;; Wrap BODY in a command that evaluates BODY and throws the
|
|
|
- ;; result with `cmd-finished-tag'.
|
|
|
- ((symbol-function ',temp-cmd)
|
|
|
- (lambda ()
|
|
|
- (interactive)
|
|
|
- (throw ',cmd-finished-tag (progn ,@body))))
|
|
|
- ;; Set up the keymap for invoking the temp command
|
|
|
- (transient-map (make-sparse-keymap))
|
|
|
- (command-invoke-key-sequence "C-c e")
|
|
|
- (simulated-key-sequence ,keys)
|
|
|
- (trailing-C-g-key-sequence
|
|
|
- ;; We *really* want to trigger `keyboard-quit' if we reach
|
|
|
- ;; the end KEYS.
|
|
|
- "C-g C-g C-g C-g C-g C-g C-g")
|
|
|
- (full-key-sequence
|
|
|
- (mapconcat #'identity
|
|
|
- (list
|
|
|
- command-invoke-key-sequence
|
|
|
- simulated-key-sequence
|
|
|
- trailing-C-g-key-sequence)
|
|
|
- " ")))
|
|
|
- (when (seq-contains (kbd simulated-key-sequence) (elt (kbd "C-g") 0))
|
|
|
- (error "KEYS must not include C-g"))
|
|
|
- ;; Finish setting up the keymap for the temp command
|
|
|
- (define-key transient-map (kbd command-invoke-key-sequence) ',temp-cmd)
|
|
|
- (set-transient-map transient-map)
|
|
|
- ;; Run the command followed by KEYS followed by C-g. The
|
|
|
- ;; `catch' ensures that the keyboard macro stops executing as
|
|
|
- ;; soon as BODY has finished evaluating, even if there are more
|
|
|
- ;; keys to interpret.
|
|
|
- (let ((result
|
|
|
- (condition-case err
|
|
|
- (catch ',cmd-finished-tag
|
|
|
- (execute-kbd-macro (kbd full-key-sequence))
|
|
|
- ;; If the above doesn't throw, return the canary
|
|
|
- ',canary-sym)
|
|
|
- ;; On `keyboard-quit', return canary
|
|
|
- (quit ',canary-sym))))
|
|
|
- (if (eq result ',canary-sym)
|
|
|
- (error "Reached end of simulated input while evaluating body")
|
|
|
- result)))))
|
|
|
-
|
|
|
-(ert-deftest simulate-input ()
|
|
|
- "Tests for the basic functionality of the `with-simulated-input' macro.
|
|
|
-
|
|
|
-This macro is used in testing ido-cr+."
|
|
|
- ;; Basic string input
|
|
|
- (should
|
|
|
- (string= "hello"
|
|
|
- (with-simulated-input "hello RET"
|
|
|
- (read-string "Enter a string: "))))
|
|
|
- ;; Error if RET is not pressed to finish the input
|
|
|
- (should-error
|
|
|
- (with-simulated-input "hello"
|
|
|
- (read-string "Enter a string: ")))
|
|
|
- ;; Can throw an error manually
|
|
|
- (should-error
|
|
|
- (with-simulated-input "(error SPC \"Manually SPC throwing SPC an SPC error\") RET"
|
|
|
- (command-execute 'eval-expression)))
|
|
|
- ;; Extra keys should not cause errors
|
|
|
- (should
|
|
|
- (string= "hello"
|
|
|
- (with-simulated-input "hello RET M-x eval-expression (error SPC \"Manually SPC throwing SPC an SPC error\") RET"
|
|
|
- (read-string "Enter a string: ")))))
|
|
|
+(require 'with-simulated-input)
|
|
|
|
|
|
(defmacro with-mode (mode arg &rest body)
|
|
|
"Eval (MODE ARG), then body, then restore previous status of MODE.
|