ert-play-keys function
* lisp/emacs-lisp/ert-x.el (ert-play-keys): new defun. * test/lisp/simple-tests.el (undo-test-kill-c-a-then-undo) (undo-test-point-after-forward-kill): Use new function `ert-play-keys' and `(ert-with-test-buffer (:selected t) ...)' rather (with-temp-buffer (switch-to-buffer (current-buffer) ...)'. * test/lisp/erc/erc-scenarios-spelling.el (erc-scenarios-spelling--auto-correct): Use new function `ert-play-keys' and `(ert-with-buffer-selected ...)' rather than `execute-kbd-macro' and `(with-current-buffer ... (set-window-buffer nil (current-buffer) ...)'. * doc/misc/ert.texi (Helper Functions): Document ert-play-keys, and differences between ert-simulate-command, ert-simulate-keys & ert-play-keys. * test/lisp/emacs-lisp/ert-x-tests.el (ert-x-tests-play-keys) (ert-x-tests-simulate-command, ert-x-tests-simulate-keys): New tests.
This commit is contained in:
@@ -1132,6 +1132,12 @@ This has the same effect as combining @code{ert-with-test-buffer} with
|
||||
(ert-with-test-buffer (:name "global" :selected t)
|
||||
@dots{}))
|
||||
@end lisp
|
||||
|
||||
@findex ert-play-keys
|
||||
The @var{select-form} shall be set non-nil when @var{body} contains some
|
||||
call to @code{ert-play-keys} to generate programmatically user input
|
||||
events inserting text into the test buffer, or starting commands acting
|
||||
on the test buffer.
|
||||
@end defmac
|
||||
|
||||
@defmac ert-with-buffer-selected (buffer &body body)
|
||||
@@ -1154,6 +1160,13 @@ value is the last form in @var{body}. Example:
|
||||
@end lisp
|
||||
|
||||
This displays a temporary buffer like @file{ *temp*-739785*}.
|
||||
|
||||
@findex ert-play-keys
|
||||
One of the use of @code{ert-with-buffer-selected} is to set the buffer
|
||||
to which user input events generated programmatically by one or more
|
||||
calls to @code{ert-play-keys} are targetted, which is needed when those
|
||||
events are supposed to insert text into this buffer, or start commands
|
||||
acting on it.
|
||||
@end defmac
|
||||
|
||||
@subsection Protecting buffers
|
||||
@@ -1348,7 +1361,14 @@ symbol and the rest are arguments to the command. Example:
|
||||
|
||||
@strong{Note}: Since the command is not called by
|
||||
@code{call-interactively}, a test for @code{(called-interactively-p
|
||||
'interactive)} in the command will fail.
|
||||
@var{kind})} in the command will fail for whatever @var{kind}.@*
|
||||
Function @code{ert-play-keys} may be used instead to start a command if
|
||||
you need the predicate @code{(called-interactively-p @var{kind})} tested
|
||||
within the command body to return @code{t} for @var{kind} @code{any},
|
||||
note however that it will still be @code{nil} too for @var{kind}
|
||||
@code{interactive} since @code{ert-play-keys} uses keyboard macros under
|
||||
the hood, and that @code{ert-play-keys} needs selecting the buffer of
|
||||
interest.
|
||||
@end defun
|
||||
|
||||
@defmac ert-simulate-keys (keys &rest body)
|
||||
@@ -1362,8 +1382,76 @@ vector. Examples:
|
||||
(ert-simulate-keys (kbd "#fake C-m C-a C-k C-m") @dots{})
|
||||
(ert-simulate-keys [?b ?2 return] @dots{})
|
||||
@end lisp
|
||||
|
||||
@c @findex ert-play-keys
|
||||
To generate input event for inserting some text into a buffer, or
|
||||
calling some interactive command, see rather function
|
||||
@code{ert-play-keys}.
|
||||
@end defmac
|
||||
|
||||
@defun ert-play-keys (keys)
|
||||
Generate programmatically user input events.
|
||||
|
||||
@c @findex ert-simulate-keys
|
||||
Contrary to @code{ert-simulate-keys}, these events are not intended to be
|
||||
consumed by functions reading input, like @code{read-from-minibuffer},
|
||||
but are consumed by the command loop which typically will process them
|
||||
to start interactive commands or insert text into the selected buffer.
|
||||
|
||||
So, before calling @code{ert-play-keys} you generally need to select the
|
||||
buffer to which input events are intended to insert text or call a
|
||||
command. Do this by passing a non-nil @code{:selected} flag to
|
||||
@code{ert-with-test-buffer} if the buffer was created this way, or use
|
||||
the @code{ert-with-buffer-selected} macro.
|
||||
|
||||
@c @findex ert-simulate-command
|
||||
Contrary to @code{ert-simulate-command}, when @code{ert-play-keys}
|
||||
generates events starting a command you cannot get the command return
|
||||
value. On the other hand, @code{(called-interactively-p 'any)} tested in
|
||||
the command body will be @code{t}, but not @code{(called-interactively-p
|
||||
'interactive)} as @code{ert-play-keys} does not a true interactive call,
|
||||
but uses a keyboard macro under the hood. Another difference is that,
|
||||
contrary to @code{ert-simulate-command}, @code{ert-play-keys} needs to
|
||||
select the buffer on which the command acts for the input events to
|
||||
reach it.
|
||||
|
||||
In this example a test buffer is created and selected, then
|
||||
@code{ert-play-keys} sets the mark, inserts text @samp{n'importe quoi}
|
||||
and kills it, then the test checks that the killed text is in the kill
|
||||
ring and the test buffer is empty, then a second @code{ert-play-keys}
|
||||
call yanks again the killed text, and finally the test checks the test
|
||||
buffer contains @samp{n'importe quoi}:
|
||||
|
||||
@lisp
|
||||
(ert-deftest ert-example-kill&yank ()
|
||||
"Test kill and yank."
|
||||
(ert-with-test-buffer (:selected t)
|
||||
(ert-play-keys "C-SPC n'importe SPC quoi C-w")
|
||||
(should (string= "n'importe quoi" (car kill-ring)))
|
||||
(should (string= "" (buffer-substring (point-min) (point-max))))
|
||||
(ert-play-keys "C-y")
|
||||
(should (string= "n'importe quoi"
|
||||
(buffer-substring (point-min) (point-max))))))
|
||||
@end lisp
|
||||
|
||||
@noindent
|
||||
Write input events as above with a string in the input format used by
|
||||
@code{key-parse}, or directly in the internal Emacs representation like
|
||||
here which is otherwise the same test as above:
|
||||
|
||||
@lisp
|
||||
(ert-deftest ert-example-kill&yank ()
|
||||
"Test kill and yank."
|
||||
(ert-with-test-buffer (:selected t)
|
||||
(ert-play-keys (vconcat [ ?\C- ] "n'importe quoi" [ ?\C-w]))
|
||||
(should (string= "n'importe quoi" (car kill-ring)))
|
||||
(should (string= "" (buffer-substring (point-min) (point-max))))
|
||||
(ert-play-keys [ ?\C-y ])
|
||||
(should (string= "n'importe quoi"
|
||||
(buffer-substring (point-min) (point-max))))))
|
||||
@end lisp
|
||||
@end defun
|
||||
|
||||
@defun ert-filter-string (s &rest regexps)
|
||||
This function returns a copy of string @var{s} with all matches of
|
||||
@var{regexps} removed. Elements of @var{regexps} may also be
|
||||
|
||||
@@ -416,6 +416,19 @@ The same keyword arguments are supported as in
|
||||
(format "/mock::%s" temporary-file-directory))))
|
||||
"Temporary directory for remote file tests.")
|
||||
|
||||
(defun ert-play-keys (keys)
|
||||
"Play the key sequence KEYS as if it was user input.
|
||||
|
||||
KEYS shall have the same format as in a call to function `kmacro'.
|
||||
|
||||
This macro should be expanded within the body of
|
||||
`ert-with-buffer-selected' to select a buffer when keys KEYS start
|
||||
commands acting on this buffer, or within the body of
|
||||
`ert-with-test-buffer' used with `:selected' flag set."
|
||||
(funcall
|
||||
(kmacro keys)))
|
||||
|
||||
|
||||
|
||||
;;;; Obsolete
|
||||
|
||||
|
||||
@@ -3125,14 +3125,13 @@ The return value is the last form in BODY."
|
||||
|
||||
If BUFFER-OR-NAME is nil, the current buffer is used.
|
||||
|
||||
The buffer is made the current buffer, and the temporary window
|
||||
becomes the `selected-window', before BODY is evaluated. The
|
||||
modification hooks `before-change-functions' and
|
||||
`after-change-functions' are not inhibited during the evaluation
|
||||
of BODY, which makes it easier to use `execute-kbd-macro' to
|
||||
simulate user interaction. The window configuration is restored
|
||||
before returning, even if BODY exits nonlocally. The return
|
||||
value is the last form in BODY."
|
||||
The buffer is made the current buffer, and the temporary window becomes
|
||||
the `selected-window', before BODY is evaluated. The modification hooks
|
||||
`before-change-functions' and `after-change-functions' are not inhibited
|
||||
during the evaluation of BODY, which makes it easier to use
|
||||
`ert-play-keys' to simulate user sending input events. The window
|
||||
configuration is restored before returning, even if BODY exits
|
||||
nonlocally. The return value is the last form in BODY."
|
||||
(declare (debug (form body)) (indent 1))
|
||||
`(save-window-excursion
|
||||
(with-current-buffer (or ,buffer-or-name (current-buffer))
|
||||
|
||||
@@ -293,6 +293,77 @@ desired effect."
|
||||
(should-error
|
||||
(ert-with-temp-directory dir :text "foo" nil)))
|
||||
|
||||
(ert-deftest ert-x-tests-play-keys ()
|
||||
"Test `ert-play-keys'.
|
||||
Send one symbolic event, some inserted text, and some key event to the
|
||||
test buffer, and check all of them are processed."
|
||||
(ert-with-test-buffer (:selected t)
|
||||
(let (verdict-event verdict-key verdict-pre-command-hook verdict-post-command-hook)
|
||||
(let ((pre-command-hook (lambda () (setq verdict-pre-command-hook t)))
|
||||
(post-command-hook (lambda () (setq verdict-post-command-hook t)))
|
||||
(map (let ((map (make-sparse-keymap)))
|
||||
(define-key map [event]
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(setq verdict-event
|
||||
(list t
|
||||
(called-interactively-p 'any)
|
||||
(called-interactively-p 'interactive)))))
|
||||
(define-key map [?$]
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(setq verdict-key
|
||||
(list t
|
||||
(called-interactively-p 'any)
|
||||
(called-interactively-p 'interactive)))))
|
||||
map)))
|
||||
(let ((minor-mode-map-alist (cons (cons t map) minor-mode-map-alist)))
|
||||
(ert-play-keys (vconcat [event] "n'importe $quoi"))))
|
||||
(should (equal verdict-event '(t t nil)))
|
||||
(should (equal verdict-key '(t t nil)))
|
||||
(should (eq verdict-pre-command-hook t))
|
||||
(should (eq verdict-post-command-hook t)))
|
||||
(should (string= "n'importe quoi"
|
||||
(buffer-substring (point-min) (point-max))))))
|
||||
|
||||
(ert-deftest ert-x-tests-simulate-command ()
|
||||
"Test `ert-simulate-command'."
|
||||
(ert-with-test-buffer ()
|
||||
(let (verdict-interactive verdict-pre-command-hook verdict-post-command-hook)
|
||||
(let ((pre-command-hook (lambda () (setq verdict-pre-command-hook t)))
|
||||
(post-command-hook (lambda () (setq verdict-post-command-hook t))))
|
||||
(should (eq (ert-simulate-command
|
||||
(list
|
||||
(lambda (x)
|
||||
(interactive (list "un rien"))
|
||||
(insert x)
|
||||
(setq verdict-interactive (list t
|
||||
(called-interactively-p 'any)
|
||||
(called-interactively-p 'interactive)))
|
||||
:ok)
|
||||
"n'importe quoi"))
|
||||
:ok)))
|
||||
(should (equal verdict-interactive '(t nil nil)))
|
||||
(should (eq verdict-pre-command-hook t))
|
||||
(should (eq verdict-post-command-hook t)))
|
||||
(should (string= "n'importe quoi"
|
||||
(buffer-substring (point-min) (point-max))))))
|
||||
|
||||
(ert-deftest ert-x-tests-simulate-keys ()
|
||||
"Test `ert-simulate-keys'."
|
||||
(ert-with-test-buffer ()
|
||||
(let* ((map (let ((map (make-sparse-keymap)))
|
||||
(define-key map [?b]
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(insert "r"))) map))
|
||||
(minor-mode-map-alist (cons (cons t map) minor-mode-map-alist)))
|
||||
(ert-simulate-keys
|
||||
(listify-key-sequence "un bien\nn'importe quoi")
|
||||
(should (string= (read-from-minibuffer "Please enter something: ") "un rien")))
|
||||
(should (string= "" (buffer-substring (point-min) (point-max)))))))
|
||||
|
||||
|
||||
(provide 'ert-x-tests)
|
||||
|
||||
;;; ert-x-tests.el ends here
|
||||
|
||||
@@ -61,14 +61,13 @@
|
||||
(should erc-spelling-mode)
|
||||
(should flyspell-mode)))
|
||||
|
||||
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
|
||||
(ert-with-buffer-selected (erc-d-t-wait-for 10 (get-buffer "#chan"))
|
||||
(should erc-spelling-mode)
|
||||
(should flyspell-mode)
|
||||
(funcall expect 10 "<alice> tester, welcome!")
|
||||
|
||||
;; Insert a command with one misspelled word.
|
||||
(set-window-buffer nil (current-buffer))
|
||||
(execute-kbd-macro "\M->/AMSG an/dor /gmsg one fsbot two frob my shoe")
|
||||
(ert-play-keys (vconcat [?\M->] "/AMSG an/dor /gmsg one fsbot two frob my shoe"))
|
||||
(funcall expect 10 "shoe")
|
||||
|
||||
(let* ((ovs (overlays-in erc-input-marker (point)))
|
||||
@@ -90,7 +89,7 @@
|
||||
|
||||
;; Depending on the machine, this should become something
|
||||
;; like: "/AMSG an/dor /gmsg one fsbot two Rob my shoe".
|
||||
(execute-kbd-macro (key-parse "M-TAB"))
|
||||
(ert-play-keys "M-TAB")
|
||||
(should (equal (overlays-in erc-input-marker (point-max))
|
||||
(list ov1)))))
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'ert)
|
||||
(require 'ert-x)
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
(defun simple-test--buffer-substrings ()
|
||||
@@ -730,14 +730,13 @@ See bug#35036."
|
||||
;; Test for a regression introduced by undo-auto--boundaries changes.
|
||||
;; https://lists.gnu.org/r/emacs-devel/2015-11/msg01652.html
|
||||
(defun undo-test-kill-c-a-then-undo ()
|
||||
(with-temp-buffer
|
||||
(switch-to-buffer (current-buffer))
|
||||
(ert-with-test-buffer (:selected t)
|
||||
(setq buffer-undo-list nil)
|
||||
(insert "a\nb\nc\n")
|
||||
(goto-char (point-max))
|
||||
;; We use a keyboard macro because it adds undo events in the same
|
||||
;; way as if a user were involved.
|
||||
(funcall (kmacro [left
|
||||
(ert-play-keys [left
|
||||
;; Delete "c"
|
||||
backspace
|
||||
left left left
|
||||
@@ -745,21 +744,20 @@ See bug#35036."
|
||||
backspace
|
||||
;; C-/ or undo
|
||||
?\C-/
|
||||
]))
|
||||
])
|
||||
(point)))
|
||||
|
||||
(defun undo-test-point-after-forward-kill ()
|
||||
(with-temp-buffer
|
||||
(switch-to-buffer (current-buffer))
|
||||
(ert-with-test-buffer (:selected t)
|
||||
(setq buffer-undo-list nil)
|
||||
(insert "kill word forward")
|
||||
;; Move to word "word".
|
||||
(goto-char 6)
|
||||
(funcall (kmacro [;; kill-word
|
||||
(ert-play-keys [;; kill-word
|
||||
C-delete
|
||||
;; undo
|
||||
?\C-/
|
||||
]))
|
||||
])
|
||||
(point)))
|
||||
|
||||
(ert-deftest undo-point-in-wrong-place ()
|
||||
|
||||
Reference in New Issue
Block a user