DarwinAwardWinner / with-simulated-input

Test your interactive elisp functions non-interactively!
GNU General Public License v3.0
38 stars 4 forks source link

with-simulated-input

MELPA Stable CI Status Coverage Status

This package provides an Emacs Lisp macro, with-simulated-input, which evaluates one or more forms while simulating a sequence of input events for those forms to read. The result is the same as if you had evaluated the forms and then manually typed in the same input. This macro is useful for non-interactive testing of normally interactive commands and functions, such as completing-read.

For example:

(with-simulated-input
    "hello SPC world RET"
  (read-string "Say hello to the world: "))

This would return the string "hello world".

Running code during input

Sometimes you need to simulate an interaction that is difficult or impossible to express as a sequence of keys. In this case, you can pass a list of "inputs" instead of a single string. Any string in this list will be treated as a key sequence, and any other form will be treated as Emacs Lisp code and evaluated at that point during the simulated interaction. For example, we can use Emacs Lisp code to enter "world" after entering "hello" via key sequence:

(let ((thing-to-greet "world"))
  (with-simulated-input
      ("hello SPC" (insert thing-to-greet) "RET")
    (read-string "Say hello: ")))

Note 1: The return values of any forms in the input list are ignored. Only the side effects matter. In this case, the side effect of insert is to insert "world" into the minibuffer.

Note 2: Previous versions of with-simulated-input attempted to evalaute KEYS normally despite being a macro, so a quote was required in front of KEYS if it was a list. This is no longer the case as of version 3.0.

Simulating idleness

Some interactive functions rely on idle timers to do their work, so you might need a way to simulate idleness. For that, there is the wsi-simulate-idle-time function. For example, the following code will return "hello world".

;; Insert "world" after 500 seconds
(run-with-idle-timer 500 nil 'insert "world")
(with-simulated-input
    ;; Type "hello ", then "wait" 501 seconds, then type "RET"
    ("hello SPC" (wsi-simulate-idle-time 501) "RET")
  (read-string "Enter a string: "))

Note that the example code above only pretends to be idle for 501 seconds. It actually runs immediately.

Running the tests

This package comes with a test suite. If you want to run it yourself, first install the Eldev, then use eldev test to run the tests. Please run this test suite before submitting any pull requests, and note in the pull request whether any of the tests fail.