3 (defvar *in-middle-of-failure?
* t
)
6 (name *last-test-case-name
*)
7 (suite *last-testsuite-name
*)
8 (break-on-errors?
*test-break-on-errors?
*)
9 (break-on-failures?
*test-break-on-failures?
*)
11 (profile *profile-style
* profile-supplied?
)
12 (testsuite-initargs nil
))
13 "Run a single test-case in a testsuite. Will run the most recently
14 defined or run testcase unless the name and suite arguments are used
16 (assert suite nil
"Test suite could not be determined.")
17 (assert name nil
"Test-case could not be determined.")
18 (when profile-supplied?
19 (push profile testsuite-initargs
)
20 (push :profile testsuite-initargs
))
21 (let* ((*test-break-on-errors?
* break-on-errors?
)
22 (*test-break-on-failures?
* break-on-failures?
))
24 (setf result
(make-test-result
25 suite
:single
:testsuite-initargs testsuite-initargs
)))
27 (let ((*current-test-case-name
* (find-test-case suite name
:errorp t
))
28 (*test-result
* result
))
29 (do-testing-in-environment
32 (run-test-internal *current-test
* *current-test-case-name
* result
))))
33 (setf *test-result
* result
)
34 (setf *last-test-case-name
* (find-test-case suite name
)
35 *last-testsuite-name
* suite
))))
37 (defun do-testing-in-environment (suite-name result fn
)
39 (*current-testsuite-name
* suite-name
))
44 (handler-bind ((warning #'muffle-warning
)
47 (excl:interrupt-signal
50 (cancel-testing :interrupt
)))
53 (handle-error-while-testing
54 condition
'testsuite-error suite-name result
)
58 (handle-error-while-testing
59 condition
'testsuite-serious-condition
62 (setf (current-step result
) :create
)
63 (setf suite
(make-testsuite
64 suite-name
(testsuite-initargs result
)))
65 (let ((*current-test
* suite
))
67 (let ((*lift-equality-test
* (equality-test suite
)))
68 (%start-test-suite
(type-of suite
) result
)
69 (testsuite-setup suite result
)
70 (do-testing suite result fn
)
73 (testsuite-teardown suite result
))))
74 (ensure-failed (condition)
75 :test
(lambda (c) (declare (ignore c
)) *in-middle-of-failure?
*)
77 'testsuite-failure result suite-name
78 *current-test-case-name
* condition
))
80 :report
(lambda (s) (format s
"Re-run test-suite ~a"
81 *current-testsuite-name
*))
84 :report
(lambda (s) (format s
"Skip rest of test-suite ~a"
85 *current-testsuite-name
*))
90 (defmethod do-testing ((suite test-mixin
) result fn
)
94 (defun run-tests (&rest args
&key
96 (break-on-errors?
*test-break-on-errors?
*)
97 (break-on-failures?
*test-break-on-failures?
*)
99 (dribble *lift-dribble-pathname
*)
100 (report-pathname *lift-report-pathname
*)
101 (profile *profile-style
* profile-supplied?
)
102 (skip-tests *skip-tests
*)
104 (do-children?
*test-run-subsuites?
*)
105 (testsuite-initargs nil
)
108 "Run all of the tests in a suite."
110 (let ((args-copy (copy-list args
)))
112 (remf args
:break-on-errors?
)
113 (remf args
:break-on-failures?
)
114 (remf args
:run-setup
)
117 (remf args
:skip-tests
)
118 (remf args
:report-pathname
)
119 (remf args
:do-children?
)
120 (remf args
:testsuite-initargs
)
122 (when profile-supplied?
123 (push profile testsuite-initargs
)
124 (push :profile testsuite-initargs
))
125 (let* ((*lift-report-pathname
*
126 (cond ((null report-pathname
) nil
)
127 ((eq report-pathname t
)
128 (report-summary-pathname))
131 (*test-run-subsuites?
* do-children?
)
132 (*skip-tests
* (canonize-skip-tests skip-tests
))
133 (*print-readably
* nil
)
134 (report-pathname *lift-report-pathname
*))
135 (when report-pathname
136 (ensure-directories-exist report-pathname
))
137 (cond ((and suite config
)
138 (error "Specify either configuration file or test suite
143 (apply #'make-test-result config
:multiple
144 :testsuite-initargs testsuite-initargs
146 (when report-pathname
147 (write-log-header report-pathname result args-copy
))
148 (let* ((*test-result
* result
))
149 (setf result
(run-tests-from-file config
))))
150 ((or suite
(setf suite
*last-testsuite-name
*))
153 (apply #'make-test-result suite
154 :multiple
:testsuite-initargs testsuite-initargs
156 (setf (testsuite-initargs result
) testsuite-initargs
)
157 (when report-pathname
158 (write-log-header report-pathname result args-copy
))
159 (let* ((*test-break-on-errors?
* break-on-errors?
)
160 (*test-break-on-failures?
* break-on-failures?
)
161 (*test-result
* result
)
166 :if-does-not-exist
:create
167 :if-exists
*lift-if-dribble-exists
*)))
168 (*lift-standard-output
*
170 *lift-standard-output
* dribble-stream
))
171 (*standard-output
* *lift-standard-output
*)
172 (*error-output
* (maybe-add-dribble
173 *error-output
* dribble-stream
))
174 (*debug-io
* (maybe-add-dribble
175 *debug-io
* dribble-stream
))
176 (*lift-debug-output
* (maybe-add-dribble
177 *lift-debug-output
* dribble-stream
)))
180 (run-tests-internal suite result
)
181 (cancel-testing (&optional
(result *test-result
*))
182 :report
(lambda (stream)
183 (format stream
"Cancel testing of ~a"
184 *current-testsuite-name
*))
185 (declare (ignore result
))
189 (close dribble-stream
)))
191 (setf (tests-run result
) (reverse (tests-run result
)))
192 (when report-pathname
193 (write-log-footer report-pathname result
))
196 (error "There is not a current test suite and neither suite
197 nor configuration file options were specified.")))))
198 (setf *test-result
* result
)))
200 (defun run-tests-internal (suite-name result
)
201 (dolist (suite-name (if *test-run-subsuites?
*
202 (collect-testsuites suite-name
)
204 (do-testing-in-environment
207 (testsuite-run *current-test
* result
)))
208 (setf *test-result
* result
)))
210 (defun testsuite-run (testsuite result
)
211 "Run the cases in `testsuite`"
212 (let* ((methods (testsuite-methods testsuite
))
213 (suite-name (class-name (class-of testsuite
)))
214 (*current-testsuite-name
* suite-name
)
216 (cond ((skip-test-suite-children-p result suite-name
)
217 (skip-testsuite result suite-name
))
219 (unless (start-time result
)
220 (setf (start-time result
) (get-test-real-time)
221 (start-time-universal result
) (get-universal-time)))
223 (loop for method in methods do
226 (write-log-test-start :save suite-name method
227 :stream
*lift-report-pathname
*)
229 (if (skip-test-case-p result suite-name method
)
230 `(:problem
,(skip-test-case
231 result suite-name method
))
232 (run-test-internal testsuite method result
))))
233 (when *lift-report-pathname
*
235 :save suite-name method data
236 :stream
*lift-report-pathname
*))))
237 (setf (end-time result
) (get-universal-time)))))
238 (setf *last-testsuite-name
* suite-name
)))
240 (defmethod do-test ((suite test-mixin
) name result
)
241 (declare (ignore result
))
242 (let* ((suite-name (class-name (class-of suite
)))
243 (fn (gethash name
(test-name->methods suite-name
))))
246 (error "expected to find ~a test for ~a but didn't" name suite-name
))))
248 (defun run-test-internal (suite test-case-name result
)
249 (let* ((result-pushed? nil
)
250 (suite-name (class-name (class-of suite
)))
251 (*current-test-case-name
* test-case-name
)
252 (*current-testsuite-name
* suite-name
)
254 (current-condition nil
))
255 (set-test-case-options suite-name test-case-name
)
256 (loop for case in
(ensure-list
257 (test-case-option suite-name test-case-name
:depends-on
))
258 unless
(test-case-tested-p suite-name case
) do
259 (run-test-internal suite case result
))
260 (flet ((maybe-push-result ()
261 (let ((datum (list suite-name test-case-name
(test-data suite
))))
262 (cond ((null result-pushed?
)
263 (setf result-pushed? t
)
264 (push datum
(tests-run result
)))
267 (setf (first (tests-run result
)) datum
))))))
268 (%start-test-case test-case-name result
)
272 (handler-bind ((warning #'muffle-warning
)
275 (excl:interrupt-signal
278 (cancel-testing :interrupt
)))
281 (handle-error-while-testing
282 condition
'test-error suite-name result
)
286 (handle-error-while-testing
287 condition
'test-serious-condition
292 (setf (current-method suite
) test-case-name
)
293 (record-start-times result suite
)
297 (setf (current-step result
) :testing
)
298 (multiple-value-bind (result measures error-condition
)
299 (while-measuring (t measure-space measure-seconds
)
300 (do-test suite test-case-name result
))
301 (declare (ignore result
))
302 (setf error error-condition
)
303 (destructuring-bind (space seconds
) measures
304 (setf (getf (test-data suite
) :seconds
) seconds
305 (getf (test-data suite
) :conses
) space
)))
308 (check-for-surprises suite-name test-case-name
))
311 (when (run-teardown-p suite
:test-case
)
312 (test-case-teardown suite result
))
313 (record-end-times result suite
))
315 (ensure-failed (condition)
316 :test
(lambda (c) (declare (ignore c
))
317 *in-middle-of-failure?
*)
319 'test-failure result suite-name
320 *current-test-case-name
* condition
)
321 (setf current-condition condition
)
322 (if (and *test-break-on-failures?
*
323 (not (failure-okay-p suite-name test-case-name
)))
324 (let ((*in-middle-of-failure?
* nil
))
325 (invoke-debugger current-condition
))
329 :report
(lambda (s) (format s
"Skip test-case ~a"
330 *current-test-case-name
*))
332 (test-failed (condition)
333 :test
(lambda (c) (declare (ignore c
))
334 *in-middle-of-failure?
*)
335 (setf current-condition condition
)
338 :report
(lambda (s) (format s
"Re-run test-case ~a"
339 *current-test-case-name
*))
343 (maybe-push-result)))
344 (when *test-print-test-case-names
*
345 (when (not (eq *test-print-test-case-names
* :brief
))
346 (format *lift-debug-output
* "~40T"))
347 (print-lift-message "~a"
348 (result-summary-tag (getf (test-data suite
) :problem
)
349 *test-print-test-case-names
*)))
350 (setf *current-test-case-name
* test-case-name
)
351 (setf *test-result
* result
)
352 (third (first (tests-run result
))))
354 (defun handle-error-while-testing (condition error-class suite-name result
)
355 (let ((*in-middle-of-failure?
* nil
))
357 error-class result suite-name
358 *current-test-case-name
* condition
359 :backtrace
(get-backtrace condition
))
360 (when (and *test-break-on-errors?
*
361 (not (error-okay-p *current-testsuite-name
* *current-test-case-name
*)))
362 (invoke-debugger condition
))))
364 (defun maybe-add-dribble (stream dribble-stream
)
366 (values (make-broadcast-stream stream dribble-stream
) t
)
367 (values stream nil
)))