1 ;; Authors: Martin Blais <blais@furius.ca>
3 ;; Copyright: This module has been placed in the public domain.
5 ;; Simple generic test runner for test scripts.
9 ;; emacs --script <file>.el
12 ;; There are mainly two useful functions from this pacakge:
14 ;; 1. regression-test-compare-expect-values : used to compare expected output
15 ;; values from running a function;
17 ;; 2. regression-test-compare-expect-buffer : used to compare expected output
18 ;; buffer contents after running the function.
20 ;; regression-test-compare-expect-values test format
21 ;; -------------------------------------------------
23 ;; The tests are a list of tuples, with the following entries:
25 ;; - a SYMBOL that uniquely identifies the test.
27 ;; - the input buffer CONTENTS to prepare and run the test on. If char @ is
28 ;; present in the buffer, it is removed and the cursor is placed at that
29 ;; position before running the tested function.
31 ;; - the expected OUTPUT value that the function should return. If the actual
32 ;; output is different from this, the test will fail.
34 ;; - an optional list of INPUT ARGUMENTS that the test function is called with
37 ;; regression-test-compare-expect-buffer test format
38 ;; -------------------------------------------------
40 ;; - a SYMBOL that uniquely identifies the test.
42 ;; - the input buffer CONTENTS to prepare and run the test on. Here too, char @
43 ;; is present in the buffer, it is removed and the cursor is placed at that
44 ;; position before running the tested function.
46 ;; - the EXPECTED buffer contents after the function has been run.
47 ;; Additionally, if char @ is present, it is checked that the cursor is
48 ;; located at that position in the buffer after the function is run (this is
51 ;; - an optional list of PREFIX ARGUMENTS, which indicates to the test program
52 ;; to set those prefix arguments before running the given function. If there
53 ;; are multiple prefix args, the function is invoked many times.
59 (defvar regression-point-char
"@"
60 "Special character used to mark the position of point in input
61 text and expected text.")
63 (defun regression-test-loop (suitename testfun testlist fun
&optional continue
)
64 "Loop over a series of tests in a buffer and run the 'testfun'
67 (message (format "\n\n Test Suite: %s\n\n" suitename
))
69 (let ((buf (get-buffer-create "regression-tests"))
72 (dolist (curtest testlist
)
74 ;; Print current text.
75 (message (format "========= %s" (prin1-to-string (car curtest
))))
77 (setq errtxt
(run-test buf
(cadr curtest
) testfun
78 (list (car curtest
) (caddr curtest
)
83 (progn (message errtxt
)
84 (message "(Continuing...)"))
89 (defun run-test (buf input testfun args
)
90 "Prepare BUF with the starting text INPUT, move the cursor
91 where the special character is located, run TESTFUN with ARGS and
92 return the error text."
93 (switch-to-buffer buf
)
97 (if (not (search-backward regression-point-char nil t
))
98 (error (concat "Error: Badly formed test input, missing "
99 "the cursor position marker.")))
102 (apply testfun args
))
104 (defun run-test-filter (testfun &rest args
)
105 "Run a test as a filter.
107 Can be used with \"emacs --batch -l tests-runner.el -l ../rst.el --eval \"(run-test-filter 'function-name 'arg1...)\""
108 (let (;; Input from stdin
109 (input (read-from-minibuffer "")))
110 ;; Output result to stderr
111 (message "%s" (run-test (get-buffer-create "test") input testfun args
))
112 (insert regression-point-char
)
113 ;; Output buffer to stdout
114 (princ (buffer-string))
117 (defun regression-compare-buffers (testname expected testargs
)
118 "Compare the buffer and expected text and return actual
119 contents if they do not match."
121 ;; Run the section title update command n times.
122 (dolist (x (or testargs
(list nil
)))
123 (let ((current-prefix-arg x
))
126 ;; Compare the buffer output with the expected text.
127 (let* (;; Get the actual buffer contents.
128 (actual (buffer-string))
129 ;; Get the expected location of point
130 (exppoint (string-match regression-point-char expected
))
132 (expected-clean (if exppoint
133 (concat (substring expected
0 exppoint
)
134 (substring expected
(+ 1 exppoint
)))
137 ;; Adjust position of point vs. string index.
138 (exppoint (and exppoint
(+ exppoint
1)))
142 (if (not (string= expected-clean actual
))
143 ;; Error! Test failed.
144 (format "Error: Test %s failed: \nexpected\n%s\ngot\n%s"
146 (prin1-to-string expected-clean
)
147 (prin1-to-string actual
))
148 (if (and exppoint
(not (equal exppoint
(point))))
149 ;; Error! Test failed, final position of cursor is not the same.
150 (format "Error: Test %s failed: cursor badly placed." testname
))
153 (defun regression-test-compare-expect-buffer
154 (suitename testlist fun
&optional continue
)
155 "Run the regression tests for the expected buffer contents."
156 (regression-test-loop
157 suitename
'regression-compare-buffers testlist fun continue
))
160 (defun regression-compare-values (testname expected testargs
)
161 "Compare the buffer and expected text and return actual
162 contents if they do not match."
165 ;; Run the section title update command n times.
166 (setq actual
(apply fun testargs
))
168 ;; Compare the buffer output with the expected text.
169 (if (not (equal actual expected
))
170 ;; Error! Test failed.
171 (format "Error: Test %s failed: expected '%s' got '%s'."
173 (prin1-to-string expected
)
174 (prin1-to-string actual
))
177 (defun regression-test-compare-expect-values
178 (suitename testlist fun
&optional continue
)
179 "Run the regression tests for expected values comparison."
180 (regression-test-loop
181 suitename
'regression-compare-values testlist fun continue
))