clucumber 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +4 -9
- data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
- data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
- data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
- data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
- data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
- data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
- data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
- data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
- data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
- data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
- data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
- data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
- data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
- data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
- data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
- data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
- data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
- data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
- data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
- data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
- data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
- data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
- data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
- data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
- data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
- data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
- data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
- data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
- data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
- data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
- data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
- data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
- data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
- data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
- data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
- data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
- data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
- data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
- data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
- data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
- data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
- data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
- data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
- data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
- data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
- data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
- data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
- data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
- data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
- data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
- data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
- data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
- data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
- data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
- data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
- data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
- data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
- data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
- data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
- data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
- data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
- data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
- data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
- data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
- data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
- data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
- data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
- data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
- data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
- data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
- data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
- data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
- data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
- data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
- data/lib/clucumber/vendor/lift/lift.asd +77 -0
- data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
- data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
- data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
- data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
- data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
- data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
- data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
- data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
- data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
- data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
- data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
- data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
- data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
- data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
- data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
- data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
- data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
- data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
- data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
- data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
- data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
- data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
- data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
- data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
- data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
- data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
- data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
- data/lib/clucumber/vendor/usocket/package.lisp +82 -0
- data/lib/clucumber/vendor/usocket/server.lisp +45 -0
- data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
- data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
- data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
- data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
- data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
- data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
- data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
- data/lib/clucumber.rb +29 -7
- metadata +151 -5
@@ -0,0 +1,2383 @@
|
|
1
|
+
;;;-*- Mode: Lisp; Package: lift -*-
|
2
|
+
|
3
|
+
(in-package #:lift)
|
4
|
+
|
5
|
+
;;; ---------------------------------------------------------------------------
|
6
|
+
;;; global environment thingies
|
7
|
+
;;; ---------------------------------------------------------------------------
|
8
|
+
|
9
|
+
(defparameter *make-testsuite-arguments*
|
10
|
+
'(:run-setup :test-slot-names :equality-test :log-file :timeout
|
11
|
+
:default-initargs :profile :expected-failure :expected-error))
|
12
|
+
|
13
|
+
(defvar *current-testsuite-name* nil)
|
14
|
+
(defvar *current-test-case-name* nil)
|
15
|
+
|
16
|
+
(defvar *test-is-being-defined?* nil)
|
17
|
+
(defvar *test-is-being-compiled?* nil)
|
18
|
+
(defvar *test-is-being-loaded?* nil)
|
19
|
+
(defvar *test-is-being-executed?* nil)
|
20
|
+
|
21
|
+
(defvar *test-maximum-error-count* nil
|
22
|
+
"The maximum numbers of errors to allow during a [run-tests][].
|
23
|
+
|
24
|
+
If `*test-maximum-error-count*` is nil, then a call to run-tests
|
25
|
+
will continue regardless of the number of errors. If it a positive
|
26
|
+
integer, then run-tests will stop as soon as the number of test-errors
|
27
|
+
if greater than or equal to its value. Setting this to some small
|
28
|
+
value can help prevent running lengthly test-suites when there are many
|
29
|
+
errors. See also [\\*test-maximum-failure-count\\*][].")
|
30
|
+
|
31
|
+
(defvar *test-maximum-failure-count* nil
|
32
|
+
"The maximum numbers of failures to allow during a [run-tests][].
|
33
|
+
|
34
|
+
If `*test-maximum-failure-count*` is nil, then a call to run-tests
|
35
|
+
will continue regardless of the number of failures. If it a positive
|
36
|
+
integer, then run-tests will stop as soon as the number of test-failures
|
37
|
+
if greater than or equal to its value. Setting this to some small
|
38
|
+
value can help prevent running lengthly test-suites when there are many
|
39
|
+
failures. See also [\\*test-maximum-error-count\\*][].")
|
40
|
+
|
41
|
+
(defvar *lift-debug-output* *debug-io*
|
42
|
+
"Messages from LIFT will be sent to this stream. It can set to nil or
|
43
|
+
to an output stream. It defaults to *debug-io*.")
|
44
|
+
|
45
|
+
(defvar *test-maximum-time* 2
|
46
|
+
"Maximum number of seconds a process test is allowed to run before we give up.")
|
47
|
+
|
48
|
+
(defvar *test-break-on-errors?* nil)
|
49
|
+
(defvar *test-break-on-failures?* nil)
|
50
|
+
(defvar *test-do-children?* t)
|
51
|
+
(defparameter *test-ignore-warnings?* nil
|
52
|
+
"If true, LIFT will not cause a test to fail if a warning occurs while
|
53
|
+
the test is running. Note that this may interact oddly with ensure-warning.")
|
54
|
+
(defparameter *test-print-when-defined?* nil)
|
55
|
+
(defparameter *test-evaluate-when-defined?* t)
|
56
|
+
(defparameter *test-scratchpad* nil
|
57
|
+
"A place to put things. This is set to nil before every test.")
|
58
|
+
(defparameter *test-notepad* nil
|
59
|
+
"Another place to put things \(see {ref *test-scratchpad*}\).")
|
60
|
+
|
61
|
+
(defparameter *lift-equality-test* 'equal
|
62
|
+
"The function used in ensure-same to test if two things are equal. If metatilities is loaded, then you might want to use samep.")
|
63
|
+
|
64
|
+
(defvar *test-describe-if-not-successful?* nil
|
65
|
+
;; Was t, but this behavior was extremely annoying since each
|
66
|
+
;; time a test-restul appears in a stack backtrace it is printed
|
67
|
+
;; over many unstructured lines.
|
68
|
+
"If true, then a complete test description is printed when there are any test warnings or failures. Otherwise, one would need to explicity call describe.")
|
69
|
+
|
70
|
+
(defvar *test-print-length* :follow-print
|
71
|
+
"The print-length in effect when LIFT prints test results. It works exactly like `*print-length*` except that it can also take on the value :follow-print. In this case, it will be set to the value of `*print-length*`.")
|
72
|
+
(defvar *test-print-level* :follow-print
|
73
|
+
"The print-level in effect when LIFT prints test results. It works exactly like `*print-level*` except that it can also take on the value :follow-print. In this case, it will be set to whatever `*print-level*` is.")
|
74
|
+
|
75
|
+
(defvar *test-print-testsuite-names* t
|
76
|
+
"If true, LIFT will print the name of each test suite to *debug-io* before it begins to run the suite. See also: *test-print-test-case-names*.")
|
77
|
+
|
78
|
+
(defvar *test-print-test-case-names* nil
|
79
|
+
"If true, LIFT will print the name of each test-case before it runs. See also: *test-print-testsuite-names*.")
|
80
|
+
|
81
|
+
(defparameter *lift-tests-to-skip* nil
|
82
|
+
"A lift of test-suites and (testsuite test-case) pairs that LIFT will ignore
|
83
|
+
during calls to run-tests.")
|
84
|
+
|
85
|
+
(defvar *test-result* nil
|
86
|
+
"Set to the most recent test result by calls to run-test or run-tests.")
|
87
|
+
|
88
|
+
(defvar *test-environment* nil)
|
89
|
+
|
90
|
+
(defvar *test-metadata* (list)
|
91
|
+
"A place for LIFT to put stuff.")
|
92
|
+
|
93
|
+
(defvar *current-test* nil
|
94
|
+
"The current testsuite.")
|
95
|
+
|
96
|
+
(defvar *testsuite-test-count* nil
|
97
|
+
"Temporary variable used to 'communicate' between deftestsuite and addtest.")
|
98
|
+
|
99
|
+
(defvar *lift-dribble-pathname* nil
|
100
|
+
"If bound, then test output from run-tests will be sent to this file in
|
101
|
+
in addition to *lift-standard-output*. It can be set to nil or to a pathname.")
|
102
|
+
|
103
|
+
(defvar *lift-report-pathname* nil
|
104
|
+
"If bound to a pathname or stream, then a summary of test information will
|
105
|
+
be written to it for later processing. It can be set to:
|
106
|
+
|
107
|
+
* `nil` - generate no output
|
108
|
+
* pathname designator - send output to this pathname
|
109
|
+
* `t` - send output to a pathname constructed from the name of the system
|
110
|
+
being tested (this only works if ASDF is being used to test the system).
|
111
|
+
|
112
|
+
As an example of the last case, if LIFT is testing a system named ...
|
113
|
+
")
|
114
|
+
|
115
|
+
(defvar *lift-standard-output* *standard-output*
|
116
|
+
"Output from tests will be sent to this stream. If can set to nil or
|
117
|
+
to an output stream. It defaults to *standard-output*.")
|
118
|
+
|
119
|
+
(defvar *lift-if-dribble-exists* :append
|
120
|
+
"Specifies what to do to any existing file at *lift-dribble-pathname*. It
|
121
|
+
can be :supersede, :append, or :error.")
|
122
|
+
|
123
|
+
(defvar *test-show-expected-p* t)
|
124
|
+
|
125
|
+
(defvar *test-show-details-p* t)
|
126
|
+
|
127
|
+
(defvar *test-show-code-p* t)
|
128
|
+
|
129
|
+
;;; ---------------------------------------------------------------------------
|
130
|
+
;;; Error messages and warnings
|
131
|
+
;;; ---------------------------------------------------------------------------
|
132
|
+
|
133
|
+
(defparameter +lift-test-name-not-supplied-with-test-class+
|
134
|
+
"if you specify a test-class, you must also specify a test-name.")
|
135
|
+
|
136
|
+
(defparameter +lift-test-class-not-found+
|
137
|
+
"test class '~S' not found.")
|
138
|
+
|
139
|
+
(defparameter +lift-confused-about-arguments+
|
140
|
+
"I'm confused about what you said?!")
|
141
|
+
|
142
|
+
(defparameter +lift-no-current-test-class+
|
143
|
+
"There is no current-test-class to use as a default.")
|
144
|
+
|
145
|
+
(defparameter +lift-could-not-find-test+
|
146
|
+
"Could not find test: ~S.~S")
|
147
|
+
|
148
|
+
(defparameter +run-tests-null-test-case+
|
149
|
+
"There is no current testsuite (possibly because
|
150
|
+
none have been defined yet?). You can specify the
|
151
|
+
testsuite to test by evaluating (run-tests :suite <suitename>).")
|
152
|
+
|
153
|
+
(defparameter +lift-unable-to-parse-test-name-and-class+
|
154
|
+
"")
|
155
|
+
|
156
|
+
|
157
|
+
;;; ---------------------------------------------------------------------------
|
158
|
+
;;; test conditions
|
159
|
+
;;; ---------------------------------------------------------------------------
|
160
|
+
|
161
|
+
(define-condition lift-compile-error (error)
|
162
|
+
((msg :initform ""
|
163
|
+
:reader msg
|
164
|
+
:initarg :lift-message))
|
165
|
+
(:report (lambda (c s)
|
166
|
+
(format s "Compile error: '~S'" (msg c)))))
|
167
|
+
|
168
|
+
(define-condition testsuite-not-defined (lift-compile-error)
|
169
|
+
((testsuite-name :reader testsuite-name
|
170
|
+
:initarg :testsuite-name))
|
171
|
+
(:report (lambda (c s)
|
172
|
+
(format s "Test class ~A not defined before it was used."
|
173
|
+
(testsuite-name c)))))
|
174
|
+
|
175
|
+
(define-condition testsuite-ambiguous (lift-compile-error)
|
176
|
+
((testsuite-name :reader testsuite-name
|
177
|
+
:initarg :testsuite-name)
|
178
|
+
(possible-matches :reader possible-matches
|
179
|
+
:initarg :possible-matches))
|
180
|
+
(:report
|
181
|
+
(lambda (c s)
|
182
|
+
(format s "There are several test suites named ~s: they are ~{~s~^, ~}"
|
183
|
+
(testsuite-name c)
|
184
|
+
(possible-matches c)))))
|
185
|
+
|
186
|
+
(define-condition test-case-not-defined (lift-compile-error)
|
187
|
+
((testsuite-name :reader testsuite-name
|
188
|
+
:initarg :testsuite-name)
|
189
|
+
(test-case-name :reader test-case-name
|
190
|
+
:initarg :test-case-name))
|
191
|
+
(:report (lambda (c s)
|
192
|
+
(format s "Testsuite ~s has no test-case named ~s."
|
193
|
+
(testsuite-name c)
|
194
|
+
(test-case-name c)))))
|
195
|
+
|
196
|
+
(define-condition test-case-ambiguous (lift-compile-error)
|
197
|
+
((testsuite-name :reader testsuite-name
|
198
|
+
:initarg :testsuite-name)
|
199
|
+
(test-case-name :reader test-case-name
|
200
|
+
:initarg :test-case-name)
|
201
|
+
(possible-matches :reader possible-matches
|
202
|
+
:initarg possible-matches))
|
203
|
+
(:report
|
204
|
+
(lambda (c s)
|
205
|
+
(format s "There are several test cases named ~s.~s: they are ~{~s~^, ~}"
|
206
|
+
(testsuite-name c)
|
207
|
+
(test-case-name c)
|
208
|
+
(possible-matches c)))))
|
209
|
+
|
210
|
+
(define-condition test-condition (warning)
|
211
|
+
((message :initform ""
|
212
|
+
:initarg :message
|
213
|
+
:accessor message))
|
214
|
+
(:report (lambda (c s)
|
215
|
+
(when (message c)
|
216
|
+
(format s "~%~A" (message c))))))
|
217
|
+
|
218
|
+
(define-condition test-timeout-condition (test-condition)
|
219
|
+
((maximum-time :initform *test-maximum-time*
|
220
|
+
:accessor maximum-time
|
221
|
+
:initarg :maximum-time))
|
222
|
+
(:report (lambda (c s)
|
223
|
+
(format s "Test ran out of time (longer than ~S-second~:P)"
|
224
|
+
(maximum-time c)))))
|
225
|
+
|
226
|
+
(define-condition ensure-failed-error (test-condition)
|
227
|
+
((assertion :initform ""
|
228
|
+
:accessor assertion
|
229
|
+
:initarg :assertion))
|
230
|
+
(:report (lambda (c s)
|
231
|
+
(format s "Ensure failed: ~S ~@[(~a)~]"
|
232
|
+
(assertion c) (message c)))))
|
233
|
+
|
234
|
+
(define-condition ensure-null-failed-error (ensure-failed-error)
|
235
|
+
((value :initform ""
|
236
|
+
:accessor value
|
237
|
+
:initarg :value)
|
238
|
+
(assertion :initform ""
|
239
|
+
:accessor assertion
|
240
|
+
:initarg :assertion))
|
241
|
+
(:report (lambda (c s)
|
242
|
+
(format s "Ensure null failed: ~s evaluates to ~s ~@[(~a)~]"
|
243
|
+
(assertion c) (value c) (message c)))))
|
244
|
+
|
245
|
+
(define-condition ensure-expected-condition (test-condition)
|
246
|
+
((expected-condition-type
|
247
|
+
:initform nil
|
248
|
+
:accessor expected-condition-type
|
249
|
+
:initarg :expected-condition-type)
|
250
|
+
(the-condition
|
251
|
+
:initform nil
|
252
|
+
:accessor the-condition
|
253
|
+
:initarg :the-condition))
|
254
|
+
(:report (lambda (c s)
|
255
|
+
(let ((the-condition (the-condition c)))
|
256
|
+
(format s "Expected ~S but got ~S~@[:~_ ~A~]"
|
257
|
+
(expected-condition-type c)
|
258
|
+
(type-of the-condition)
|
259
|
+
(and (typep the-condition 'condition)
|
260
|
+
the-condition))))))
|
261
|
+
|
262
|
+
(define-condition ensure-expected-no-warning-condition (test-condition)
|
263
|
+
((the-condition
|
264
|
+
:initform nil
|
265
|
+
:accessor the-condition
|
266
|
+
:initarg :the-condition))
|
267
|
+
(:report (lambda (c s)
|
268
|
+
(format s "Expected no warnings but got ~S"
|
269
|
+
(the-condition c)))))
|
270
|
+
|
271
|
+
(define-condition failed-comparison-condition (test-condition)
|
272
|
+
((first-value :accessor first-value
|
273
|
+
:initarg :first-value)
|
274
|
+
(second-value :accessor second-value
|
275
|
+
:initarg :second-value)
|
276
|
+
(test :accessor test
|
277
|
+
:initarg :test)))
|
278
|
+
|
279
|
+
(define-condition ensure-not-same (failed-comparison-condition)
|
280
|
+
()
|
281
|
+
(:report (lambda (c s)
|
282
|
+
(format s "Ensure-same: ~S is not ~S to ~S~@[ (~a)~]"
|
283
|
+
(first-value c) (test c) (second-value c)
|
284
|
+
(message c)))))
|
285
|
+
|
286
|
+
(define-condition ensure-same (failed-comparison-condition)
|
287
|
+
()
|
288
|
+
(:report (lambda (c s)
|
289
|
+
(format s "Ensure-different: ~S is ~S to ~S~@[ (~a)~]"
|
290
|
+
(first-value c) (test c) (second-value c)
|
291
|
+
(message c)))))
|
292
|
+
|
293
|
+
(define-condition ensure-cases-failure (test-condition)
|
294
|
+
((total :initarg :total :initform 0)
|
295
|
+
(problems :initarg :problems :initform nil))
|
296
|
+
(:report (lambda (condition stream)
|
297
|
+
(format
|
298
|
+
stream
|
299
|
+
"Ensure-cases: ~d out of ~d cases failed. Failing cases are:"
|
300
|
+
(length (slot-value condition 'problems))
|
301
|
+
(slot-value condition 'total))
|
302
|
+
(format
|
303
|
+
stream
|
304
|
+
"~&~@< ~@;~{~% ~{~20s ~3,8@t~a~}~^, ~}~:>"
|
305
|
+
(slot-value condition 'problems)))))
|
306
|
+
|
307
|
+
(define-condition unexpected-success-failure (test-condition)
|
308
|
+
((expected :reader expected :initarg :expected)
|
309
|
+
(expected-more :reader expected-more :initarg :expected-more))
|
310
|
+
(:report (lambda (c s)
|
311
|
+
(format s "Test succeeded but we expected ~s (~s)"
|
312
|
+
(expected c)
|
313
|
+
(expected-more c)))))
|
314
|
+
|
315
|
+
(defun build-lift-error-message (context message &rest arguments)
|
316
|
+
(format nil "~A: ~A"
|
317
|
+
context
|
318
|
+
(apply #'format nil message arguments)))
|
319
|
+
|
320
|
+
(defun signal-lift-error (context message &rest arguments)
|
321
|
+
(let ((c (make-condition
|
322
|
+
'lift-compile-error
|
323
|
+
:lift-message (apply #'build-lift-error-message
|
324
|
+
context message arguments))))
|
325
|
+
(unless (signal c)
|
326
|
+
(error c))))
|
327
|
+
|
328
|
+
(defun report-lift-error (context message &rest arguments)
|
329
|
+
(format *debug-io* "~&~A."
|
330
|
+
(apply #'build-lift-error-message context message arguments))
|
331
|
+
(values))
|
332
|
+
|
333
|
+
(defun lift-report-condition (c)
|
334
|
+
(format *debug-io* "~&~A." c))
|
335
|
+
|
336
|
+
(defmacro ensure (predicate &key report arguments)
|
337
|
+
"If ensure's `predicate` evaluates to false, then it will generate a
|
338
|
+
test failure. You can use the `report` and `arguments` keyword parameters
|
339
|
+
to customize the report generated in test results. For example:
|
340
|
+
|
341
|
+
(ensure (= 23 12)
|
342
|
+
:report \"I hope ~a does not = ~a\"
|
343
|
+
:arguments (12 23))
|
344
|
+
|
345
|
+
will generate a message like
|
346
|
+
|
347
|
+
Warning: Ensure failed: (= 23 12) (I hope 12 does not = 23)
|
348
|
+
"
|
349
|
+
(let ((gpredicate (gensym)))
|
350
|
+
`(let ((,gpredicate ,predicate))
|
351
|
+
(if ,gpredicate
|
352
|
+
(values ,gpredicate)
|
353
|
+
(let ((condition (make-condition
|
354
|
+
'ensure-failed-error
|
355
|
+
:assertion ',predicate
|
356
|
+
,@(when report
|
357
|
+
`(:message
|
358
|
+
(format nil ,report ,@arguments))))))
|
359
|
+
(if (find-restart 'ensure-failed)
|
360
|
+
(invoke-restart 'ensure-failed condition)
|
361
|
+
(warn condition)))))))
|
362
|
+
|
363
|
+
(defmacro ensure-null (predicate &key report arguments)
|
364
|
+
"If ensure-null's `predicate` evaluates to true, then it will generate a
|
365
|
+
test failure. You can use the `report` and `arguments` keyword parameters
|
366
|
+
to customize the report generated in test results. See [ensure][] for more
|
367
|
+
details."
|
368
|
+
(let ((g (gensym)))
|
369
|
+
`(let ((,g ,predicate))
|
370
|
+
(if (null ,g)
|
371
|
+
t
|
372
|
+
(let ((condition (make-condition 'ensure-null-failed-error
|
373
|
+
:value ,g
|
374
|
+
:assertion ',predicate
|
375
|
+
,@(when report
|
376
|
+
`(:message (format nil ,report ,@arguments))))))
|
377
|
+
(if (find-restart 'ensure-failed)
|
378
|
+
(invoke-restart 'ensure-failed condition)
|
379
|
+
(warn condition)))))))
|
380
|
+
|
381
|
+
(defmacro ensure-condition (condition &body body)
|
382
|
+
"This macro is used to make sure that body really does produce condition."
|
383
|
+
(setf condition (remove-leading-quote condition))
|
384
|
+
(destructuring-bind (condition &key report arguments)
|
385
|
+
(if (consp condition) condition (list condition))
|
386
|
+
(let ((g (gensym)))
|
387
|
+
`(let ((,g nil))
|
388
|
+
(unwind-protect
|
389
|
+
(handler-case
|
390
|
+
(progn ,@body)
|
391
|
+
(,condition (cond)
|
392
|
+
(declare (ignore cond)) (setf ,g t))
|
393
|
+
(condition (cond)
|
394
|
+
(setf ,g t)
|
395
|
+
(let ((c (make-condition
|
396
|
+
'ensure-expected-condition
|
397
|
+
:expected-condition-type ',condition
|
398
|
+
:the-condition cond
|
399
|
+
,@(when report
|
400
|
+
`(:message
|
401
|
+
(format nil ,report ,arguments))))))
|
402
|
+
(if (find-restart 'ensure-failed)
|
403
|
+
(invoke-restart 'ensure-failed c)
|
404
|
+
(warn c)))))
|
405
|
+
(when (not ,g)
|
406
|
+
(if (find-restart 'ensure-failed)
|
407
|
+
(invoke-restart
|
408
|
+
'ensure-failed
|
409
|
+
(make-condition
|
410
|
+
'ensure-expected-condition
|
411
|
+
:expected-condition-type ',condition
|
412
|
+
:the-condition nil
|
413
|
+
,@(when report
|
414
|
+
`(:message (format nil ,report ,arguments)))))
|
415
|
+
(warn "Ensure-condition didn't get the condition it expected."))))))))
|
416
|
+
|
417
|
+
(defmacro ensure-no-warning (&body body)
|
418
|
+
"This macro is used to make sure that body produces no warning."
|
419
|
+
(let ((g (gensym))
|
420
|
+
(gcondition (gensym)))
|
421
|
+
`(let ((,g nil)
|
422
|
+
(,gcondition nil))
|
423
|
+
(unwind-protect
|
424
|
+
(handler-case
|
425
|
+
(progn ,@body)
|
426
|
+
(warning (c)
|
427
|
+
(setf ,gcondition c ,g t)))
|
428
|
+
(when ,g
|
429
|
+
(let ((c (make-condition
|
430
|
+
'ensure-expected-no-warning-condition
|
431
|
+
:the-condition ,gcondition)))
|
432
|
+
(if (find-restart 'ensure-failed)
|
433
|
+
(invoke-restart 'ensure-failed c)
|
434
|
+
(warn c))))))))
|
435
|
+
|
436
|
+
(defmacro ensure-warning (&body body)
|
437
|
+
"Ensure-warning evaluates its body. If the body does *not* signal a
|
438
|
+
warning, then ensure-warning will generate a test failure."
|
439
|
+
`(ensure-condition warning ,@body))
|
440
|
+
|
441
|
+
(defmacro ensure-error (&body body)
|
442
|
+
"Ensure-error evaluates its body. If the body does *not* signal an
|
443
|
+
error, then ensure-error will generate a test failure."
|
444
|
+
`(ensure-condition error ,@body))
|
445
|
+
|
446
|
+
(defmacro ensure-same
|
447
|
+
(form values &key (test nil test-specified-p)
|
448
|
+
(report nil) (arguments nil)
|
449
|
+
(ignore-multiple-values? nil))
|
450
|
+
"Ensure same compares value-or-values-1 value-or-values-2 or
|
451
|
+
each value of value-or-values-1 value-or-values-2 (if they are
|
452
|
+
multiple values) using test. If a problem is encountered
|
453
|
+
ensure-same raises a warning which uses report as a format string
|
454
|
+
and arguments as arguments to that string (if report and arguments
|
455
|
+
are supplied). If ensure-same is used within a test, a test failure
|
456
|
+
is generated instead of a warning"
|
457
|
+
(%build-ensure-comparison form values 'unless
|
458
|
+
test test-specified-p report arguments
|
459
|
+
ignore-multiple-values?))
|
460
|
+
|
461
|
+
(defmacro ensure-different
|
462
|
+
(form values &key (test nil test-specified-p)
|
463
|
+
(report nil) (arguments nil)
|
464
|
+
(ignore-multiple-values? nil))
|
465
|
+
"Ensure-different compares value-or-values-1 value-or-values-2 or each value of value-or-values-1 and value-or-values-2 (if they are multiple values) using test. If any comparison returns true, then ensure-different raises a warning which uses report as a format string and `arguments` as arguments to that string (if report and `arguments` are supplied). If ensure-different is used within a test, a test failure is generated instead of a warning"
|
466
|
+
(%build-ensure-comparison form values 'when
|
467
|
+
test test-specified-p report arguments
|
468
|
+
ignore-multiple-values?))
|
469
|
+
|
470
|
+
(defun %build-ensure-comparison
|
471
|
+
(form values guard-fn test test-specified-p report arguments
|
472
|
+
ignore-multiple-values?)
|
473
|
+
(setf test (remove-leading-quote test))
|
474
|
+
(when (and (consp test)
|
475
|
+
(eq (first test) 'function))
|
476
|
+
(setf test (second test)))
|
477
|
+
(let ((gblock (gensym "block-"))
|
478
|
+
(ga (gensym "a-"))
|
479
|
+
(gb (gensym "b-"))
|
480
|
+
(gtest (gensym "test-")))
|
481
|
+
`(block ,gblock
|
482
|
+
(flet ((,gtest (,ga ,gb)
|
483
|
+
(,@(cond (test-specified-p
|
484
|
+
(if (atom test)
|
485
|
+
(list test)
|
486
|
+
`(funcall ,test)))
|
487
|
+
(t
|
488
|
+
`(funcall *lift-equality-test*)))
|
489
|
+
,ga ,gb)))
|
490
|
+
(loop for value in (,(if ignore-multiple-values?
|
491
|
+
'list 'multiple-value-list) ,form)
|
492
|
+
for other-value in (,(if ignore-multiple-values?
|
493
|
+
'list 'multiple-value-list) ,values) do
|
494
|
+
(,guard-fn (,gtest value other-value)
|
495
|
+
(,(ecase guard-fn
|
496
|
+
(unless 'maybe-raise-not-same-condition)
|
497
|
+
(when 'maybe-raise-ensure-same-condition))
|
498
|
+
value other-value
|
499
|
+
,(if test-specified-p (list 'quote test) '*lift-equality-test*)
|
500
|
+
,report ,@arguments)
|
501
|
+
(return-from ,gblock nil))))
|
502
|
+
(values t))))
|
503
|
+
|
504
|
+
(defun maybe-raise-not-same-condition (value-1 value-2 test
|
505
|
+
report &rest arguments)
|
506
|
+
(let ((condition (make-condition 'ensure-not-same
|
507
|
+
:first-value value-1
|
508
|
+
:second-value value-2
|
509
|
+
:test test
|
510
|
+
:message (when report
|
511
|
+
(apply #'format nil
|
512
|
+
report arguments)))))
|
513
|
+
(if (find-restart 'ensure-failed)
|
514
|
+
(invoke-restart 'ensure-failed condition)
|
515
|
+
(warn condition))))
|
516
|
+
|
517
|
+
(defun maybe-raise-ensure-same-condition (value-1 value-2 test
|
518
|
+
report &rest arguments)
|
519
|
+
(let ((condition (make-condition 'ensure-same
|
520
|
+
:first-value value-1
|
521
|
+
:second-value value-2
|
522
|
+
:test test
|
523
|
+
:message (when report
|
524
|
+
(apply #'format nil
|
525
|
+
report arguments)))))
|
526
|
+
(if (find-restart 'ensure-failed)
|
527
|
+
(invoke-restart 'ensure-failed condition)
|
528
|
+
(warn condition))))
|
529
|
+
|
530
|
+
(defmacro ensure-cases ((&rest vars) (&rest cases) &body body)
|
531
|
+
(let ((case (gensym))
|
532
|
+
(total (gensym))
|
533
|
+
(problems (gensym))
|
534
|
+
(single-var-p (= (length vars) 1)))
|
535
|
+
`(let ((,problems nil) (,total 0))
|
536
|
+
(loop for ,case in ,cases do
|
537
|
+
(incf ,total)
|
538
|
+
(destructuring-bind ,vars ,(if single-var-p `(list ,case) case)
|
539
|
+
(restart-case
|
540
|
+
(progn ,@body)
|
541
|
+
(ensure-failed (cond)
|
542
|
+
(push (list ,case cond) ,problems)))))
|
543
|
+
(if ,problems
|
544
|
+
(let ((condition (make-condition
|
545
|
+
'ensure-cases-failure
|
546
|
+
:total ,total
|
547
|
+
:problems ,problems)))
|
548
|
+
(if (find-restart 'ensure-failed)
|
549
|
+
(invoke-restart 'ensure-failed condition)
|
550
|
+
(warn condition)))
|
551
|
+
;; return true if we're happy
|
552
|
+
t))))
|
553
|
+
|
554
|
+
|
555
|
+
;;; ---------------------------------------------------------------------------
|
556
|
+
;;; test-mixin
|
557
|
+
;;; ---------------------------------------------------------------------------
|
558
|
+
|
559
|
+
(defclass test-mixin ()
|
560
|
+
((name :initform nil :initarg :name :accessor name :reader testsuite-name)
|
561
|
+
(run-setup :reader run-setup :initarg :run-setup)
|
562
|
+
(done-setup? :initform nil :reader done-setup?)
|
563
|
+
(done-dynamics? :initform nil :reader done-dynamics?)
|
564
|
+
(test-slot-names :initform nil :initarg :test-slot-names
|
565
|
+
:reader test-slot-names)
|
566
|
+
(current-step :initform :created :accessor current-step)
|
567
|
+
(current-method :initform nil :accessor current-method)
|
568
|
+
(save-equality-test :initform nil :reader save-equality-test)
|
569
|
+
(log-file :initform nil :initarg :log-file :reader log-file)
|
570
|
+
(test-data :initform nil :accessor test-data)
|
571
|
+
(expected-failure-p :initform nil :initarg :expected-failure-p
|
572
|
+
:reader expected-failure-p)
|
573
|
+
(expected-error-p :initform nil :initarg :expected-error-p
|
574
|
+
:reader expected-error-p)
|
575
|
+
(expected-problem-p :initform nil :initarg :expected-problem-p
|
576
|
+
:reader expected-problem-p)
|
577
|
+
(suite-initargs
|
578
|
+
:initform nil
|
579
|
+
:accessor suite-initargs)
|
580
|
+
(profile
|
581
|
+
:initform nil
|
582
|
+
:initarg :profile
|
583
|
+
:accessor profile))
|
584
|
+
(:documentation "A test suite")
|
585
|
+
(:default-initargs
|
586
|
+
:run-setup :once-per-test-case))
|
587
|
+
|
588
|
+
(defclass test-result ()
|
589
|
+
((results-for :initform nil
|
590
|
+
:initarg :results-for
|
591
|
+
:accessor results-for)
|
592
|
+
(tests-run :initform nil :accessor tests-run)
|
593
|
+
(suites-run :initform nil :accessor suites-run)
|
594
|
+
(failures :initform nil :accessor failures)
|
595
|
+
(expected-failures :initform nil :accessor expected-failures)
|
596
|
+
(errors :initform nil :accessor errors)
|
597
|
+
(expected-errors :initform nil :accessor expected-errors)
|
598
|
+
(test-mode :initform :single :initarg :test-mode :accessor test-mode)
|
599
|
+
(test-interactive? :initform nil
|
600
|
+
:initarg :test-interactive? :accessor test-interactive?)
|
601
|
+
(real-start-time :initarg :real-start-time :reader real-start-time)
|
602
|
+
(start-time :accessor start-time :initform nil)
|
603
|
+
(end-time :accessor end-time)
|
604
|
+
(real-end-time :accessor real-end-time)
|
605
|
+
(real-start-time-universal
|
606
|
+
:initarg :real-start-time-universal :reader real-start-time-universal)
|
607
|
+
(start-time-universal :accessor start-time-universal :initform nil)
|
608
|
+
(end-time-universal :accessor end-time-universal)
|
609
|
+
(real-end-time-universal :accessor real-end-time-universal)
|
610
|
+
(properties :initform nil :accessor test-result-properties)
|
611
|
+
(tests-to-skip :initform nil
|
612
|
+
:initarg :tests-to-skip
|
613
|
+
:reader tests-to-skip
|
614
|
+
:writer %set-tests-to-skip))
|
615
|
+
(:documentation
|
616
|
+
"A `test-result` instance contains all of the information collectd by
|
617
|
+
LIFT during a test run.")
|
618
|
+
(:default-initargs
|
619
|
+
:test-interactive? *test-is-being-defined?*
|
620
|
+
:real-start-time (get-internal-real-time)
|
621
|
+
:real-start-time-universal (get-universal-time)
|
622
|
+
:tests-to-skip *lift-tests-to-skip*))
|
623
|
+
|
624
|
+
(defmethod initialize-instance :after
|
625
|
+
((result test-result) &key tests-to-skip)
|
626
|
+
(when tests-to-skip
|
627
|
+
(%set-tests-to-skip
|
628
|
+
(mapcar (lambda (datum)
|
629
|
+
(cond ((or (atom datum)
|
630
|
+
(= (length datum) 1))
|
631
|
+
(cons (find-testsuite datum) nil))
|
632
|
+
((= (length datum) 2)
|
633
|
+
(cons (find-testsuite (first datum))
|
634
|
+
(or (and (keywordp (second datum)) (second datum))
|
635
|
+
(find-test-case (find-testsuite (first datum))
|
636
|
+
(second datum)))))
|
637
|
+
(t
|
638
|
+
(warn "Unable to interpret skip datum ~a. Ignoring."
|
639
|
+
datum))))
|
640
|
+
tests-to-skip)
|
641
|
+
result)))
|
642
|
+
|
643
|
+
(defun test-result-property (result property &optional default)
|
644
|
+
(getf (test-result-properties result) property default))
|
645
|
+
|
646
|
+
(defun (setf test-result-property) (value result property)
|
647
|
+
(setf (getf (test-result-properties result) property) value))
|
648
|
+
|
649
|
+
(defun print-lift-message (message &rest args)
|
650
|
+
(apply #'format *lift-debug-output* message args)
|
651
|
+
(force-output *lift-debug-output*))
|
652
|
+
|
653
|
+
(defgeneric testsuite-setup (testsuite result)
|
654
|
+
(:documentation "Setup at the testsuite-level")
|
655
|
+
(:method ((testsuite test-mixin) (result test-result))
|
656
|
+
(values))
|
657
|
+
(:method :before ((testsuite test-mixin) (result test-result))
|
658
|
+
(when (and *test-print-testsuite-names*
|
659
|
+
(eq (test-mode result) :multiple))
|
660
|
+
(print-lift-message "~&Start: ~a" (type-of testsuite)))
|
661
|
+
(push (type-of testsuite) (suites-run result))
|
662
|
+
(setf (current-step testsuite) :testsuite-setup)))
|
663
|
+
|
664
|
+
(defgeneric testsuite-expects-error (testsuite)
|
665
|
+
(:documentation "Returns whether or not the testsuite as a whole expects an error.")
|
666
|
+
(:method ((testsuite test-mixin))
|
667
|
+
nil))
|
668
|
+
|
669
|
+
(defgeneric testsuite-expects-failure (testsuite)
|
670
|
+
(:documentation "Returns whether or not the testsuite as a whole expects to fail.")
|
671
|
+
(:method ((testsuite test-mixin))
|
672
|
+
nil))
|
673
|
+
|
674
|
+
(defgeneric testsuite-run (testsuite result)
|
675
|
+
(:documentation "Run the cases in this suite and it's children."))
|
676
|
+
|
677
|
+
(defgeneric testsuite-teardown (testsuite result)
|
678
|
+
(:documentation "Cleanup at the testsuite level.")
|
679
|
+
(:method ((testsuite test-mixin) (result test-result))
|
680
|
+
;; no-op
|
681
|
+
)
|
682
|
+
(:method :after ((testsuite test-mixin) (result test-result))
|
683
|
+
(setf (current-step testsuite) :testsuite-teardown
|
684
|
+
(real-end-time result) (get-internal-real-time)
|
685
|
+
(real-end-time-universal result) (get-universal-time))))
|
686
|
+
|
687
|
+
(defgeneric setup-test (testsuite)
|
688
|
+
(:documentation "Setup for a test-case. By default it does nothing."))
|
689
|
+
|
690
|
+
(defgeneric test-case-teardown (testsuite result)
|
691
|
+
(:documentation "Tear-down a test-case. By default it does nothing.")
|
692
|
+
(:method-combination progn :most-specific-first))
|
693
|
+
|
694
|
+
(defgeneric testsuite-methods (testsuite)
|
695
|
+
(:documentation "Returns a list of the test methods defined for test. I.e.,
|
696
|
+
the methods that should be run to do the tests for this test."))
|
697
|
+
|
698
|
+
(defgeneric lift-test (suite name)
|
699
|
+
(:documentation ""))
|
700
|
+
|
701
|
+
(defgeneric do-testing (testsuite result fn)
|
702
|
+
(:documentation ""))
|
703
|
+
|
704
|
+
(defgeneric end-test (result case method-name)
|
705
|
+
(:documentation ""))
|
706
|
+
|
707
|
+
(defgeneric run-test-internal (suite name result &rest args)
|
708
|
+
(:documentation ""))
|
709
|
+
|
710
|
+
(defgeneric run-tests-internal (suite &rest args
|
711
|
+
&key &allow-other-keys)
|
712
|
+
(:documentation ""))
|
713
|
+
|
714
|
+
(defgeneric start-test (result case method-name)
|
715
|
+
(:documentation ""))
|
716
|
+
|
717
|
+
(defgeneric test-report-code (testsuite method)
|
718
|
+
(:documentation ""))
|
719
|
+
|
720
|
+
(defgeneric testsuite-p (thing)
|
721
|
+
(:documentation "Determine whether or not `thing` is a testsuite. Thing can be a symbol naming a suite, a subclass of `test-mixin` or an instance of a test suite. Returns nil if `thing` is not a testsuite and the symbol naming the suite if it is."))
|
722
|
+
|
723
|
+
(defgeneric testsuite-name->gf (case name)
|
724
|
+
(:documentation ""))
|
725
|
+
|
726
|
+
(defgeneric testsuite-name->method (class name)
|
727
|
+
(:documentation ""))
|
728
|
+
|
729
|
+
(defgeneric flet-test-function (testsuite function-name &rest args)
|
730
|
+
(:documentation ""))
|
731
|
+
|
732
|
+
(defgeneric equality-test (testsuite)
|
733
|
+
(:documentation ""))
|
734
|
+
|
735
|
+
(defgeneric do-testing-in-environment (testsuite result function)
|
736
|
+
(:documentation ""))
|
737
|
+
|
738
|
+
(defgeneric skip-test-case (result suite-name test-case-name)
|
739
|
+
)
|
740
|
+
|
741
|
+
(defgeneric describe-test-result (result stream &key &allow-other-keys)
|
742
|
+
)
|
743
|
+
|
744
|
+
(defgeneric write-profile-information (testsuite))
|
745
|
+
|
746
|
+
(defmethod write-profile-information ((suite t))
|
747
|
+
)
|
748
|
+
|
749
|
+
(defmethod equality-test ((suite test-mixin))
|
750
|
+
#'equal)
|
751
|
+
|
752
|
+
(defmethod setup-test :before ((test test-mixin))
|
753
|
+
(setf *test-scratchpad* nil
|
754
|
+
(current-step test) :test-setup))
|
755
|
+
|
756
|
+
(defmethod setup-test ((test test-mixin))
|
757
|
+
(values))
|
758
|
+
|
759
|
+
(defmethod test-case-teardown progn ((test test-mixin) (result test-result))
|
760
|
+
(values))
|
761
|
+
|
762
|
+
(defmethod test-case-teardown :around ((test test-mixin) (result test-result))
|
763
|
+
(setf (current-step test) :test-teardown)
|
764
|
+
(call-next-method))
|
765
|
+
|
766
|
+
(defmethod initialize-instance :after ((testsuite test-mixin) &rest initargs
|
767
|
+
&key &allow-other-keys)
|
768
|
+
(when (null (testsuite-name testsuite))
|
769
|
+
(setf (slot-value testsuite 'name)
|
770
|
+
(symbol-name (type-of testsuite))))
|
771
|
+
;; FIXME - maybe remove LIFT standard arguments?
|
772
|
+
(setf (suite-initargs testsuite) initargs))
|
773
|
+
|
774
|
+
(defmethod print-object ((tc test-mixin) stream)
|
775
|
+
(print-unreadable-object (tc stream :identity t :type t)
|
776
|
+
(format stream "~a" (testsuite-name tc))))
|
777
|
+
|
778
|
+
;;; ---------------------------------------------------------------------------
|
779
|
+
;;; macros
|
780
|
+
;;; ---------------------------------------------------------------------------
|
781
|
+
|
782
|
+
(defvar *current-definition* nil
|
783
|
+
"An associative-container which saves interesting information about
|
784
|
+
the thing being defined.")
|
785
|
+
|
786
|
+
(defun initialize-current-definition ()
|
787
|
+
(setf *current-definition* nil))
|
788
|
+
|
789
|
+
(defun set-definition (name value)
|
790
|
+
(let ((current (assoc name *current-definition*)))
|
791
|
+
(if current
|
792
|
+
(setf (cdr current) value)
|
793
|
+
(push (cons name value) *current-definition*)))
|
794
|
+
|
795
|
+
(values value))
|
796
|
+
|
797
|
+
(defun def (name &optional (definition *current-definition*))
|
798
|
+
(when definition (cdr (assoc name definition))))
|
799
|
+
|
800
|
+
(defun (setf def) (value name)
|
801
|
+
(set-definition name value))
|
802
|
+
|
803
|
+
(defvar *code-blocks* nil)
|
804
|
+
|
805
|
+
(defstruct (code-block (:type list) (:conc-name nil))
|
806
|
+
block-name (priority 0) filter code operate-when)
|
807
|
+
|
808
|
+
(defgeneric block-handler (name value)
|
809
|
+
(:documentation "")
|
810
|
+
(:method ((name t) (value t))
|
811
|
+
(error "Unknown clause: ~A" name)))
|
812
|
+
|
813
|
+
(defun add-code-block (name priority operate-when filter handler code)
|
814
|
+
(let ((current (assoc name *code-blocks*))
|
815
|
+
(value (make-code-block
|
816
|
+
:operate-when operate-when
|
817
|
+
:block-name name
|
818
|
+
:priority priority
|
819
|
+
:filter filter
|
820
|
+
:code code)))
|
821
|
+
(if current
|
822
|
+
(setf (cdr current) value)
|
823
|
+
(push (cons name value) *code-blocks*))
|
824
|
+
(eval
|
825
|
+
`(defmethod block-handler ((name (eql ',name)) value)
|
826
|
+
(declare (ignorable value))
|
827
|
+
,@handler)))
|
828
|
+
(setf *code-blocks* (sort *code-blocks* #'<
|
829
|
+
:key (lambda (name.cb)
|
830
|
+
(priority (cdr name.cb))))))
|
831
|
+
|
832
|
+
(defmacro with-test-slots (&body body)
|
833
|
+
`(symbol-macrolet ((lift-result (getf (test-data *current-test*) :result)))
|
834
|
+
;; case111 - LW complains otherwise
|
835
|
+
(declare (ignorable lift-result)
|
836
|
+
,@(when (def :dynamic-variables)
|
837
|
+
`((special ,@(mapcar #'car (def :dynamic-variables))))))
|
838
|
+
(symbol-macrolet
|
839
|
+
,(mapcar #'(lambda (local)
|
840
|
+
`(,local (test-environment-value ',local)))
|
841
|
+
(test-slots (def :testsuite-name)))
|
842
|
+
(declare (ignorable ,@(test-slots (def :testsuite-name))))
|
843
|
+
(macrolet
|
844
|
+
,(mapcar (lambda (spec)
|
845
|
+
(destructuring-bind (name arglist) spec
|
846
|
+
`(,name ,arglist
|
847
|
+
`(flet-test-function
|
848
|
+
*current-test* ',',name ,,@arglist))))
|
849
|
+
(def :function-specs))
|
850
|
+
(progn ,@body)))))
|
851
|
+
|
852
|
+
(defvar *deftest-clauses*
|
853
|
+
'(:setup :teardown :test :documentation :tests :export-p :export-slots
|
854
|
+
:run-setup :dynamic-variables :equality-test :categories :function))
|
855
|
+
|
856
|
+
(defmacro deftest (testsuite-name superclasses slots &rest
|
857
|
+
clauses-and-options)
|
858
|
+
"The `deftest` form is obsolete, see [deftestsuite][]."
|
859
|
+
|
860
|
+
(warn "Deftest is obsolete, use deftestsuite instead.")
|
861
|
+
`(deftestsuite ,testsuite-name ,superclasses ,slots ,@clauses-and-options))
|
862
|
+
|
863
|
+
(setf *code-blocks* nil)
|
864
|
+
|
865
|
+
(add-code-block
|
866
|
+
:setup 1 :methods
|
867
|
+
(lambda ()
|
868
|
+
(or (def :setup) (def :direct-slot-names)))
|
869
|
+
'((setf (def :setup) (cleanup-parsed-parameter value)))
|
870
|
+
'build-setup-test-method)
|
871
|
+
|
872
|
+
(add-code-block
|
873
|
+
:teardown 100 :methods
|
874
|
+
(lambda () (or (def :teardown) (def :direct-slot-names)))
|
875
|
+
'((setf (def :teardown) (cleanup-parsed-parameter value)))
|
876
|
+
'build-test-teardown-method)
|
877
|
+
|
878
|
+
(add-code-block
|
879
|
+
:function 0 :methods
|
880
|
+
(lambda () (def :functions))
|
881
|
+
'((push value (def :functions)))
|
882
|
+
'build-test-local-functions)
|
883
|
+
|
884
|
+
(add-code-block
|
885
|
+
:documentation 0 :class-def
|
886
|
+
nil
|
887
|
+
'((setf (def :documentation) (first value)))
|
888
|
+
nil)
|
889
|
+
|
890
|
+
(add-code-block
|
891
|
+
:export-p 0 :class-def
|
892
|
+
nil
|
893
|
+
'((setf (def :export-p) (first value)))
|
894
|
+
nil)
|
895
|
+
|
896
|
+
(add-code-block
|
897
|
+
:export-slots 0 :class-def
|
898
|
+
nil
|
899
|
+
'((setf (def :export-slots) (first value)))
|
900
|
+
nil)
|
901
|
+
|
902
|
+
(add-code-block
|
903
|
+
:run-setup 0 :class-def
|
904
|
+
nil
|
905
|
+
'((push (first value) (def :default-initargs))
|
906
|
+
(push :run-setup (def :default-initargs))
|
907
|
+
(setf (def :run-setup) (first value)))
|
908
|
+
'check-run-setup-value)
|
909
|
+
|
910
|
+
(defun %valid-run-setup-values ()
|
911
|
+
'(:once-per-session :once-per-suite
|
912
|
+
:once-per-test-case :never))
|
913
|
+
|
914
|
+
(defun check-run-setup-value ()
|
915
|
+
(when (def :run-setup)
|
916
|
+
(unless (member (def :run-setup) (%valid-run-setup-values))
|
917
|
+
(error "The :run-setup option must be one of ~{~a~^, ~}."
|
918
|
+
(%valid-run-setup-values)))))
|
919
|
+
|
920
|
+
(add-code-block
|
921
|
+
:equality-test 0 :methods
|
922
|
+
(lambda () (def :equality-test))
|
923
|
+
'((setf (def :equality-test) (cleanup-parsed-parameter value)))
|
924
|
+
'build-test-equality-test)
|
925
|
+
|
926
|
+
(add-code-block
|
927
|
+
:expected-error 0 :methods
|
928
|
+
(lambda () (def :expected-error))
|
929
|
+
'((setf (def :expected-error) (cleanup-parsed-parameter value)))
|
930
|
+
'build-testsuite-expected-error)
|
931
|
+
|
932
|
+
(add-code-block
|
933
|
+
:expected-failure 0 :methods
|
934
|
+
(lambda () (def :expected-failure))
|
935
|
+
'((setf (def :expected-failure) (cleanup-parsed-parameter value)))
|
936
|
+
'build-testsuite-expected-failure)
|
937
|
+
|
938
|
+
(add-code-block
|
939
|
+
:log-file 0 :class-def
|
940
|
+
nil
|
941
|
+
'((push (first value) (def :default-initargs))
|
942
|
+
(push :log-file (def :default-initargs)))
|
943
|
+
nil)
|
944
|
+
|
945
|
+
(add-code-block
|
946
|
+
:dynamic-variables 0 :class-def
|
947
|
+
nil
|
948
|
+
'((setf (def :direct-dynamic-variables) value))
|
949
|
+
nil)
|
950
|
+
|
951
|
+
(add-code-block
|
952
|
+
:categories 0 :class-def
|
953
|
+
nil
|
954
|
+
'((push value (def :categories)))
|
955
|
+
nil)
|
956
|
+
|
957
|
+
(add-code-block
|
958
|
+
:default-initargs 1 :class-def
|
959
|
+
(lambda () (def :default-initargs))
|
960
|
+
'((dolist (x (reverse (cleanup-parsed-parameter value)))
|
961
|
+
(push x (def :default-initargs))))
|
962
|
+
nil)
|
963
|
+
|
964
|
+
(defmacro deftestsuite (testsuite-name superclasses slots &rest
|
965
|
+
clauses-and-options)
|
966
|
+
"
|
967
|
+
Creates a testsuite named `testsuite-name` and, optionally, the code required for test setup, test tear-down and the actual test-cases. A testsuite is a collection of test-cases and other testsuites.
|
968
|
+
|
969
|
+
Test suites can have multiple superclasses (just like the classes that they are). Usually, these will be other test classes and the class hierarchy becomes the test case hierarchy. If necessary, however, non-testsuite classes can also be used as superclasses.
|
970
|
+
|
971
|
+
Slots are specified as in defclass with the following additions:
|
972
|
+
|
973
|
+
* Initargs and accessors are automatically defined. If a slot is named`my-slot`, then the initarg will be `:my-slot` and the accessors will be `my-slot` and `(setf my-slot)`.
|
974
|
+
* If the second argument is not a CLOS slot option keyword, then it will be used as the `:initform` for the slot. I.e., if you have
|
975
|
+
|
976
|
+
(deftestsuite my-test ()
|
977
|
+
((my-slot 23)))
|
978
|
+
|
979
|
+
then `my-slot` will be initialized to 23 during test setup.
|
980
|
+
|
981
|
+
Test options are one of :setup, :teardown, :test, :tests, :documentation, :export-p, :dynamic-variables, :export-slots, :function, :categories, :run-setup, or :equality-test.
|
982
|
+
|
983
|
+
* :categories - a list of symbols. Categories allow you to groups tests into clusters outside of the basic hierarchy. This provides finer grained control on selecting which tests to run. May be specified multiple times.
|
984
|
+
|
985
|
+
* :documentation - a string specifying any documentation for the test. Should only be specified once.
|
986
|
+
|
987
|
+
* :dynamic-variables - a list of atoms or pairs of the form (name value). These specify any special variables that should be bound in a let around the body of the test. The name should be symbol designating a special variable. The value (if supplied) will be bound to the variable. If the value is not supplied, the variable will be bound to nil. Should only be specified once.
|
988
|
+
|
989
|
+
* :equality-test - the name of the function to be used by default in calls to ensure-same and ensure-different. Should only be supplied once.
|
990
|
+
|
991
|
+
* :export-p - If true, the testsuite name will be exported from the current package. Should only be specified once.
|
992
|
+
|
993
|
+
* :export-slots - if true, any slots specified in the test suite will be exported from the current package. Should only be specified once.
|
994
|
+
|
995
|
+
* :function - creates a locally accessible function for this test suite. May be specified multiple times.
|
996
|
+
|
997
|
+
* :run-setup - specify when to run the setup code for this test suite. Allowed values are
|
998
|
+
|
999
|
+
* :once-per-test-case or t (the default)
|
1000
|
+
* :once-per-session
|
1001
|
+
* :once-per-suite
|
1002
|
+
* :never or nil
|
1003
|
+
|
1004
|
+
:run-setup is handy when a testsuite has a time consuming setup phase that you do not want to repeat for every test.
|
1005
|
+
|
1006
|
+
* :setup - a list of forms to be evaluated before each test case is run. Should only be specified once.
|
1007
|
+
|
1008
|
+
* :teardown - a list of forms to be evaluated after each test case is run. Should only be specified once.
|
1009
|
+
|
1010
|
+
* :test - Define a single test case. Can be specified multiple times.
|
1011
|
+
|
1012
|
+
* :tests - Define multiple test cases for this test suite. Can be specified multiple times.
|
1013
|
+
"
|
1014
|
+
#+no-lift-tests
|
1015
|
+
`(values)
|
1016
|
+
#-no-lift-tests
|
1017
|
+
(let ((test-list nil)
|
1018
|
+
(options nil)
|
1019
|
+
(return (gensym)))
|
1020
|
+
;; convert any clause like :setup foo into (:setup foo)
|
1021
|
+
(setf clauses-and-options
|
1022
|
+
(convert-clauses-into-lists clauses-and-options *deftest-clauses*))
|
1023
|
+
(initialize-current-definition)
|
1024
|
+
(setf (def :testsuite-name) testsuite-name)
|
1025
|
+
(setf (def :superclasses) (mapcar #'find-testsuite superclasses))
|
1026
|
+
(setf (def :deftestsuite) t)
|
1027
|
+
;; parse clauses into defs
|
1028
|
+
(loop for clause in clauses-and-options do
|
1029
|
+
(typecase clause
|
1030
|
+
(symbol (pushnew clause options))
|
1031
|
+
(cons (destructuring-bind (kind &rest spec) clause
|
1032
|
+
(case kind
|
1033
|
+
(:test (push (first spec) test-list))
|
1034
|
+
(:tests
|
1035
|
+
(loop for test in spec do
|
1036
|
+
(push test test-list)))
|
1037
|
+
(t (block-handler kind spec)))))
|
1038
|
+
(t (error "When parsing ~S" clause))))
|
1039
|
+
(let ((slot-names nil) (slot-specs nil))
|
1040
|
+
(loop for slot in (if (listp slots) slots (list slots)) do
|
1041
|
+
(push (if (consp slot) (first slot) slot) slot-names)
|
1042
|
+
(push (parse-brief-slot slot) slot-specs))
|
1043
|
+
(setf (def :slot-specs) (nreverse slot-specs)
|
1044
|
+
(def :direct-slot-names) (nreverse slot-names)
|
1045
|
+
(def :slots-parsed) t))
|
1046
|
+
;;?? issue 27: breaks 'encapsulation' of code-block mechanism
|
1047
|
+
(setf (def :function-specs)
|
1048
|
+
(loop for spec in (def :functions) collect
|
1049
|
+
(destructuring-bind (name arglist &body body) (first spec)
|
1050
|
+
(declare (ignore body))
|
1051
|
+
`(,name ,arglist))))
|
1052
|
+
;;?? needed
|
1053
|
+
(empty-test-tables testsuite-name)
|
1054
|
+
(compute-superclass-inheritence)
|
1055
|
+
(prog2
|
1056
|
+
(setf *testsuite-test-count* 0)
|
1057
|
+
`(eval-when (:compile-toplevel :load-toplevel :execute)
|
1058
|
+
(eval-when (:compile-toplevel)
|
1059
|
+
(push ',return *test-is-being-compiled?*))
|
1060
|
+
(eval-when (:load-toplevel)
|
1061
|
+
(push ',return *test-is-being-loaded?*))
|
1062
|
+
(eval-when (:execute)
|
1063
|
+
(push ',return *test-is-being-executed?*))
|
1064
|
+
;; remove previous methods (do this _before_ we define the class)
|
1065
|
+
(unless (or *test-is-being-compiled?*
|
1066
|
+
*test-is-being-loaded?*)
|
1067
|
+
#+(or)
|
1068
|
+
(print (list :cle *test-is-being-compiled?*
|
1069
|
+
*test-is-being-loaded?*
|
1070
|
+
*test-is-being-loaded?*))
|
1071
|
+
(remove-previous-definitions ',(def :testsuite-name)))
|
1072
|
+
,(build-test-class)
|
1073
|
+
(unwind-protect
|
1074
|
+
(let ((*test-is-being-defined?* t))
|
1075
|
+
(setf *current-test-case-name* nil)
|
1076
|
+
(setf *current-testsuite-name* ',(def :testsuite-name)
|
1077
|
+
(test-slots ',(def :testsuite-name))
|
1078
|
+
',(def :slot-names)
|
1079
|
+
(testsuite-dynamic-variables ',(def :testsuite-name))
|
1080
|
+
',(def :dynamic-variables)
|
1081
|
+
;;?? issue 27: breaks 'encapsulation' of code-block
|
1082
|
+
;; mechanism
|
1083
|
+
(testsuite-function-specs ',(def :testsuite-name))
|
1084
|
+
',(def :function-specs))
|
1085
|
+
,@(when (def :export-p)
|
1086
|
+
`((export '(,(def :testsuite-name)))))
|
1087
|
+
,@(when (def :export-slots?)
|
1088
|
+
`((export ',(def :direct-slot-names))))
|
1089
|
+
;; make a place to save test-case information
|
1090
|
+
(empty-test-tables ',(def :testsuite-name))
|
1091
|
+
;; create methods
|
1092
|
+
;; setup :before
|
1093
|
+
,@(loop for (nil . block) in *code-blocks*
|
1094
|
+
when (and block
|
1095
|
+
(code block)
|
1096
|
+
(eq (operate-when block) :methods)
|
1097
|
+
(or (not (filter block))
|
1098
|
+
(funcall (filter block)))) collect
|
1099
|
+
(funcall (code block)))
|
1100
|
+
,@(when (def :dynamic-variables)
|
1101
|
+
`((defmethod do-testing :around
|
1102
|
+
((suite ,(def :testsuite-name)) result fn)
|
1103
|
+
(declare (ignore result fn)
|
1104
|
+
(special
|
1105
|
+
,@(mapcar
|
1106
|
+
#'car (def :dynamic-variables))))
|
1107
|
+
(cond ((done-dynamics? suite)
|
1108
|
+
(call-next-method))
|
1109
|
+
(t
|
1110
|
+
(setf (slot-value suite 'done-dynamics?) t)
|
1111
|
+
(let* (,@(def :dynamic-variables))
|
1112
|
+
(declare (special
|
1113
|
+
,@(mapcar
|
1114
|
+
#'car (def :dynamic-variables))))
|
1115
|
+
(call-next-method)))))))
|
1116
|
+
;; tests
|
1117
|
+
,@(when test-list
|
1118
|
+
`((let ((*test-evaluate-when-defined?* nil))
|
1119
|
+
,@(loop for test in (nreverse test-list) collect
|
1120
|
+
`(addtest (,(def :testsuite-name))
|
1121
|
+
,@test))
|
1122
|
+
(setf *testsuite-test-count* nil))))
|
1123
|
+
,(if (and test-list *test-evaluate-when-defined?*)
|
1124
|
+
`(unless (or *test-is-being-compiled?*
|
1125
|
+
*test-is-being-loaded?*)
|
1126
|
+
(let ((*test-break-on-errors?* *test-break-on-errors?*))
|
1127
|
+
(run-tests :suite ',testsuite-name)))
|
1128
|
+
`(find-class ',testsuite-name)))
|
1129
|
+
;; cleanup
|
1130
|
+
(setf *test-is-being-compiled?*
|
1131
|
+
(remove ',return *test-is-being-compiled?*))
|
1132
|
+
(setf *test-is-being-loaded?*
|
1133
|
+
(remove ',return *test-is-being-loaded?*))
|
1134
|
+
(setf *test-is-being-executed?*
|
1135
|
+
(remove ',return *test-is-being-executed?*)))))))
|
1136
|
+
|
1137
|
+
(defun compute-superclass-inheritence ()
|
1138
|
+
;;?? issue 27: break encapsulation of code blocks
|
1139
|
+
;;?? we assume that we won't have too deep a hierarchy or too many
|
1140
|
+
;; dv's or functions so that having lots of duplicate names is OK
|
1141
|
+
(let ((slots nil)
|
1142
|
+
(dynamic-variables nil)
|
1143
|
+
(function-specs nil))
|
1144
|
+
(dolist (super (def :superclasses))
|
1145
|
+
(cond ((find-testsuite super)
|
1146
|
+
(setf slots (append slots (test-slots super))
|
1147
|
+
dynamic-variables
|
1148
|
+
(append dynamic-variables
|
1149
|
+
(testsuite-dynamic-variables super))
|
1150
|
+
function-specs
|
1151
|
+
(append function-specs
|
1152
|
+
(testsuite-function-specs super))))
|
1153
|
+
(t
|
1154
|
+
(error 'testsuite-not-defined :testsuite-name super))))
|
1155
|
+
(setf (def :slot-names)
|
1156
|
+
(remove-duplicates (append (def :direct-slot-names) slots))
|
1157
|
+
(def :dynamic-variables)
|
1158
|
+
(remove-duplicates
|
1159
|
+
(append (%build-pairs (def :direct-dynamic-variables))
|
1160
|
+
dynamic-variables)
|
1161
|
+
:key #'car)
|
1162
|
+
(def :function-specs)
|
1163
|
+
(remove-duplicates
|
1164
|
+
(append (def :function-specs) function-specs)))
|
1165
|
+
(setf (def :superclasses)
|
1166
|
+
(loop for class in (def :superclasses)
|
1167
|
+
unless (some (lambda (oter)
|
1168
|
+
(and (not (eq class oter))
|
1169
|
+
(member class (superclasses oter))))
|
1170
|
+
(def :superclasses)) collect
|
1171
|
+
class))))
|
1172
|
+
|
1173
|
+
(defun %build-pairs (putative-pairs)
|
1174
|
+
(let ((result nil))
|
1175
|
+
(dolist (putative-pair putative-pairs)
|
1176
|
+
(if (atom putative-pair)
|
1177
|
+
(push (list putative-pair nil) result)
|
1178
|
+
(push putative-pair result)))
|
1179
|
+
(nreverse result)))
|
1180
|
+
|
1181
|
+
(defmacro addtest (name &body test)
|
1182
|
+
"Adds a single new test-case to the most recently defined testsuite."
|
1183
|
+
#+no-lift-tests
|
1184
|
+
`nil
|
1185
|
+
#-no-lift-tests
|
1186
|
+
(let ((body nil)
|
1187
|
+
(return (gensym))
|
1188
|
+
(options nil)
|
1189
|
+
(looks-like-suite-name (looks-like-suite-name-p name))
|
1190
|
+
(looks-like-code (looks-like-code-p name)))
|
1191
|
+
(cond ((and looks-like-suite-name looks-like-code)
|
1192
|
+
(error "Can't disambiguate suite name from possible code."))
|
1193
|
+
(looks-like-suite-name
|
1194
|
+
;; testsuite given
|
1195
|
+
(setf (def :testsuite-name) (first name)
|
1196
|
+
options (rest name)
|
1197
|
+
name nil body test))
|
1198
|
+
(t
|
1199
|
+
;; the 'name' is really part of the test...
|
1200
|
+
(setf body (cons name test))))
|
1201
|
+
(unless (def :testsuite-name)
|
1202
|
+
(when *current-testsuite-name*
|
1203
|
+
(setf (def :testsuite-name) *current-testsuite-name*)))
|
1204
|
+
(unless (def :testsuite-name)
|
1205
|
+
(signal-lift-error 'add-test +lift-no-current-test-class+))
|
1206
|
+
(unless (or (def :deftestsuite)
|
1207
|
+
(find-testsuite (def :testsuite-name)))
|
1208
|
+
(signal-lift-error 'add-test +lift-test-class-not-found+
|
1209
|
+
(def :testsuite-name)))
|
1210
|
+
`(eval-when (:compile-toplevel :load-toplevel :execute)
|
1211
|
+
(eval-when (:compile-toplevel)
|
1212
|
+
(push ',return *test-is-being-compiled?*))
|
1213
|
+
(eval-when (:load-toplevel)
|
1214
|
+
(push ',return *test-is-being-loaded?*))
|
1215
|
+
(eval-when (:execute)
|
1216
|
+
(push ',return *test-is-being-executed?*))
|
1217
|
+
(unwind-protect
|
1218
|
+
(let ((*test-is-being-defined?* t))
|
1219
|
+
(muffle-redefinition-warnings
|
1220
|
+
,(build-test-test-method (def :testsuite-name) body options))
|
1221
|
+
(setf *current-testsuite-name* ',(def :testsuite-name))
|
1222
|
+
(if *test-evaluate-when-defined?*
|
1223
|
+
(unless (or *test-is-being-compiled?*
|
1224
|
+
*test-is-being-loaded?*)
|
1225
|
+
(let ((*test-break-on-errors?* (testing-interactively-p)))
|
1226
|
+
(run-test)))
|
1227
|
+
(values)))
|
1228
|
+
;; cleanup
|
1229
|
+
(setf *test-is-being-compiled?*
|
1230
|
+
(remove ',return *test-is-being-compiled?*)
|
1231
|
+
*test-is-being-loaded?*
|
1232
|
+
(remove ',return *test-is-being-loaded?*)
|
1233
|
+
*test-is-being-executed?*
|
1234
|
+
(remove ',return *test-is-being-executed?*))))))
|
1235
|
+
|
1236
|
+
(defun looks-like-suite-name-p (form)
|
1237
|
+
(and (consp form)
|
1238
|
+
(atom (first form))
|
1239
|
+
(find-testsuite (first form))
|
1240
|
+
(property-list-p (rest form))))
|
1241
|
+
|
1242
|
+
(defun property-list-p (form)
|
1243
|
+
(and (listp form)
|
1244
|
+
(block check-it
|
1245
|
+
(let ((even? t))
|
1246
|
+
(loop for x in form
|
1247
|
+
for want-keyword? = t then (not want-keyword?) do
|
1248
|
+
(when (and want-keyword? (not (keywordp x)))
|
1249
|
+
(return-from check-it nil))
|
1250
|
+
(setf even? (not even?)))
|
1251
|
+
(return-from check-it even?)))))
|
1252
|
+
|
1253
|
+
#|
|
1254
|
+
(property-list-p '(:a :b))
|
1255
|
+
(property-list-p '(:a 2 :b 3 :c 5 :d 8))
|
1256
|
+
(property-list-p nil)
|
1257
|
+
|
1258
|
+
(property-list-p 3)
|
1259
|
+
(property-list-p '(3))
|
1260
|
+
(property-list-p '(3 :a))
|
1261
|
+
(property-list-p '(:a 3 :b))
|
1262
|
+
|#
|
1263
|
+
|
1264
|
+
(defun looks-like-code-p (name)
|
1265
|
+
(declare (ignore name))
|
1266
|
+
;; FIXME - stub
|
1267
|
+
nil)
|
1268
|
+
|
1269
|
+
(defun remove-test (&key (test-case *current-test-case-name*)
|
1270
|
+
(suite *current-testsuite-name*))
|
1271
|
+
(assert suite nil "Test suite could not be determined.")
|
1272
|
+
(assert test-case nil "Test-case could not be determined.")
|
1273
|
+
(setf (testsuite-tests suite)
|
1274
|
+
(remove test-case (testsuite-tests suite))))
|
1275
|
+
|
1276
|
+
(defun run-test (&rest args
|
1277
|
+
&key (test-case *current-test-case-name*)
|
1278
|
+
(name test-case name-supplied-p)
|
1279
|
+
(suite *current-testsuite-name*)
|
1280
|
+
(break-on-errors? *test-break-on-errors?*)
|
1281
|
+
(break-on-failures? *test-break-on-failures?*)
|
1282
|
+
(do-children? *test-do-children?*)
|
1283
|
+
(result nil)
|
1284
|
+
(profile nil)
|
1285
|
+
(testsuite-initargs nil))
|
1286
|
+
"Run a single testcase in a test suite. Will run the most recently defined or run testcase unless the name and suite arguments are used to override them."
|
1287
|
+
(when name-supplied-p
|
1288
|
+
(setf test-case name))
|
1289
|
+
(assert suite nil "Test suite could not be determined.")
|
1290
|
+
(assert test-case nil "Test-case could not be determined.")
|
1291
|
+
(let ((args-copy (copy-list args)))
|
1292
|
+
(declare (ignore args-copy))
|
1293
|
+
(remf args :suite)
|
1294
|
+
(remf args :break-on-errors?)
|
1295
|
+
(remf args :break-on-failures?)
|
1296
|
+
(remf args :run-setup)
|
1297
|
+
(remf args :dribble)
|
1298
|
+
(remf args :config)
|
1299
|
+
(remf args :report-pathname)
|
1300
|
+
(remf args :do-children?)
|
1301
|
+
(remf args :tests-to-skip)
|
1302
|
+
(remf args :testsuite-initargs)
|
1303
|
+
(let* ((*test-break-on-errors?* break-on-errors?)
|
1304
|
+
(*test-break-on-failures?* break-on-failures?)
|
1305
|
+
(*test-do-children?* do-children?)
|
1306
|
+
(*current-test*
|
1307
|
+
(make-testsuite
|
1308
|
+
suite
|
1309
|
+
(if (find :profile testsuite-initargs)
|
1310
|
+
testsuite-initargs
|
1311
|
+
(setf testsuite-initargs
|
1312
|
+
`(:profile ,profile ,@testsuite-initargs))))))
|
1313
|
+
(unless result
|
1314
|
+
(setf result (make-test-result suite :single)))
|
1315
|
+
(prog1
|
1316
|
+
(let ((*current-test-case-name* (find-test-case suite test-case))
|
1317
|
+
(*current-testsuite-name* suite)
|
1318
|
+
(*test-result* result))
|
1319
|
+
(do-testing-in-environment
|
1320
|
+
*current-test* result
|
1321
|
+
(lambda ()
|
1322
|
+
(apply #'run-test-internal
|
1323
|
+
*current-test* *current-test-case-name* result nil))))
|
1324
|
+
(setf *test-result* result)
|
1325
|
+
(setf *current-test-case-name* (find-test-case suite test-case)
|
1326
|
+
*current-testsuite-name* suite)))))
|
1327
|
+
|
1328
|
+
(defun make-testsuite (suite-name args)
|
1329
|
+
(let ((testsuite (find-testsuite suite-name :errorp t)))
|
1330
|
+
(if testsuite
|
1331
|
+
(apply #'make-instance testsuite args)
|
1332
|
+
(error "Testsuite ~a not found." suite-name))))
|
1333
|
+
|
1334
|
+
(defmethod do-testing-in-environment :around ((suite test-mixin) result fn)
|
1335
|
+
(declare (ignore fn))
|
1336
|
+
(tagbody
|
1337
|
+
:test-start
|
1338
|
+
(restart-case
|
1339
|
+
(handler-bind ((warning #'muffle-warning)
|
1340
|
+
; ignore warnings...
|
1341
|
+
(error
|
1342
|
+
(lambda (condition)
|
1343
|
+
(report-test-problem
|
1344
|
+
'testsuite-error result suite
|
1345
|
+
*current-test-case-name* condition
|
1346
|
+
:backtrace (get-backtrace condition))
|
1347
|
+
(if *test-break-on-errors?*
|
1348
|
+
(invoke-debugger condition)
|
1349
|
+
(go :test-end)))))
|
1350
|
+
(unwind-protect
|
1351
|
+
(let ((*lift-equality-test* (equality-test suite)))
|
1352
|
+
(testsuite-setup suite result)
|
1353
|
+
(call-next-method)
|
1354
|
+
result)
|
1355
|
+
;; cleanup
|
1356
|
+
(testsuite-teardown suite result)))
|
1357
|
+
(ensure-failed (condition)
|
1358
|
+
(report-test-problem
|
1359
|
+
'testsuite-failure result suite
|
1360
|
+
*current-test-case-name* condition))
|
1361
|
+
(retry-test () :report "Retry the test."
|
1362
|
+
(go :test-start)))
|
1363
|
+
:test-end)
|
1364
|
+
(values result))
|
1365
|
+
|
1366
|
+
(defmethod do-testing-in-environment ((suite test-mixin) result fn)
|
1367
|
+
(do-testing suite result fn)
|
1368
|
+
(values result))
|
1369
|
+
|
1370
|
+
(defmethod do-testing ((suite test-mixin) result fn)
|
1371
|
+
(funcall fn)
|
1372
|
+
(values result))
|
1373
|
+
|
1374
|
+
(defmethod run-tests-internal ((suite symbol) &rest args
|
1375
|
+
&key &allow-other-keys)
|
1376
|
+
(let ((*current-test* (make-testsuite suite args))
|
1377
|
+
(passthrough-arguments nil))
|
1378
|
+
(loop for arg in '(:result :do-children?)
|
1379
|
+
when (getf args arg) do
|
1380
|
+
(push (getf args arg) passthrough-arguments)
|
1381
|
+
(push arg passthrough-arguments))
|
1382
|
+
(apply #'run-tests-internal *current-test* passthrough-arguments)))
|
1383
|
+
|
1384
|
+
(defmethod run-tests-internal
|
1385
|
+
((case test-mixin) &key
|
1386
|
+
(result (make-test-result (class-of case) :multiple))
|
1387
|
+
(do-children? *test-do-children?*))
|
1388
|
+
(let ((*test-do-children?* do-children?))
|
1389
|
+
(do-testing-in-environment
|
1390
|
+
case result
|
1391
|
+
(lambda ()
|
1392
|
+
(testsuite-run case result)))
|
1393
|
+
(setf *test-result* result)))
|
1394
|
+
|
1395
|
+
(defun run-tests (&rest args &key
|
1396
|
+
(suite nil)
|
1397
|
+
(break-on-errors? *test-break-on-errors?*)
|
1398
|
+
(break-on-failures? *test-break-on-failures?*)
|
1399
|
+
(config nil)
|
1400
|
+
(dribble *lift-dribble-pathname*)
|
1401
|
+
(report-pathname t)
|
1402
|
+
(profile nil)
|
1403
|
+
;(timeout nil)
|
1404
|
+
(do-children? *test-do-children?*)
|
1405
|
+
(testsuite-initargs nil)
|
1406
|
+
result
|
1407
|
+
&allow-other-keys)
|
1408
|
+
"Run all of the tests in a suite."
|
1409
|
+
(declare (ignore profile))
|
1410
|
+
(prog1
|
1411
|
+
(let ((args-copy (copy-list args)))
|
1412
|
+
(remf args :suite)
|
1413
|
+
(remf args :break-on-errors?)
|
1414
|
+
(remf args :break-on-failures?)
|
1415
|
+
(remf args :run-setup)
|
1416
|
+
(remf args :dribble)
|
1417
|
+
(remf args :config)
|
1418
|
+
(remf args :report-pathname)
|
1419
|
+
(remf args :do-children?)
|
1420
|
+
(remf args :tests-to-skip)
|
1421
|
+
(remf args :testsuite-initargs)
|
1422
|
+
(let* ((*lift-report-pathname*
|
1423
|
+
(cond ((null report-pathname) nil)
|
1424
|
+
((eq report-pathname t)
|
1425
|
+
(report-summary-pathname))))
|
1426
|
+
(*test-do-children?* do-children?)
|
1427
|
+
(report-pathname *lift-report-pathname*))
|
1428
|
+
(when report-pathname
|
1429
|
+
(ensure-directories-exist report-pathname))
|
1430
|
+
(cond ((and suite config)
|
1431
|
+
(error "Specify either configuration file or test suite
|
1432
|
+
but not both."))
|
1433
|
+
(config
|
1434
|
+
(unless result
|
1435
|
+
(setf result
|
1436
|
+
(apply #'make-test-result config :multiple args)))
|
1437
|
+
(when report-pathname
|
1438
|
+
(write-report-header report-pathname result args-copy))
|
1439
|
+
(let* ((*test-result* result))
|
1440
|
+
(setf result (run-tests-from-file config))))
|
1441
|
+
((or suite (setf suite *current-testsuite-name*))
|
1442
|
+
(unless result
|
1443
|
+
(setf result
|
1444
|
+
(apply #'make-test-result suite :multiple args)))
|
1445
|
+
(when report-pathname
|
1446
|
+
(write-report-header report-pathname result args-copy))
|
1447
|
+
(let* ((*test-break-on-errors?* break-on-errors?)
|
1448
|
+
(*test-break-on-failures?* break-on-failures?)
|
1449
|
+
(*test-result* result)
|
1450
|
+
(dribble-stream
|
1451
|
+
(when dribble
|
1452
|
+
(open dribble
|
1453
|
+
:direction :output
|
1454
|
+
:if-does-not-exist :create
|
1455
|
+
:if-exists *lift-if-dribble-exists*)))
|
1456
|
+
(*standard-output*
|
1457
|
+
(maybe-add-dribble
|
1458
|
+
*lift-standard-output* dribble-stream))
|
1459
|
+
(*error-output* (maybe-add-dribble
|
1460
|
+
*error-output* dribble-stream))
|
1461
|
+
(*debug-io* (maybe-add-dribble
|
1462
|
+
*debug-io* dribble-stream)))
|
1463
|
+
(unwind-protect
|
1464
|
+
(with-simple-restart (cancel-testing
|
1465
|
+
"Cancel testing of ~a"
|
1466
|
+
*current-testsuite-name*)
|
1467
|
+
(dolist (testsuite (if (consp suite)
|
1468
|
+
suite (list suite)))
|
1469
|
+
(let ((*current-testsuite-name* testsuite))
|
1470
|
+
(apply #'run-tests-internal testsuite
|
1471
|
+
:result result
|
1472
|
+
testsuite-initargs))
|
1473
|
+
(setf *current-testsuite-name* testsuite)))
|
1474
|
+
;; cleanup
|
1475
|
+
(when dribble-stream
|
1476
|
+
(close dribble-stream)))
|
1477
|
+
;; FIXME -- ugh!
|
1478
|
+
(setf (tests-run result) (reverse (tests-run result)))
|
1479
|
+
(when report-pathname
|
1480
|
+
(write-report-footer report-pathname result))
|
1481
|
+
(values result)))
|
1482
|
+
(t
|
1483
|
+
(error "There is not a current test suite and neither suite
|
1484
|
+
nor configuration file options were specified.")))))
|
1485
|
+
(setf *test-result* result)))
|
1486
|
+
|
1487
|
+
(defun maybe-add-dribble (stream dribble-stream)
|
1488
|
+
(if dribble-stream
|
1489
|
+
(values (make-broadcast-stream stream dribble-stream) t)
|
1490
|
+
(values stream nil)))
|
1491
|
+
|
1492
|
+
(defun skip-test-case-p (result suite-name test-case-name)
|
1493
|
+
(find-if (lambda (skip-datum)
|
1494
|
+
(and (eq suite-name (car skip-datum))
|
1495
|
+
(or (null (cdr skip-datum))
|
1496
|
+
(eq test-case-name (cdr skip-datum)))))
|
1497
|
+
(tests-to-skip result)))
|
1498
|
+
|
1499
|
+
(defmethod skip-test-case (result suite-name test-case-name)
|
1500
|
+
(declare (ignore result suite-name test-case-name))
|
1501
|
+
)
|
1502
|
+
|
1503
|
+
(defun skip-test-suite-children-p (result testsuite)
|
1504
|
+
(let ((suite-name (class-name (class-of testsuite))))
|
1505
|
+
(find-if (lambda (skip-datum)
|
1506
|
+
(and (eq suite-name (car skip-datum))
|
1507
|
+
(eq :including-children (cdr skip-datum))))
|
1508
|
+
(tests-to-skip result))))
|
1509
|
+
|
1510
|
+
(defmethod testsuite-run ((testsuite test-mixin) (result test-result))
|
1511
|
+
(unless (start-time result)
|
1512
|
+
(setf (start-time result) (get-internal-real-time)
|
1513
|
+
(start-time-universal result) (get-universal-time)))
|
1514
|
+
(unwind-protect
|
1515
|
+
(let* ((methods (testsuite-methods testsuite))
|
1516
|
+
(suite-name (class-name (class-of testsuite)))
|
1517
|
+
(*current-testsuite-name* suite-name))
|
1518
|
+
(loop for method in methods do
|
1519
|
+
(if (skip-test-case-p result suite-name method)
|
1520
|
+
(skip-test-case result suite-name method)
|
1521
|
+
(run-test-internal testsuite method result)))
|
1522
|
+
(when (and *test-do-children?*
|
1523
|
+
(not (skip-test-suite-children-p result testsuite)))
|
1524
|
+
(loop for subclass in (direct-subclasses (class-of testsuite))
|
1525
|
+
when (and (testsuite-p subclass)
|
1526
|
+
(not (member (class-name subclass)
|
1527
|
+
(suites-run result)))) do
|
1528
|
+
(run-tests-internal (class-name subclass)
|
1529
|
+
:result result))))
|
1530
|
+
(setf (end-time result) (get-universal-time))))
|
1531
|
+
|
1532
|
+
(defmethod run-test-internal ((suite symbol) (name symbol) result
|
1533
|
+
&rest args &key &allow-other-keys)
|
1534
|
+
(let ((*current-test* (make-testsuite suite args))
|
1535
|
+
(passthrough-arguments nil))
|
1536
|
+
(loop for arg in '(:result :do-children?)
|
1537
|
+
when (getf args arg) do
|
1538
|
+
(push (getf args arg) passthrough-arguments)
|
1539
|
+
(push arg passthrough-arguments))
|
1540
|
+
(apply #'run-test-internal
|
1541
|
+
*current-test* name result passthrough-arguments)))
|
1542
|
+
|
1543
|
+
(defmethod run-test-internal ((suite test-mixin) (name symbol) result
|
1544
|
+
&rest _)
|
1545
|
+
(declare (ignore _))
|
1546
|
+
(let ((result-pushed? nil)
|
1547
|
+
(*current-test-case-name* name)
|
1548
|
+
(error nil))
|
1549
|
+
(flet ((maybe-push-result ()
|
1550
|
+
;(print (list :mpr result-pushed? (test-data suite)))
|
1551
|
+
(let ((datum (list (type-of suite)
|
1552
|
+
*current-test-case-name* (test-data suite))))
|
1553
|
+
(cond ((null result-pushed?)
|
1554
|
+
(setf result-pushed? t)
|
1555
|
+
(push datum (tests-run result)))
|
1556
|
+
(t
|
1557
|
+
;; replace
|
1558
|
+
(setf (first (tests-run result)) datum))))))
|
1559
|
+
(when (and *test-print-test-case-names*
|
1560
|
+
(eq (test-mode result) :multiple))
|
1561
|
+
(print-lift-message "~& run: ~a" name))
|
1562
|
+
(tagbody
|
1563
|
+
:test-start
|
1564
|
+
(restart-case
|
1565
|
+
(handler-bind ((warning #'muffle-warning)
|
1566
|
+
; ignore warnings...
|
1567
|
+
(error
|
1568
|
+
(lambda (condition)
|
1569
|
+
(report-test-problem
|
1570
|
+
'test-error result suite
|
1571
|
+
*current-test-case-name* condition
|
1572
|
+
:backtrace (get-backtrace condition))
|
1573
|
+
(if (and *test-break-on-errors?*
|
1574
|
+
(not (testcase-expects-error-p)))
|
1575
|
+
(invoke-debugger condition)
|
1576
|
+
(go :test-end)))))
|
1577
|
+
(setf (current-method suite) name)
|
1578
|
+
(start-test result suite name)
|
1579
|
+
(unwind-protect
|
1580
|
+
(progn
|
1581
|
+
(setup-test suite)
|
1582
|
+
(setf (current-step suite) :testing)
|
1583
|
+
(multiple-value-bind (result measures error-condition)
|
1584
|
+
(while-measuring (t measure-space measure-seconds)
|
1585
|
+
(lift-test suite name))
|
1586
|
+
(declare (ignore result))
|
1587
|
+
(setf error error-condition)
|
1588
|
+
(destructuring-bind (space seconds) measures
|
1589
|
+
(setf (getf (test-data suite) :seconds) seconds
|
1590
|
+
(getf (test-data suite) :conses) space)))
|
1591
|
+
(when error
|
1592
|
+
(error error))
|
1593
|
+
(check-for-surprises suite))
|
1594
|
+
;; cleanup
|
1595
|
+
(maybe-push-result)
|
1596
|
+
(test-case-teardown suite result)
|
1597
|
+
(end-test result suite name)))
|
1598
|
+
(ensure-failed (condition)
|
1599
|
+
(report-test-problem
|
1600
|
+
'test-failure result suite
|
1601
|
+
*current-test-case-name* condition)
|
1602
|
+
(if (and *test-break-on-failures?*
|
1603
|
+
(not (testcase-expects-failure-p)))
|
1604
|
+
(invoke-debugger condition)
|
1605
|
+
(go :test-end)))
|
1606
|
+
(retry-test () :report "Retry the test."
|
1607
|
+
(go :test-start)))
|
1608
|
+
:test-end)
|
1609
|
+
(maybe-push-result))
|
1610
|
+
(when *lift-report-pathname*
|
1611
|
+
(let ((current (first (tests-run result))))
|
1612
|
+
(summarize-single-test
|
1613
|
+
:save (first current) (second current) (third current)
|
1614
|
+
:stream *lift-report-pathname*))))
|
1615
|
+
(setf *current-test-case-name* name
|
1616
|
+
*test-result* result))
|
1617
|
+
|
1618
|
+
(defun testcase-expects-error-p (&optional (test *current-test*))
|
1619
|
+
(let* ((options (getf (test-data test) :options)))
|
1620
|
+
(or (testsuite-expects-error test)
|
1621
|
+
(second (member :expected-error options)))))
|
1622
|
+
|
1623
|
+
(defun testcase-expects-failure-p (&optional (test *current-test*))
|
1624
|
+
(let* ((options (getf (test-data test) :options)))
|
1625
|
+
(or (testsuite-expects-failure test)
|
1626
|
+
(second (member :expected-failure options)))))
|
1627
|
+
|
1628
|
+
(defun testcase-expects-problem-p (&optional (test *current-test*))
|
1629
|
+
(let* ((options (getf (test-data test) :options)))
|
1630
|
+
(second (member :expected-problem options))))
|
1631
|
+
|
1632
|
+
(defun check-for-surprises (testsuite)
|
1633
|
+
(let* ((expected-failure-p (testcase-expects-failure-p testsuite))
|
1634
|
+
(expected-error-p (testcase-expects-error-p testsuite))
|
1635
|
+
(expected-problem-p (testcase-expects-problem-p testsuite))
|
1636
|
+
(condition nil))
|
1637
|
+
(cond
|
1638
|
+
(expected-failure-p
|
1639
|
+
(setf (slot-value testsuite 'expected-failure-p) expected-failure-p))
|
1640
|
+
(expected-error-p
|
1641
|
+
(setf (slot-value testsuite 'expected-error-p) expected-error-p))
|
1642
|
+
(expected-problem-p
|
1643
|
+
(setf (slot-value testsuite 'expected-problem-p) expected-problem-p)))
|
1644
|
+
(cond
|
1645
|
+
((expected-failure-p testsuite)
|
1646
|
+
(setf condition
|
1647
|
+
(make-condition 'unexpected-success-failure
|
1648
|
+
:expected :failure
|
1649
|
+
:expected-more (expected-failure-p testsuite))))
|
1650
|
+
((expected-error-p testsuite)
|
1651
|
+
(setf condition
|
1652
|
+
(make-condition 'unexpected-success-failure
|
1653
|
+
:expected :error
|
1654
|
+
:expected-more (expected-error-p testsuite))))
|
1655
|
+
((expected-problem-p testsuite)
|
1656
|
+
(setf condition
|
1657
|
+
(make-condition 'unexpected-success-failure
|
1658
|
+
:expected :problem
|
1659
|
+
:expected-more (expected-problem-p testsuite)))))
|
1660
|
+
(when condition
|
1661
|
+
(if (find-restart 'ensure-failed)
|
1662
|
+
(invoke-restart 'ensure-failed condition)
|
1663
|
+
(warn condition)))))
|
1664
|
+
|
1665
|
+
(defun report-test-problem (problem-type result suite method condition
|
1666
|
+
&rest args)
|
1667
|
+
;; ick
|
1668
|
+
(let ((docs nil)
|
1669
|
+
(option nil))
|
1670
|
+
(declare (ignorable docs option))
|
1671
|
+
(cond ((and (eq problem-type 'test-failure)
|
1672
|
+
(not (typep condition 'unexpected-success-failure))
|
1673
|
+
(testcase-expects-failure-p suite))
|
1674
|
+
(setf problem-type 'test-expected-failure
|
1675
|
+
option :expected-failure))
|
1676
|
+
((and (eq problem-type 'test-error)
|
1677
|
+
(testcase-expects-error-p suite))
|
1678
|
+
(setf problem-type 'test-expected-error
|
1679
|
+
option :expected-error))
|
1680
|
+
((and (or (eq problem-type 'test-failure)
|
1681
|
+
(eq problem-type 'test-error))
|
1682
|
+
(testcase-expects-problem-p suite))
|
1683
|
+
(setf problem-type (or (and (eq problem-type 'test-failure)
|
1684
|
+
'test-expected-failure)
|
1685
|
+
(and (eq problem-type 'test-error)
|
1686
|
+
'test-expected-error))
|
1687
|
+
option :expected-problem)))
|
1688
|
+
(let ((problem (apply #'make-instance problem-type
|
1689
|
+
:testsuite suite
|
1690
|
+
:test-method method
|
1691
|
+
:test-condition condition
|
1692
|
+
:test-step (current-step suite) args)))
|
1693
|
+
(setf (getf (test-data suite) :problem) problem)
|
1694
|
+
(etypecase problem
|
1695
|
+
((or test-failure testsuite-failure) (push problem (failures result)))
|
1696
|
+
(test-expected-failure (push problem (expected-failures result)))
|
1697
|
+
((or test-error testsuite-error) (push problem (errors result)))
|
1698
|
+
(test-expected-error (push problem (expected-errors result))))
|
1699
|
+
(when (and *test-maximum-failure-count*
|
1700
|
+
(numberp *test-maximum-failure-count*)
|
1701
|
+
(>= (length (failures result)) *test-maximum-failure-count*))
|
1702
|
+
(cancel-testing :failures))
|
1703
|
+
(when (and *test-maximum-error-count*
|
1704
|
+
(numberp *test-maximum-error-count*)
|
1705
|
+
(>= (length (errors result)) *test-maximum-error-count*))
|
1706
|
+
(cancel-testing :errors))
|
1707
|
+
problem)))
|
1708
|
+
|
1709
|
+
(defun cancel-testing (why)
|
1710
|
+
(declare (ignore why))
|
1711
|
+
(flet ((do-it (name)
|
1712
|
+
;; should just use find-restart but I was experimenting
|
1713
|
+
(let* ((restarts (compute-restarts))
|
1714
|
+
(it (find name restarts :key #'restart-name :from-end nil)))
|
1715
|
+
(when it
|
1716
|
+
(invoke-restart it)))))
|
1717
|
+
(do-it 'cancel-testing-from-configuration)
|
1718
|
+
(do-it 'cancel-testing)))
|
1719
|
+
|
1720
|
+
;;; ---------------------------------------------------------------------------
|
1721
|
+
;;; test-result and printing
|
1722
|
+
;;; ---------------------------------------------------------------------------
|
1723
|
+
|
1724
|
+
(defun get-test-print-length ()
|
1725
|
+
(let ((foo *test-print-length*))
|
1726
|
+
(if (eq foo :follow-print) *print-length* foo)))
|
1727
|
+
|
1728
|
+
(defun get-test-print-level ()
|
1729
|
+
(let ((foo *test-print-level*))
|
1730
|
+
(if (eq foo :follow-print) *print-level* foo)))
|
1731
|
+
|
1732
|
+
(defmethod start-test ((result test-result) (suite test-mixin) name)
|
1733
|
+
(declare (ignore name))
|
1734
|
+
(setf (current-step suite) :start-test
|
1735
|
+
(test-data suite)
|
1736
|
+
`(:start-time ,(get-internal-real-time)
|
1737
|
+
:start-time-universal ,(get-universal-time))))
|
1738
|
+
|
1739
|
+
(defmethod end-test ((result test-result) (suite test-mixin) name)
|
1740
|
+
(declare (ignore name))
|
1741
|
+
(setf (current-step suite) :end-test
|
1742
|
+
(getf (test-data suite) :end-time) (get-internal-real-time)
|
1743
|
+
(end-time result) (get-internal-real-time)
|
1744
|
+
(getf (test-data suite) :end-time-universal) (get-universal-time)
|
1745
|
+
(end-time-universal result) (get-universal-time)))
|
1746
|
+
|
1747
|
+
(defun make-test-result (for test-mode &rest args)
|
1748
|
+
(apply #'make-instance 'test-result
|
1749
|
+
:results-for for
|
1750
|
+
:test-mode test-mode
|
1751
|
+
args))
|
1752
|
+
|
1753
|
+
(defun testing-interactively-p ()
|
1754
|
+
(values nil))
|
1755
|
+
|
1756
|
+
(defmethod print-object ((tr test-result) stream)
|
1757
|
+
(let ((complete-success? (and (null (errors tr))
|
1758
|
+
(null (failures tr))
|
1759
|
+
(null (expected-failures tr))
|
1760
|
+
(null (expected-errors tr)))))
|
1761
|
+
(let* ((*print-level* (get-test-print-level))
|
1762
|
+
(*print-length* (get-test-print-length))
|
1763
|
+
(non-failure-failures
|
1764
|
+
(count-if
|
1765
|
+
(lambda (failure)
|
1766
|
+
(member (class-of (test-condition failure))
|
1767
|
+
(subclasses 'unexpected-success-failure :proper? nil)))
|
1768
|
+
(expected-failures tr)))
|
1769
|
+
(expected-failures (- (length (expected-failures tr))
|
1770
|
+
non-failure-failures)))
|
1771
|
+
(print-unreadable-object (tr stream)
|
1772
|
+
(cond ((and (null (tests-run tr)) complete-success?)
|
1773
|
+
(format stream "~A: no tests defined" (results-for tr)))
|
1774
|
+
((eq (test-mode tr) :single)
|
1775
|
+
(cond ((test-interactive? tr)
|
1776
|
+
;; interactive
|
1777
|
+
(cond (complete-success?
|
1778
|
+
(format stream "Test passed"))
|
1779
|
+
((errors tr)
|
1780
|
+
(format stream "Error during testing"))
|
1781
|
+
((expected-errors tr)
|
1782
|
+
(format stream "Expected error during testing"))
|
1783
|
+
((failures tr)
|
1784
|
+
(format stream "Test failed"))
|
1785
|
+
((plusp non-failure-failures)
|
1786
|
+
(format stream "Test succeeded unexpectedly"))
|
1787
|
+
(t
|
1788
|
+
(format stream "Test failed expectedly"))))
|
1789
|
+
(t
|
1790
|
+
;; from run-test
|
1791
|
+
(format stream "~A.~A ~A"
|
1792
|
+
(results-for tr)
|
1793
|
+
(first (first (tests-run tr)))
|
1794
|
+
(cond (complete-success?
|
1795
|
+
"passed")
|
1796
|
+
((errors tr)
|
1797
|
+
"Error")
|
1798
|
+
(t
|
1799
|
+
"failed")))
|
1800
|
+
(when (or (expected-errors tr) (expected-failures tr))
|
1801
|
+
(format stream "(~[~:;, ~:*~A expected failure~:P~]~[~:;, ~:*~A succeeded unexpectedly~]~[~:;, ~:*~A expected error~:P~])"
|
1802
|
+
expected-failures non-failure-failures
|
1803
|
+
(expected-errors tr))))))
|
1804
|
+
(t
|
1805
|
+
;; multiple tests run
|
1806
|
+
(format stream "Results for ~A " (results-for tr))
|
1807
|
+
(if complete-success?
|
1808
|
+
(format stream "[~A Successful test~:P]"
|
1809
|
+
(length (tests-run tr)))
|
1810
|
+
(format stream "~A Test~:P~[~:;, ~:*~A Failure~:P~]~[~:;, ~:*~A Error~:P~]~[~:;, ~:*~A Expected failure~:P~]~[~:;, ~:*~A Expected error~:P~]"
|
1811
|
+
(length (tests-run tr))
|
1812
|
+
(length (failures tr))
|
1813
|
+
(length (errors tr))
|
1814
|
+
(length (expected-failures tr))
|
1815
|
+
(length (expected-errors tr))))))
|
1816
|
+
;; note that suites with no tests think that they are completely
|
1817
|
+
;; successful. Optimistic little buggers, huh?
|
1818
|
+
(when (and (not complete-success?) *test-describe-if-not-successful?*)
|
1819
|
+
(format stream "~%")
|
1820
|
+
(print-test-result-details stream tr t t))))))
|
1821
|
+
|
1822
|
+
(defmethod describe-object ((result test-result) stream)
|
1823
|
+
(describe-test-result result stream))
|
1824
|
+
|
1825
|
+
(defmethod describe-test-result (result stream
|
1826
|
+
&key
|
1827
|
+
(show-details-p *test-show-details-p*)
|
1828
|
+
(show-expected-p *test-show-expected-p*)
|
1829
|
+
(show-code-p *test-show-code-p*))
|
1830
|
+
(let* ((number-of-failures (length (failures result)))
|
1831
|
+
(number-of-errors (length (errors result)))
|
1832
|
+
(number-of-expected-errors (length (expected-errors result)))
|
1833
|
+
(non-failure-failures
|
1834
|
+
(count-if
|
1835
|
+
(lambda (failure)
|
1836
|
+
(member (class-of (test-condition failure))
|
1837
|
+
(subclasses 'unexpected-success-failure :proper? nil)))
|
1838
|
+
(expected-failures result)))
|
1839
|
+
(number-of-expected-failures (- (length (expected-failures result))
|
1840
|
+
non-failure-failures))
|
1841
|
+
(*print-level* (get-test-print-level))
|
1842
|
+
(*print-length* (get-test-print-length)))
|
1843
|
+
(unless *test-is-being-defined?*
|
1844
|
+
(print-test-summary result stream)
|
1845
|
+
(when (and show-details-p
|
1846
|
+
(or (plusp number-of-failures)
|
1847
|
+
(plusp number-of-expected-failures)
|
1848
|
+
(plusp number-of-errors)
|
1849
|
+
(plusp number-of-expected-errors)))
|
1850
|
+
(format stream "~%~%")
|
1851
|
+
(print-test-result-details
|
1852
|
+
stream result show-expected-p show-code-p)
|
1853
|
+
(print-test-summary result stream)))))
|
1854
|
+
|
1855
|
+
(defun print-test-summary (result stream)
|
1856
|
+
(let* ((number-of-failures (length (failures result)))
|
1857
|
+
(number-of-errors (length (errors result)))
|
1858
|
+
(number-of-expected-errors (length (expected-errors result)))
|
1859
|
+
(non-failure-failures
|
1860
|
+
(count-if
|
1861
|
+
(lambda (failure)
|
1862
|
+
(member (class-of (test-condition failure))
|
1863
|
+
(subclasses 'unexpected-success-failure :proper? nil)))
|
1864
|
+
(expected-failures result)))
|
1865
|
+
(number-of-expected-failures (- (length (expected-failures result))
|
1866
|
+
non-failure-failures)))
|
1867
|
+
(format stream "~&Test Report for ~A: ~D test~:P run"
|
1868
|
+
(results-for result) (length (tests-run result)))
|
1869
|
+
(cond ((or (failures result) (errors result)
|
1870
|
+
(expected-failures result) (expected-errors result))
|
1871
|
+
(format stream "~[~:;, ~:*~A Error~:P~]~[~:;, ~:*~A Failure~:P~]~[~:;, ~:*~A Expected error~:P~]~[~:;, ~:*~A Expected failure~:P~]~[~:;, ~:*~A Successful Surprise~:P~]."
|
1872
|
+
number-of-errors
|
1873
|
+
number-of-failures
|
1874
|
+
number-of-expected-errors
|
1875
|
+
number-of-expected-failures
|
1876
|
+
non-failure-failures))
|
1877
|
+
((or (expected-failures result) (expected-errors result))
|
1878
|
+
(format stream ", all passed *~[~:;, ~:*~A Expected error~:P~]~[~:;, ~:*~A Expected failure~:P~])."
|
1879
|
+
number-of-expected-errors
|
1880
|
+
number-of-expected-failures))
|
1881
|
+
(t
|
1882
|
+
(format stream ", all passed!")))))
|
1883
|
+
|
1884
|
+
(defun print-test-result-details (stream result show-expected-p show-code-p)
|
1885
|
+
(loop for report in (errors result) do
|
1886
|
+
(print-test-problem "ERROR : " report stream
|
1887
|
+
show-code-p))
|
1888
|
+
(loop for report in (failures result) do
|
1889
|
+
(print-test-problem "Failure: " report stream
|
1890
|
+
show-code-p))
|
1891
|
+
(when show-expected-p
|
1892
|
+
(loop for report in (expected-failures result) do
|
1893
|
+
(print-test-problem "Expected failure: " report stream
|
1894
|
+
show-code-p))
|
1895
|
+
(loop for report in (expected-errors result) do
|
1896
|
+
(print-test-problem "Expected Error : " report stream
|
1897
|
+
show-code-p))))
|
1898
|
+
|
1899
|
+
(defun print-test-problem (prefix report stream show-code-p)
|
1900
|
+
(let* ((suite (testsuite report))
|
1901
|
+
(method (test-method report))
|
1902
|
+
(condition (test-condition report))
|
1903
|
+
(code (test-report-code suite method))
|
1904
|
+
(testsuite-name method)
|
1905
|
+
(*print-level* (get-test-print-level))
|
1906
|
+
(*print-length* (get-test-print-length)))
|
1907
|
+
(let ((*package* (symbol-package method)))
|
1908
|
+
(format stream "~&~A~(~A : ~A~)" prefix (type-of suite) testsuite-name)
|
1909
|
+
(let ((doc-string (gethash testsuite-name
|
1910
|
+
(test-case-documentation
|
1911
|
+
(class-name (class-of suite))))))
|
1912
|
+
(when doc-string
|
1913
|
+
(format stream "~&~A" doc-string)))
|
1914
|
+
(if show-code-p
|
1915
|
+
(setf code (with-output-to-string (out)
|
1916
|
+
(pprint code out)))
|
1917
|
+
(setf code nil))
|
1918
|
+
(format stream "~&~< ~@;~
|
1919
|
+
~@[Condition: ~<~@;~A~:>~]~
|
1920
|
+
~@[~&Code : ~a~]~
|
1921
|
+
~&~:>" (list (list condition) code)))))
|
1922
|
+
|
1923
|
+
|
1924
|
+
;;; ---------------------------------------------------------------------------
|
1925
|
+
;;; test-reports
|
1926
|
+
;;; ---------------------------------------------------------------------------
|
1927
|
+
|
1928
|
+
(defclass test-problem-mixin ()
|
1929
|
+
((testsuite :initform nil :initarg :testsuite :reader testsuite)
|
1930
|
+
(test-method :initform nil :initarg :test-method :reader test-method)
|
1931
|
+
(test-condition :initform nil
|
1932
|
+
:initarg :test-condition
|
1933
|
+
:reader test-condition)
|
1934
|
+
(test-problem-kind :reader test-problem-kind :allocation :class)
|
1935
|
+
(test-step :initform nil :initarg :test-step :reader test-step)))
|
1936
|
+
|
1937
|
+
(defmethod print-object ((problem test-problem-mixin) stream)
|
1938
|
+
(print-unreadable-object (problem stream)
|
1939
|
+
(format stream "TEST-~@:(~A~): ~A in ~A"
|
1940
|
+
(test-problem-kind problem)
|
1941
|
+
(name (testsuite problem))
|
1942
|
+
(test-method problem))))
|
1943
|
+
|
1944
|
+
(defclass generic-problem (test-problem-mixin)
|
1945
|
+
((test-problem-kind :initarg :test-problem-kind
|
1946
|
+
:allocation :class)))
|
1947
|
+
|
1948
|
+
(defclass expected-problem-mixin ()
|
1949
|
+
((documentation :initform nil
|
1950
|
+
:initarg :documentation
|
1951
|
+
:accessor failure-documentation)))
|
1952
|
+
|
1953
|
+
(defclass test-expected-failure (expected-problem-mixin generic-problem)
|
1954
|
+
()
|
1955
|
+
(:default-initargs
|
1956
|
+
:test-problem-kind "Expected failure"))
|
1957
|
+
|
1958
|
+
(defclass test-failure (generic-problem)
|
1959
|
+
()
|
1960
|
+
(:default-initargs
|
1961
|
+
:test-problem-kind "failure"))
|
1962
|
+
|
1963
|
+
(defclass test-error-mixin (generic-problem)
|
1964
|
+
((backtrace :initform nil :initarg :backtrace :reader backtrace)))
|
1965
|
+
|
1966
|
+
(defclass test-expected-error (expected-problem-mixin test-error-mixin)
|
1967
|
+
()
|
1968
|
+
(:default-initargs
|
1969
|
+
:test-problem-kind "Expected error"))
|
1970
|
+
|
1971
|
+
(defclass test-error (test-error-mixin)
|
1972
|
+
()
|
1973
|
+
(:default-initargs
|
1974
|
+
:test-problem-kind "Error"))
|
1975
|
+
|
1976
|
+
(defclass testsuite-error (test-error-mixin)
|
1977
|
+
()
|
1978
|
+
(:default-initargs
|
1979
|
+
:test-problem-kind "Testsuite error"))
|
1980
|
+
|
1981
|
+
(defclass testsuite-failure (generic-problem)
|
1982
|
+
()
|
1983
|
+
(:default-initargs
|
1984
|
+
:test-problem-kind "Testsuite failure"))
|
1985
|
+
|
1986
|
+
(defmethod test-report-code ((testsuite test-mixin) (method symbol))
|
1987
|
+
(let* ((class-name (class-name (class-of testsuite))))
|
1988
|
+
(gethash method
|
1989
|
+
(test-name->code-table class-name))))
|
1990
|
+
|
1991
|
+
;;; ---------------------------------------------------------------------------
|
1992
|
+
;;; utilities
|
1993
|
+
;;; ---------------------------------------------------------------------------
|
1994
|
+
|
1995
|
+
(defun remove-test-methods (test-name)
|
1996
|
+
(prog1
|
1997
|
+
(length (testsuite-tests test-name))
|
1998
|
+
(setf (testsuite-tests test-name) nil)))
|
1999
|
+
|
2000
|
+
(defun remove-previous-definitions (classname)
|
2001
|
+
"Remove the methods of this class and all its subclasses."
|
2002
|
+
(let ((classes-removed nil)
|
2003
|
+
(class (find-class classname nil))
|
2004
|
+
(removed-count 0))
|
2005
|
+
(when class
|
2006
|
+
(loop for subclass in (subclasses class :proper? nil) do
|
2007
|
+
(push subclass classes-removed)
|
2008
|
+
(incf removed-count
|
2009
|
+
(remove-test-methods (class-name subclass)))
|
2010
|
+
#+Ignore
|
2011
|
+
;;?? causing more trouble than it solves...??
|
2012
|
+
(setf (find-class (class-name subclass)) nil))
|
2013
|
+
|
2014
|
+
(unless (length-1-list-p classes-removed)
|
2015
|
+
(format *debug-io*
|
2016
|
+
"~&;;; Removed Test suite ~(~A~) and its subclasses (~{~<~s~>~^, ~})."
|
2017
|
+
classname (sort
|
2018
|
+
(delete classname
|
2019
|
+
(mapcar #'class-name classes-removed))
|
2020
|
+
#'string-lessp)))
|
2021
|
+
(unless (zerop removed-count)
|
2022
|
+
(format *debug-io*
|
2023
|
+
"~&;;; Removed ~D methods from test suite ~(~A~)~@[ and its subclasses~]."
|
2024
|
+
removed-count classname
|
2025
|
+
(not (length-1-list-p classes-removed)))))))
|
2026
|
+
|
2027
|
+
(defun (setf test-environment-value) (value name)
|
2028
|
+
(push (cons name value) *test-environment*)
|
2029
|
+
(values value))
|
2030
|
+
|
2031
|
+
(defun test-environment-value (name)
|
2032
|
+
(cdr (assoc name *test-environment*)))
|
2033
|
+
|
2034
|
+
(defun remove-from-test-environment (name)
|
2035
|
+
(setf *test-environment*
|
2036
|
+
(remove name *test-environment* :key #'car :count 1)))
|
2037
|
+
|
2038
|
+
(defun build-test-local-functions ()
|
2039
|
+
`(progn
|
2040
|
+
,@(mapcar
|
2041
|
+
(lambda (function-spec)
|
2042
|
+
(destructuring-bind (name arglist &body body) (first function-spec)
|
2043
|
+
`(defmethod flet-test-function ((testsuite ,(def :testsuite-name))
|
2044
|
+
(function-name (eql ',name))
|
2045
|
+
&rest args)
|
2046
|
+
(with-test-slots
|
2047
|
+
,(if arglist
|
2048
|
+
`(destructuring-bind ,arglist args
|
2049
|
+
,@body)
|
2050
|
+
`(progn ,@body))))))
|
2051
|
+
(def :functions))))
|
2052
|
+
|
2053
|
+
(defun build-test-equality-test ()
|
2054
|
+
(let ((test-name (def :testsuite-name))
|
2055
|
+
(equality-test (def :equality-test)))
|
2056
|
+
`(progn
|
2057
|
+
(defmethod equality-test ((testsuite ,test-name))
|
2058
|
+
,equality-test))))
|
2059
|
+
|
2060
|
+
(defun build-testsuite-expected-error ()
|
2061
|
+
(let ((test-name (def :testsuite-name))
|
2062
|
+
(expected-error (def :expected-error)))
|
2063
|
+
`(progn
|
2064
|
+
(defmethod testsuite-expects-error ((testsuite ,test-name))
|
2065
|
+
(with-test-slots
|
2066
|
+
,expected-error)))))
|
2067
|
+
|
2068
|
+
(defun build-testsuite-expected-failure ()
|
2069
|
+
(let ((test-name (def :testsuite-name))
|
2070
|
+
(expected-failure (def :expected-failure)))
|
2071
|
+
`(progn
|
2072
|
+
(defmethod testsuite-expects-failure ((testsuite ,test-name))
|
2073
|
+
(with-test-slots
|
2074
|
+
,expected-failure)))))
|
2075
|
+
|
2076
|
+
(defun build-test-teardown-method ()
|
2077
|
+
(let ((test-name (def :testsuite-name))
|
2078
|
+
(slot-names (def :direct-slot-names))
|
2079
|
+
(teardown (def :teardown)))
|
2080
|
+
(when teardown
|
2081
|
+
(unless (consp teardown)
|
2082
|
+
(setf teardown (list teardown)))
|
2083
|
+
(when (length-1-list-p teardown)
|
2084
|
+
(setf teardown (list teardown)))
|
2085
|
+
(when (symbolp (first teardown))
|
2086
|
+
(setf teardown (list teardown))))
|
2087
|
+
(let* ((teardown-code `(,@(when teardown
|
2088
|
+
`((with-test-slots ,@teardown)))))
|
2089
|
+
(test-code `(,@teardown-code
|
2090
|
+
,@(mapcar (lambda (slot)
|
2091
|
+
`(remove-from-test-environment ',slot))
|
2092
|
+
slot-names))))
|
2093
|
+
`(progn
|
2094
|
+
,@(when teardown-code
|
2095
|
+
`((defmethod test-case-teardown progn ((testsuite ,test-name)
|
2096
|
+
(result test-result))
|
2097
|
+
(when (run-teardown-p testsuite :test-case)
|
2098
|
+
,@test-code))))
|
2099
|
+
,@(when teardown-code
|
2100
|
+
`((defmethod testsuite-teardown ((testsuite ,test-name)
|
2101
|
+
(result test-result))
|
2102
|
+
(when (run-teardown-p testsuite :testsuite)
|
2103
|
+
,@test-code))))))))
|
2104
|
+
|
2105
|
+
(defun build-setup-test-method ()
|
2106
|
+
(let ((test-name (def :testsuite-name))
|
2107
|
+
(setup (def :setup)))
|
2108
|
+
;;?? ewww, this smells bad
|
2109
|
+
(when setup
|
2110
|
+
(unless (consp setup)
|
2111
|
+
(setf setup (list setup)))
|
2112
|
+
(when (length-1-list-p setup)
|
2113
|
+
(setf setup (list setup)))
|
2114
|
+
(when (symbolp (first setup))
|
2115
|
+
(setf setup (list setup))))
|
2116
|
+
(let ((ginitargs (gensym "initargs-")))
|
2117
|
+
(multiple-value-bind (slots initforms)
|
2118
|
+
(%gather-up-initforms)
|
2119
|
+
(when (or setup slots)
|
2120
|
+
`(progn
|
2121
|
+
(defmethod setup-test :after ((testsuite ,test-name))
|
2122
|
+
(with-test-slots
|
2123
|
+
,@(when slots
|
2124
|
+
`((let ((,ginitargs (suite-initargs testsuite)))
|
2125
|
+
,@(loop for slot-name in slots
|
2126
|
+
for initform in initforms
|
2127
|
+
for keyword = (intern (symbol-name slot-name)
|
2128
|
+
:keyword)
|
2129
|
+
collect
|
2130
|
+
`(setf (test-environment-value ',slot-name)
|
2131
|
+
(or (getf ,ginitargs ,keyword)
|
2132
|
+
,initform))))))
|
2133
|
+
,@setup))))))))
|
2134
|
+
|
2135
|
+
(defun %gather-up-initforms ()
|
2136
|
+
(let ((initforms nil)
|
2137
|
+
(slot-names nil)
|
2138
|
+
(slot-specs (def :slot-specs)))
|
2139
|
+
(loop for slot in (def :direct-slot-names)
|
2140
|
+
for spec = (assoc slot slot-specs) do
|
2141
|
+
(push (getf (rest spec) :initform) initforms)
|
2142
|
+
(push (first spec) slot-names))
|
2143
|
+
(values (nreverse slot-names) (nreverse initforms))))
|
2144
|
+
|
2145
|
+
(defmethod setup-test :around ((test test-mixin))
|
2146
|
+
(when (run-setup-p test)
|
2147
|
+
(call-next-method)
|
2148
|
+
(setf (slot-value test 'done-setup?) t)))
|
2149
|
+
|
2150
|
+
(defun run-setup-p (testsuite)
|
2151
|
+
(case (run-setup testsuite)
|
2152
|
+
(:once-per-session (error "not implemented"))
|
2153
|
+
(:once-per-suite (not (done-setup? testsuite)))
|
2154
|
+
((:once-per-test-case t) t)
|
2155
|
+
((:never nil) nil)
|
2156
|
+
(t (error "Don't know about ~s for run-setup" (run-setup testsuite)))))
|
2157
|
+
|
2158
|
+
(defun run-teardown-p (testsuite when)
|
2159
|
+
(ecase when
|
2160
|
+
(:test-case
|
2161
|
+
(ecase (run-setup testsuite)
|
2162
|
+
(:once-per-session nil)
|
2163
|
+
(:once-per-suite nil)
|
2164
|
+
((:once-per-test-case t) t)
|
2165
|
+
((:never nil) nil)))
|
2166
|
+
(:testsuite
|
2167
|
+
(ecase (run-setup testsuite)
|
2168
|
+
(:once-per-session nil)
|
2169
|
+
(:once-per-suite t)
|
2170
|
+
((:once-per-test-case t) nil)
|
2171
|
+
((:never nil) nil)))))
|
2172
|
+
|
2173
|
+
(defun build-test-test-method (test-class test-body options)
|
2174
|
+
(multiple-value-bind (test-name body documentation name-supplied?)
|
2175
|
+
(parse-test-body test-body)
|
2176
|
+
(declare (ignorable name-supplied?))
|
2177
|
+
(unless (consp (first body))
|
2178
|
+
(setf body (list body)))
|
2179
|
+
`(progn
|
2180
|
+
(setf (gethash ',test-name (test-name->code-table ',test-class)) ',body
|
2181
|
+
(gethash ',body (test-code->name-table ',test-class)) ',test-name)
|
2182
|
+
,(when documentation
|
2183
|
+
`(setf (gethash ',test-name (test-case-documentation ',test-class))
|
2184
|
+
,documentation))
|
2185
|
+
#+(or mcl ccl)
|
2186
|
+
,@(when name-supplied?
|
2187
|
+
`((ccl:record-source-file ',test-name 'test-case)))
|
2188
|
+
(unless (find ',test-name (testsuite-tests ',test-class))
|
2189
|
+
(setf (testsuite-tests ',test-class)
|
2190
|
+
(append (testsuite-tests ',test-class) (list ',test-name))))
|
2191
|
+
(defmethod lift-test ((testsuite ,test-class) (case (eql ',test-name)))
|
2192
|
+
,@(when options
|
2193
|
+
`((setf (getf (test-data testsuite) :options)
|
2194
|
+
(list ,@(loop for (k v) on options by #'cddr append
|
2195
|
+
(list k v))))))
|
2196
|
+
(with-test-slots ,@body))
|
2197
|
+
(setf *current-test-case-name* ',test-name)
|
2198
|
+
(when (and *test-print-when-defined?*
|
2199
|
+
(not (or *test-is-being-compiled?*
|
2200
|
+
)))
|
2201
|
+
(format *debug-io* "~&;Test Created: ~(~S.~S~)."
|
2202
|
+
',test-class ',test-name))
|
2203
|
+
*current-test-case-name*)))
|
2204
|
+
|
2205
|
+
(defun parse-test-body (test-body)
|
2206
|
+
(let ((test-name nil)
|
2207
|
+
(body nil)
|
2208
|
+
(parsed-body nil)
|
2209
|
+
(documentation nil)
|
2210
|
+
(test-number (1+ (testsuite-test-count *current-testsuite-name*)))
|
2211
|
+
(name-supplied? nil))
|
2212
|
+
;; parse out any documentation
|
2213
|
+
(loop for form in test-body do
|
2214
|
+
(if (and (consp form)
|
2215
|
+
(keywordp (first form))
|
2216
|
+
(eq :documentation (first form)))
|
2217
|
+
(setf documentation (second form))
|
2218
|
+
(push form parsed-body)))
|
2219
|
+
(setf test-body (nreverse parsed-body))
|
2220
|
+
(setf test-name (first test-body))
|
2221
|
+
(cond ((symbolp test-name)
|
2222
|
+
(setf test-name
|
2223
|
+
(intern (format nil "~A" test-name))
|
2224
|
+
body (rest test-body)
|
2225
|
+
name-supplied? t))
|
2226
|
+
((and (test-code->name-table *current-testsuite-name*)
|
2227
|
+
(setf test-name
|
2228
|
+
(gethash test-body
|
2229
|
+
(test-code->name-table *current-testsuite-name*))))
|
2230
|
+
(setf body test-body))
|
2231
|
+
(t
|
2232
|
+
(setf test-name
|
2233
|
+
(intern (format nil "TEST-~A"
|
2234
|
+
test-number))
|
2235
|
+
body test-body)))
|
2236
|
+
(values test-name body documentation name-supplied?)))
|
2237
|
+
|
2238
|
+
(defun build-test-class ()
|
2239
|
+
;; for now, we don't generate code from :class-def code-blocks
|
2240
|
+
;; they are executed only for effect.
|
2241
|
+
(loop for (nil . block) in *code-blocks*
|
2242
|
+
when (and block
|
2243
|
+
(code block)
|
2244
|
+
(eq (operate-when block) :class-def)
|
2245
|
+
(or (not (filter block))
|
2246
|
+
(funcall (filter block)))) collect
|
2247
|
+
(funcall (code block)))
|
2248
|
+
(unless (some (lambda (superclass)
|
2249
|
+
(testsuite-p superclass))
|
2250
|
+
(def :superclasses))
|
2251
|
+
(pushnew 'test-mixin (def :superclasses)))
|
2252
|
+
;; build basic class and standard class
|
2253
|
+
`(defclass ,(def :testsuite-name) (,@(def :superclasses))
|
2254
|
+
nil
|
2255
|
+
,@(when (def :documentation)
|
2256
|
+
`((:documentation ,(def :documentation))))
|
2257
|
+
(:default-initargs
|
2258
|
+
:test-slot-names ',(def :slot-names)
|
2259
|
+
,@(def :default-initargs))))
|
2260
|
+
|
2261
|
+
(defun parse-test-slots (slot-specs)
|
2262
|
+
(loop for spec in slot-specs collect
|
2263
|
+
(let ((parsed-spec spec))
|
2264
|
+
(if (member :initform parsed-spec)
|
2265
|
+
(let ((pos (position :initform parsed-spec)))
|
2266
|
+
(append (subseq parsed-spec 0 pos)
|
2267
|
+
(subseq parsed-spec (+ pos 2))))
|
2268
|
+
parsed-spec))))
|
2269
|
+
|
2270
|
+
(defmethod testsuite-p ((classname symbol))
|
2271
|
+
(let ((class (find-class classname nil)))
|
2272
|
+
(handler-case
|
2273
|
+
(and class
|
2274
|
+
(typep (allocate-instance class) 'test-mixin)
|
2275
|
+
classname)
|
2276
|
+
(error (c) (declare (ignore c)) (values nil)))))
|
2277
|
+
|
2278
|
+
(defmethod testsuite-p ((object standard-object))
|
2279
|
+
(testsuite-p (class-name (class-of object))))
|
2280
|
+
|
2281
|
+
(defmethod testsuite-p ((class standard-class))
|
2282
|
+
(testsuite-p (class-name class)))
|
2283
|
+
|
2284
|
+
(defmethod testsuite-methods ((classname symbol))
|
2285
|
+
(testsuite-tests classname))
|
2286
|
+
|
2287
|
+
(defmethod testsuite-methods ((test test-mixin))
|
2288
|
+
(testsuite-methods (class-name (class-of test))))
|
2289
|
+
|
2290
|
+
(defmethod testsuite-methods ((test standard-class))
|
2291
|
+
(testsuite-methods (class-name test)))
|
2292
|
+
|
2293
|
+
|
2294
|
+
;; some handy properties
|
2295
|
+
(defclass-property test-slots)
|
2296
|
+
(defclass-property test-code->name-table)
|
2297
|
+
(defclass-property test-name->code-table)
|
2298
|
+
(defclass-property test-case-documentation)
|
2299
|
+
(defclass-property testsuite-tests)
|
2300
|
+
(defclass-property testsuite-dynamic-variables)
|
2301
|
+
|
2302
|
+
;;?? issue 27: break encapsulation of code blocks
|
2303
|
+
(defclass-property testsuite-function-specs)
|
2304
|
+
|
2305
|
+
(defun empty-test-tables (test-name)
|
2306
|
+
(when (find-class test-name nil)
|
2307
|
+
(setf (test-code->name-table test-name)
|
2308
|
+
(make-hash-table :test #'equal)
|
2309
|
+
(test-name->code-table test-name)
|
2310
|
+
(make-hash-table :test #'equal)
|
2311
|
+
(test-case-documentation test-name)
|
2312
|
+
(make-hash-table :test #'equal))))
|
2313
|
+
|
2314
|
+
(pushnew :timeout *deftest-clauses*)
|
2315
|
+
|
2316
|
+
(add-code-block
|
2317
|
+
:timeout 1 :class-def
|
2318
|
+
(lambda () (def :timeout))
|
2319
|
+
'((setf (def :timeout) (cleanup-parsed-parameter value)))
|
2320
|
+
(lambda ()
|
2321
|
+
(unless (some (lambda (super)
|
2322
|
+
(member (find-class 'process-test-mixin)
|
2323
|
+
(superclasses super)))
|
2324
|
+
(def :superclasses))
|
2325
|
+
(pushnew 'process-test-mixin (def :superclasses)))
|
2326
|
+
(push (def :timeout) (def :default-initargs))
|
2327
|
+
(push :maximum-time (def :default-initargs))
|
2328
|
+
nil))
|
2329
|
+
|
2330
|
+
(defclass process-test-mixin (test-mixin)
|
2331
|
+
((maximum-time :initform *test-maximum-time*
|
2332
|
+
:accessor maximum-time
|
2333
|
+
:initarg :maximum-time)))
|
2334
|
+
|
2335
|
+
(defclass test-timeout-failure (test-failure)
|
2336
|
+
((test-problem-kind :initform "Timeout" :allocation :class)))
|
2337
|
+
|
2338
|
+
(defmethod lift-test :around ((suite test-mixin) name)
|
2339
|
+
(if (profile suite)
|
2340
|
+
(with-profile-report ((format nil "~a-~a"
|
2341
|
+
(testsuite-name suite) name)
|
2342
|
+
(profile suite))
|
2343
|
+
(call-next-method))
|
2344
|
+
(call-next-method)))
|
2345
|
+
|
2346
|
+
(defmethod do-testing :around ((testsuite process-test-mixin) result fn)
|
2347
|
+
(declare (ignore fn))
|
2348
|
+
(handler-case
|
2349
|
+
(with-timeout ((maximum-time testsuite))
|
2350
|
+
(call-next-method))
|
2351
|
+
(timeout-error
|
2352
|
+
(c)
|
2353
|
+
(declare (ignore c))
|
2354
|
+
(report-test-problem
|
2355
|
+
'test-timeout-failure result testsuite (current-method testsuite)
|
2356
|
+
(make-instance 'test-timeout-condition
|
2357
|
+
:maximum-time (maximum-time testsuite))))))
|
2358
|
+
|
2359
|
+
;;?? might be "cleaner" with a macrolet (cf. lift-result)
|
2360
|
+
(defun lift-property (name)
|
2361
|
+
(when *current-test*
|
2362
|
+
(getf (getf (test-data *current-test*) :properties) name)))
|
2363
|
+
|
2364
|
+
#+(or)
|
2365
|
+
(setf (getf (getf (third (first (tests-run *test-result*))) :properties) :foo)
|
2366
|
+
3)
|
2367
|
+
|
2368
|
+
(defun (setf lift-property) (value name)
|
2369
|
+
(when *current-test*
|
2370
|
+
(setf (getf (getf (test-data *current-test*) :properties) name) value)))
|
2371
|
+
|
2372
|
+
|
2373
|
+
#+Later
|
2374
|
+
(defmacro with-test (&body forms)
|
2375
|
+
"Execute forms in the context of the current test class."
|
2376
|
+
(let* ((testsuite-name *current-testsuite-name*)
|
2377
|
+
(test-case (make-instance test-class)))
|
2378
|
+
`(eval-when (:execute)
|
2379
|
+
(prog2
|
2380
|
+
(setup-test ,test-case)
|
2381
|
+
(progn
|
2382
|
+
(with-test-slots ,@forms))
|
2383
|
+
(test-case-teardown ,test-case result)))))
|