Previous: , Up: How to Write Tests [Contents][Index]


3.8 Various Helper Functions

The package ert-x.el contains some macros and functions useful for writing tests.

Macro: ert-with-message-capture (var &rest body)

This macro executes body while collecting messages in var. It captures messages issued by Lisp code and concatenates them separated by newlines into one string. This includes messages written by message as well as objects printed by print, prin1 and princ to the echo area. Messages issued from C code using the above mentioned functions will not be captured.

This is useful for separating the issuance of messages by the code under test from the behavior of the *Messages* buffer. Example:

(ert-with-message-capture captured-messages ...)

3.8.1 Test Directories and Files

Macro: ert-resource-directory ()

It returns the absolute file name of the resource (test data) directory. The path to the resource directory is the resources directory in the same directory as the test file this is called from.

If that directory doesn’t exist, find a directory based on the test file name. If the test file is named foo-tests.el, it returns the absolute file name for foo-resources. Example:

(let ((dir (ert-resource-directory)))
 ...)

In order to use a different resource directory naming scheme, the variable ert-resource-directory-format can be changed. Before formatting, the file name will be trimmed using string-trim with arguments ert-resource-directory-trim-left-regexp and ert-resource-directory-trim-right-regexp. Example:

(let* ((ert-resource-directory-format "test-resources-%s/")
 (ert-resource-directory-trim-left-regexp ".*/")
 (dir (ert-resource-directory)))
 ...)

uses the absolute file name for test-resources-foo.

Macro: ert-resource-file (file)

It returns the absolute file name of resource (test data) file named file, which should be a relative file name. A resource file is defined as any file placed in the resource directory as returned by ert-resource-directory. Example:

(let ((file (ert-resource-file "bar/baz")))
 ...)

It returns the absolute file name for foo-resources/bar/baz when called in test file foo-tests.el.

Macro: ert-with-temp-file (name &rest body)

This macro binds name to the name of a new temporary file and evaluates body. It deletes the temporary file after body exits normally or non-locally. name will be bound to the file name of the temporary file.

The following keyword arguments are supported:

:prefix string

If non-nil, pass string to make-temp-file as the prefix argument. Otherwise, use the value of ert-temp-file-prefix.

:suffix string

If non-nil, pass string to make-temp-file as the suffix argument. Otherwise, use the value of ert-temp-file-suffix; if the value of that variable is nil, generate a suffix based on the name of the file that ert-with-temp-file is called from.

:text string

If non-nil, pass string to make-temp-file as the text argument.

:buffer symbol

Open the temporary file using find-file-noselect and bind symbol to the buffer. Kill the buffer after body exits normally or non-locally.

:coding coding

If non-nil, bind coding-system-for-write to coding when executing body. This is handy when string includes non-ASCII characters or the temporary file must have a specific encoding or end-of-line format.

Example:

(ert-with-temp-file temp-file
 :prefix "foo"
 :suffix "bar"
 :text "foobar3"
 ...)
Macro: ert-with-temp-directory (name &rest body)

This macro binds name to the name of a new temporary directory and evaluates body. It deletes the temporary directory after body exits normally or non-locally.

name is bound to the directory name, not the directory file name. (In other words, it will end with the directory delimiter; on Unix-like systems, it will end with "/".)

The same keyword arguments are supported as in ert-with-temp-file, except for :text. Example:

(ert-with-temp-directory temp-dir
 :prefix "foo"
 :suffix "bar"
 ...)
Variable: ert-remote-temporary-file-directory

This variable provides the name of a temporary directory for remote file tests. Per default, a mock-up connection method is used (this might not be possible when running on MS Windows). The default value is "/mock::/tmp/".

If a real remote connection shall be used for testing, this can be overwritten by the environment variable REMOTE_TEMPORARY_FILE_DIRECTORY. Example:

# env REMOTE_TEMPORARY_FILE_DIRECTORY=/ssh:host:/tmp make ...

3.8.2 Miscellaneous Utilities

Function: ert-simulate-command (command)

Simulate calling command the way the Emacs command loop would call it. It runs hooks like pre-command-hook and post-command-hook, and sets variables like this-command and last-command.

command should be a list where the car is the command symbol and the rest are arguments to the command. Example:

(ert-simulate-command '(find-file "project/foo.c"))

Note: Since the command is not called by call-interactively, a test for (called-interactively-p kind) in the command will fail for whatever kind.
Function ert-play-keys may be used instead to start a command if you need the predicate (called-interactively-p kind) tested within the command body to return t for kind any, note however that it will still be nil too for kind interactive since ert-play-keys uses keyboard macros under the hood, and that ert-play-keys needs selecting the buffer of interest.

Macro: ert-simulate-keys (keys &rest body)

This executes body with keys as pseudo-interactive input. keys is either a string, a list of characters, or a character vector. Examples:

(ert-simulate-keys '(?n ?\C-m) ...)
(ert-simulate-keys "\r\r\r\ry\r" ...)
(ert-simulate-keys (kbd "#fake C-m C-a C-k C-m") ...)
(ert-simulate-keys [?b ?2 return] ...)

To generate input event for inserting some text into a buffer, or calling some interactive command, see rather function ert-play-keys.

Function: ert-play-keys (keys)

Generate programmatically user input events.

Contrary to ert-simulate-keys, these events are not intended to be consumed by functions reading input, like 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 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 :selected flag to ert-with-test-buffer if the buffer was created this way, or use the ert-with-buffer-selected macro.

Contrary to ert-simulate-command, when ert-play-keys generates events starting a command you cannot get the command return value. On the other hand, (called-interactively-p 'any) tested in the command body will be t, but not (called-interactively-p 'interactive) as ert-play-keys does not a true interactive call, but uses a keyboard macro under the hood. Another difference is that, contrary to ert-simulate-command, 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 ert-play-keys sets the mark, inserts text ‘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 ert-play-keys call yanks again the killed text, and finally the test checks the test buffer contains ‘n'importe quoi’:

(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))))))

Write input events as above with a string in the input format used by key-parse, or directly in the internal Emacs representation like here which is otherwise the same test as above:

(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))))))
Function: ert-filter-string (s &rest regexps)

This function returns a copy of string s with all matches of regexps removed. Elements of regexps may also be two-element lists (regexp subexp), where subexp is the number of a subexpression in regexp. In that case, only that subexpression will be removed rather than the entire match. Example:

(with-current-buffer ...
 (ert-filter-string (buffer-string)
 '("Started at:\\(.*\\)$" 1)
 '("Finished at:\\(.*\\)$" 1))
 ...)
Function: ert-propertized-string (&rest args)

This function returns a string with properties as specified by args.

args is a list of strings and plists. The strings in args are concatenated to produce an output string. In the output string, each string from args will have the preceding plist as its property list, or no properties if there is no plist before it. Example:

(ert-propertized-string "foo " '(face italic) "bar" " baz" nil " quux")

This returns the string "foo bar baz quux" where the substring "bar baz" has a face property with the value italic.


Previous: Handling Buffers during tests, Up: How to Write Tests [Contents][Index]

AltStyle によって変換されたページ (->オリジナル) /