changeset 577: | 806c2b214df8 |
parent: | da17bf652e48 |
child: | 568c39371122 |
author: | Richard Westhaver <ellis@rwest.io> |
date: | Sun, 04 Aug 2024 20:51:07 -0400 |
permissions: | -rw-r--r-- |
description: | refactored q/tests, added rt/fuzz, more sql query work |
96 | 1 | ;;; rt.lisp --- regression testing |
2 | ||
3 | ;; Regression Testing framework. inspired by PCL, the original CMUCL |
|
4 | ;; code, and the SBCL port. |
|
5 | ||
6 | ;;; Commentary: |
|
7 | ||
8 | ;; - :rt https://www.merl.com/publications/docs/TR91-04.pdf Chapter 1 |
|
9 | ;; - :com.gigamonkeys.test https://github.com/gigamonkey/monkeylib-test-framework |
|
10 | ;; - :sb-rt https://github.com/sbcl/sbcl/blob/master/contrib/sb-rt/rt.lisp |
|
11 | ||
12 | ;; This package is intended to provide a modernized Lisp testing |
|
13 | ;; library with features found in some of the test frameworks listed |
|
14 | ;; below. |
|
15 | ||
16 | ;; - :it.bese.fiveam https://github.com/lispci/fiveam |
|
17 | ;; - :try https://github.com/melisgl/try |
|
18 | ;; - :rove https://github.com/fukamachi/rove |
|
19 | ||
20 | ;;; TODO: |
|
21 | #| |
|
22 | ||
23 | - [ ] benchmark support: do-bench, test-count, |
|
24 | ||
25 | - [ ] fixtures api |
|
26 | ||
27 | - [ ] profiling |
|
28 | |# |
|
29 | ;;; Code: |
|
449 | 30 | (in-package :std-user) |
31 | (require 'sb-cover) |
|
108 | 32 | (defpackage :rt |
96 | 33 | (:use |
34 | :cl :std :sxp :log |
|
286
237756e1358b
enforcing log level (todo), rt finessing to get x to test instead of fail
Richard Westhaver <ellis@rwest.io>
parents:
284
diff
changeset
|
35 | :sb-aprof) |
96 | 36 | (:export |
260 | 37 | :test-error |
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
38 | :*test-opts* |
96 | 39 | :*compile-tests* |
40 | :*catch-test-errors* |
|
41 | :*test-suffix* |
|
42 | :*default-test-suite-name* |
|
43 | :*test-suite* |
|
44 | :*test-suite-list* |
|
45 | ;; TODO 2023-09-04: :*test-profiler-list* not yet |
|
46 | :*testing* |
|
513 | 47 | :random-elt |
48 | :random-ref |
|
49 | :random-char |
|
50 | :random-chars |
|
51 | :random-bytes |
|
96 | 52 | :test-suite-designator |
53 | :check-suite-designator |
|
54 | :make-test |
|
55 | :make-suite |
|
56 | :test-name= |
|
57 | :do-test |
|
58 | :do-tests |
|
59 | :reset-tests |
|
60 | :continue-testing |
|
61 | :with-test-env |
|
108 | 62 | :%test-bail |
63 | :%test-result |
|
64 | :make-test-result |
|
96 | 65 | :ensure-suite |
66 | :test-fixture |
|
67 | :fixture-prototype |
|
68 | :make-fixture-prototype |
|
69 | :make-fixture |
|
70 | :with-fixture |
|
71 | :test-result |
|
108 | 72 | :test-fn |
96 | 73 | :test-pass-p |
74 | :test-fail-p |
|
75 | :test-skip-p |
|
76 | :test-failed |
|
77 | :fail! |
|
78 | :is |
|
79 | :signals |
|
80 | :deftest |
|
81 | :defsuite |
|
82 | :in-suite |
|
83 | :eval-test |
|
84 | :compile-test |
|
85 | :locked-tests |
|
86 | :push-test |
|
87 | :pop-test |
|
88 | :delete-test |
|
89 | :find-test |
|
282 | 90 | :find-suite |
96 | 91 | :do-suite |
92 | :test-object |
|
93 | :test |
|
94 | :test-fixture |
|
95 | :test-suite |
|
96 | :test-name |
|
97 | :tests |
|
98 | :test-form |
|
282 | 99 | :test-results)) |
96 | 100 | |
108 | 101 | (defpackage :rt/bench |
102 | (:nicknames :bench) |
|
103 | (:use :cl :std :log :rt) |
|
104 | (:export |
|
105 | :*bench-count* |
|
106 | :defbench |
|
107 | :do-bench)) |
|
108 | ||
260 | 109 | (uiop:define-package :rt/cover |
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
110 | (:nicknames :cover) |
448 | 111 | (:use :cl :std :log :rt) |
282 | 112 | (:export |
113 | :with-coverage :start-coverage :stop-coverage |
|
114 | :*coverage-directory* |
|
286
237756e1358b
enforcing log level (todo), rt finessing to get x to test instead of fail
Richard Westhaver <ellis@rwest.io>
parents:
284
diff
changeset
|
115 | :coverage-report)) |
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
116 | |
215 | 117 | (defpackage :rt/tracing |
118 | (:nicknames :tracing) |
|
108 | 119 | (:use :cl :std :log :rt) |
120 | (:export |
|
121 | :start-tracing |
|
122 | :stop-tracing |
|
123 | :with-tracing |
|
124 | :save-report |
|
125 | ;; Extra utility |
|
126 | :package-symbols-except)) |
|
127 | ||
128 | (defpackage :rt/flamegraph |
|
129 | (:nicknames :flamegraph) |
|
130 | (:use :cl :std :log :rt :sb-sprof) |
|
215 | 131 | (:export :save-flamegraph)) |
108 | 132 | |
577
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
133 | (defpackage :rt/fuzz |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
134 | (:nicknames :fuzz) |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
135 | (:use :cl :std :log :rt) |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
136 | (:export :fuzzer |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
137 | :fuzz |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
138 | :fuzz*)) |
806c2b214df8
refactored q/tests, added rt/fuzz, more sql query work
Richard Westhaver <ellis@rwest.io>
parents:
514
diff
changeset
|
139 | |
96 | 140 | (in-package :rt) |
141 | (in-readtable :std) |
|
142 | ||
143 | ;;; Vars |
|
282 | 144 | (defvar *test-opts* '(optimize sb-c::instrument-consing)) |
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
145 | (defvar *compile-tests* nil |
96 | 146 | "When nil do not compile tests. With a value of t, tests are compiled |
147 | with default optimizations else the value is used to configure |
|
148 | compiler optimizations.") |
|
149 | (defvar *catch-test-errors* t "When non-nil, cause errors in a test to be caught.") |
|
284
597f34d43df7
x.lisp upgrades, skel upgrades, worked on shell reader macros
Richard Westhaver <ellis@rwest.io>
parents:
282
diff
changeset
|
150 | (defvar *test-suffix* "-TEST" "A suffix to append to every `test' defined with `deftest'.") |
96 | 151 | (defvar *test-suite-list* nil "List of available `test-suite' objects.") |
152 | (defvar *test-suite* nil "A 'test-suite-designator' which identifies the current `test-suite'.") |
|
153 | (eval-when (:compile-toplevel :load-toplevel :execute) |
|
154 | (defvar *default-test-suite-name* "default")) |
|
155 | (declaim (type (or stream boolean string) *test-input*)) |
|
156 | (defvar *test-input* nil "When non-nil, specifies an input stream or buffer for `*testing*'.") |
|
157 | (defvar *testing* nil "Testing state var.") |
|
158 | ||
159 | ;;; Utils |
|
513 | 160 | |
161 | ;; random |
|
162 | (defvar *simple-charset* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") |
|
163 | ||
164 | (defun random-elt (seq) |
|
165 | (elt seq (random (length seq)))) |
|
166 | ||
167 | (defun random-ref (vec) |
|
168 | (aref vec (random (length vec)))) |
|
169 | ||
170 | (defun random-char () |
|
171 | (random-ref *simple-charset*)) |
|
172 | ||
173 | (defun random-chars (dim) |
|
174 | (let ((r (make-array dim :element-type 'character))) |
|
175 | (dotimes (i (array-total-size r) r) |
|
176 | (setf (row-major-aref r i) (random-char))))) |
|
177 | ||
178 | (defun random-byte () (random 255)) |
|
179 | ||
180 | (defun random-bytes (dim) |
|
181 | (let ((r (make-array dim :element-type 'octet))) |
|
182 | (dotimes (i (array-total-size r) r) |
|
183 | (setf (row-major-aref r i) (random-byte))))) |
|
184 | ||
96 | 185 | (eval-when (:compile-toplevel :load-toplevel :execute) |
186 | (defun make-test (&rest slots) |
|
187 | (apply #'make-instance 'test slots)) |
|
188 | (defun make-suite (&rest slots) |
|
189 | (apply #'make-instance 'test-suite slots))) |
|
190 | ||
191 | ;; TODO 2023-09-04: optimize |
|
274
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
192 | ;;(declaim (inline do-tests)) |
229 | 193 | (defun do-tests (&optional (suite *test-suite*) force (output *standard-output*)) |
96 | 194 | (if (pathnamep output) |
195 | (with-open-file (stream output :direction :output) |
|
229 | 196 | (do-suite (ensure-suite suite) :stream stream :force force)) |
197 | (do-suite (ensure-suite suite) :stream output :force force))) |
|
96 | 198 | |
274
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
199 | (defvar *test-output-mutex* (sb-thread:make-mutex :name "tests-output")) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
200 | |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
201 | ;; TODO |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
202 | (defun do-tests-concurrently (&optional (suite *test-suite*) force (output *standard-output*)) |
282 | 203 | (declare (ignore suite force)) |
274
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
204 | (sb-thread:with-mutex (*test-output-mutex*) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
205 | (let ((stream (make-synonym-stream output))) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
206 | (let ((*standard-output* stream) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
207 | (*error-output* stream)) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
208 | (nyi!))))) |
5f782d361e08
threads and db tweaks. fixed a tricky macro error caused by string-case, dat/html now works.
Richard Westhaver <ellis@rwest.io>
parents:
260
diff
changeset
|
209 | |
96 | 210 | (defun reset-tests () |
211 | (setq *testing* nil |
|
212 | *test-suite* nil |
|
213 | *test-suite-list* nil |
|
214 | *test-input* nil)) |
|
215 | ||
216 | ;; this assumes that *test-suite* is re-initialized correctly to the |
|
217 | ;; correct test-suite object. |
|
218 | (defun continue-testing () |
|
219 | (if-let ((test *testing*)) |
|
220 | (throw '%in-test test) |
|
221 | (do-suite *test-suite*))) |
|
222 | ||
223 | ;; NOTE 2023-09-01: `pushnew' does not return an indication of whether |
|
224 | ;; place is changed - it returns place. This is functionally sound but |
|
225 | ;; means that if we want to do something else in the event that place |
|
226 | ;; is unchanged, we run into some friction, |
|
227 | ;; https://stackoverflow.com/questions/56228832/adapting-common-lisp-pushnew-to-return-success-failure |
|
228 | (defun spush (item lst &key (test #'equal)) |
|
229 | "Substituting `push'" |
|
230 | (declare (type function test)) |
|
231 | (cond |
|
232 | ((null lst) (push item lst)) |
|
233 | ((list lst) |
|
234 | (if-let ((found (member item lst |
|
235 | :test test))) |
|
236 | (progn |
|
237 | (rplaca found item) |
|
238 | lst) |
|
239 | (push item lst))) |
|
240 | #|(or nil '(t (cons item lst)))|#)) |
|
241 | ||
242 | ;; FIX 2023-08-31: spush, replace with `add-test' method. |
|
243 | ;; (declaim (inline normalize-test-name)) |
|
244 | (defun normalize-test-name (a) |
|
245 | "Return the normalized `test-suite-designator' of A." |
|
246 | (etypecase a |
|
215 | 247 | (string (string-upcase a)) |
248 | (symbol (symbol-name a)) |
|
249 | (test-object (normalize-test-name (test-name a))) |
|
96 | 250 | (t (format nil "~A" a)))) |
251 | ||
252 | (defun test-name= (a b) |
|
253 | "Return t if A and B are similar `test-suite-designator's." |
|
254 | (let ((a (normalize-test-name a)) |
|
255 | (b (normalize-test-name b))) |
|
256 | (string= a b))) |
|
257 | ||
258 | ;; (declaim (inline assert-suite ensure-suite)) |
|
259 | (defun ensure-suite (name) |
|
260 | (if-let ((ok (member name *test-suite-list* :test #'test-name=))) |
|
261 | (car ok) |
|
262 | (when (or (eq name t) (null name)) (make-suite :name *default-test-suite-name*)))) |
|
263 | ||
264 | (defun check-suite-designator (suite) (check-type suite test-suite-designator)) |
|
265 | ||
266 | (defun assert-suite (name) |
|
267 | (check-suite-designator name) |
|
268 | (assert (ensure-suite name))) |
|
269 | ||
270 | (declaim (inline test-opt-key-p test-opt-valid-p)) |
|
271 | (defun test-opt-key-p (k) |
|
272 | "Test if K is a `test-opt-key'." |
|
273 | (member k '(:profile :save :stream))) |
|
274 | ||
275 | (defun test-opt-valid-p (f) |
|
276 | "Test if F is a valid `test-opt' form. If so, return F else nil." |
|
277 | (when (test-opt-key-p (car f)) |
|
278 | f)) |
|
279 | ||
280 | ;;; Conditions |
|
281 | (define-condition test-failed (error) |
|
282 | ((reason :accessor fail-reason :initarg :reason :initform "unknown") |
|
283 | (name :accessor fail-name :initarg :name) |
|
284 | (form :accessor fail-form :initarg :form)) |
|
285 | (:documentation "Signaled when a test fails.") |
|
286 | (:report (lambda (c s) |
|
287 | (format s "The following expression failed: ~S~%~A." |
|
288 | (fail-form c) |
|
289 | (fail-reason c))))) |
|
290 | ||
291 | ;;; Protocol |
|
292 | (defgeneric eval-test (self) |
|
293 | (:documentation "Eval a `test'.")) |
|
294 | ||
295 | (defgeneric compile-test (self &key &allow-other-keys) |
|
296 | (:documentation "Compile a `test'.")) |
|
297 | ||
298 | (defgeneric locked-tests (self) |
|
299 | (:documentation "Return a list of locked tests in `test-suite' object SELF.")) |
|
300 | ||
301 | (defgeneric push-test (self place) |
|
302 | (:documentation |
|
303 | "Push `test' SELF to the value of slot ':tests' in `test-suite' object PLACE.")) |
|
304 | ||
305 | (defgeneric pop-test (self) |
|
306 | (:documentation |
|
307 | "Pop the first `test' from the slot-value of ':tests' in `test-suite' object SELF.")) |
|
308 | ||
309 | (defgeneric push-result (self place) |
|
310 | (:documentation |
|
311 | "Push object SELF to the value of slot ':results' in object PLACE.")) |
|
312 | ||
313 | (defgeneric pop-result (self) |
|
314 | (:documentation |
|
315 | "Pop the first `test-result' from the slot-value of ':tests' from object SELF.")) |
|
316 | ||
317 | (defgeneric push-fixture (self place) |
|
318 | (:documentation |
|
319 | "Push object SELF to the value of slot ':results' in object PLACE.")) |
|
320 | ||
321 | (defgeneric delete-test (self &key &allow-other-keys) |
|
322 | (:documentation "Delete `test' object specified by `test-object' SELF and optional keys.")) |
|
323 | ||
324 | (defgeneric find-test (self name &key &allow-other-keys) |
|
325 | (:documentation "Find `test' object specified by name and optional keys.")) |
|
326 | ||
364 | 327 | (defgeneric do-test (self &optional context) |
328 | (:documentation "Run test SELF, printing results to *standard-output*. The second |
|
96 | 329 | argument is an optional fixture. |
330 | ||
331 | SELF can also be a `test-suite', in which case the TESTS slot is |
|
332 | queried for the value of TEST. If TEST is not provided, pops the car |
|
333 | from TESTS.")) |
|
334 | ||
335 | (defgeneric do-suite (self &key &allow-other-keys) |
|
336 | (:documentation |
|
337 | "Perform actions on `test-suite' object SELF with optional keys.")) |
|
338 | ||
339 | ;;;; Results |
|
340 | (deftype result-tag () |
|
341 | '(or (member :pass :fail :skip) null)) |
|
342 | ||
343 | (declaim (inline %make-test-result)) |
|
344 | (defstruct (test-result (:constructor %make-test-result) |
|
345 | (:conc-name tr-)) |
|
346 | (tag nil :type result-tag :read-only t) |
|
347 | (form nil :type form)) |
|
348 | ||
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
349 | (defmethod print-object ((self test-result) stream) |
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
350 | (print-unreadable-object (self stream :identity t) |
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
351 | (format stream "~A ~A" (tr-tag self) (tr-form self)))) |
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
352 | |
96 | 353 | (defun make-test-result (tag &optional form) |
354 | (%make-test-result :tag tag :form form)) |
|
355 | ||
356 | (defmethod test-pass-p ((res test-result)) |
|
357 | (when (eq :pass (tr-tag res)) t)) |
|
358 | ||
359 | (defmethod test-fail-p ((res test-result)) |
|
360 | (when (eq :fail (tr-tag res)) t)) |
|
361 | ||
362 | (defmethod test-skip-p ((res test-result)) |
|
363 | (when (eq :skip (tr-tag res)) t)) |
|
364 | ||
365 | (defmethod print-object ((self test-result) stream) |
|
366 | (print-unreadable-object (self stream) |
|
367 | (format stream "~A ~A" |
|
368 | (tr-tag self) |
|
369 | (tr-form self)))) |
|
370 | ||
371 | ;;; Objects |
|
372 | (defclass test-object () |
|
373 | ((name :initarg :name :initform (required-argument) :type string :accessor test-name) |
|
374 | #+nil (cached :initarg :cache :allocation :class :accessor test-cached-p :type boolean)) |
|
375 | (:documentation "Super class for all test-related objects.")) |
|
376 | ||
377 | (defmethod print-object ((self test-object) stream) |
|
378 | "test" |
|
379 | (print-unreadable-object (self stream :type t :identity t) |
|
380 | (format stream "~A" |
|
381 | (test-name self)))) |
|
382 | ||
383 | ;;;; Tests |
|
384 | ;; HACK 2023-08-31: inherit sxp? |
|
385 | ||
386 | (defclass test (test-object) |
|
387 | ((fn :type symbol :accessor test-fn) |
|
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
388 | (bench :type (or boolean fixnum) :accessor test-bench :initform nil :initarg :bench) |
96 | 389 | (profile :type list :accessor test-profile :initform nil :initarg :profile) |
390 | (args :type list :accessor test-args :initform nil :initarg :args) |
|
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
391 | (declare :type list :accessor test-declare :initform nil :initarg :declare) |
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
392 | (form :initarg :form :initform nil :accessor test-form) |
96 | 393 | (doc :initarg :doc :type string :accessor test-doc) |
394 | (lock :initarg :lock :type boolean :accessor test-lock-p) |
|
395 | (persist :initarg :persist :initform nil :type boolean :accessor test-persist-p) |
|
396 | (results :initarg :results :type (array test-result) :accessor test-results)) |
|
397 | (:documentation "Test class typically made with `deftest'.")) |
|
398 | ||
399 | (defmethod initialize-instance ((self test) &key name) |
|
400 | ;; (debug! "building test" name) |
|
401 | (setf (test-fn self) |
|
402 | (make-symbol |
|
403 | (format nil "~A~A" |
|
404 | name |
|
405 | (gensym *test-suffix*)))) |
|
406 | (setf (test-lock-p self) t) |
|
407 | ;; TODO 2023-09-21: we should count how many checks are in the :form |
|
408 | ;; slot and infer the array dimensions. |
|
409 | (setf (test-results self) (make-array 0 :element-type 'test-result)) |
|
410 | (call-next-method)) |
|
411 | ||
412 | (defmethod print-object ((self test) stream) |
|
413 | (print-unreadable-object (self stream :type t :identity t) |
|
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
414 | (format stream "~A :fn ~A" |
96 | 415 | (test-name self) |
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
416 | (test-fn self)))) |
96 | 417 | |
418 | (defmethod push-result ((self test-result) (place test)) |
|
419 | (with-slots (results) place |
|
420 | (push self results))) |
|
421 | ||
422 | (defmethod pop-result ((self test)) |
|
423 | (pop (test-results self))) |
|
424 | ||
425 | (defmethod eval-test ((self test)) |
|
282 | 426 | (eval `(progn ,@(test-form self)))) |
96 | 427 | |
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
428 | (defmethod funcall-test ((self test) &key declare) |
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
429 | (unless (functionp (test-fn self)) |
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
430 | (trace! (setf (symbol-function (test-fn self)) |
364 | 431 | (eval `(lambda () |
432 | ,(when declare `(declare ,declare)) |
|
433 | ,@(test-form self)))))) |
|
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
434 | (funcall (test-fn self))) |
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
435 | |
96 | 436 | (defmethod compile-test ((self test) &key declare &allow-other-keys) |
364 | 437 | (with-compilation-unit (:policy '(optimize debug)) |
438 | (compile |
|
439 | (test-fn self) |
|
440 | `(lambda () |
|
441 | ,(when declare `(declare ,declare)) |
|
442 | ,@(test-form self))))) |
|
96 | 443 | |
444 | (defun fail! (form &optional fmt &rest args) |
|
445 | (let ((reason (and fmt (apply #'format nil fmt args)))) |
|
446 | (with-simple-restart (ignore-fail "Continue testing.") |
|
447 | (error 'test-failed :reason reason :form form)))) |
|
448 | ||
449 | (defmacro with-test-env (self &body body) |
|
450 | `(catch '%in-test |
|
451 | (setf (test-lock-p ,self) t) |
|
452 | (let* ((*testing* ,self) |
|
108 | 453 | (%test-bail nil) |
454 | %test-result) |
|
455 | (block %test-bail |
|
96 | 456 | ,@body |
108 | 457 | (setf (test-lock-p ,self) %test-bail)) |
458 | %test-result))) |
|
96 | 459 | |
460 | (defmethod do-test ((self test) &optional fx) |
|
461 | (declare (ignorable fx)) |
|
462 | (with-test-env self |
|
364 | 463 | (trace! "running test: " *testing*) |
96 | 464 | (flet ((%do () |
465 | (if-let ((opt *compile-tests*)) |
|
466 | ;; RESEARCH 2023-08-31: with-compilation-unit? |
|
467 | (progn |
|
282 | 468 | (if (eq opt t) |
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
469 | (setq opt *test-opts*) |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
470 | (setq opt (push *test-opts* opt))) |
96 | 471 | ;; TODO 2023-09-21: handle failures here |
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
472 | (funcall (compile-test self :declare opt)) |
108 | 473 | (setf %test-result (make-test-result :pass (test-fn self)))) |
96 | 474 | (progn |
364 | 475 | (funcall-test self :declare '(optimize (debug 3) (safety 0))) |
108 | 476 | (setf %test-result (make-test-result :pass (test-name self))))))) |
96 | 477 | (if *catch-test-errors* |
478 | (handler-bind |
|
289
c4682fedd73d
added krypt lib, will probably add homer too
Richard Westhaver <ellis@rwest.io>
parents:
286
diff
changeset
|
479 | ((error |
365
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
480 | (lambda (c) |
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
481 | (setf %test-bail t) |
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
482 | (setf %test-result (make-test-result :fail c)) |
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
483 | (return-from %test-bail %test-result)))) |
96 | 484 | (%do)) |
485 | (%do))))) |
|
486 | ||
364 | 487 | (defmethod do-test ((self simple-string) &optional fixture) |
464 | 488 | (when-let ((test (find-test *test-suite* self))) |
489 | (do-test test fixture))) |
|
364 | 490 | |
491 | (defmethod do-test ((self symbol) &optional fixture) |
|
464 | 492 | (when-let ((test (find-test *test-suite* (symbol-name self)))) |
493 | (do-test test fixture))) |
|
364 | 494 | |
96 | 495 | ;;;; Fixtures |
496 | ||
497 | ;; Our fixtures are just closures - with a pandoric environment. You |
|
498 | ;; might call it a domain-specific object protocol. |
|
499 | ||
500 | ;; You can build fixtures inside a test or use the push-fixture |
|
501 | ;; method on a `test-suite' object. |
|
502 | ||
503 | (deftype fixture () 'form) |
|
504 | ||
505 | (declaim (inline %make-fixture-prototype)) |
|
506 | (defstruct (fixture-prototype (:constructor %make-fixture-prototype) |
|
507 | (:conc-name fxp)) |
|
508 | (kind :empty :type keyword) |
|
509 | (form nil :type form)) |
|
510 | ||
511 | (defun make-fixture-prototype (kind form) |
|
512 | (%make-fixture-prototype :kind kind :form form)) |
|
513 | ||
514 | (defmacro make-fixture (letargs &body ds) |
|
515 | (let ((letargs (let-binding-transform letargs))) |
|
516 | `(let (,@letargs) |
|
517 | (dlambda ,@ds)))) |
|
518 | ||
519 | (defmacro with-fixture ((var fx) &body body) |
|
520 | `(let ((,var ,fx)) |
|
521 | ,@body)) |
|
522 | ||
523 | ;;;; Suites |
|
524 | (defclass test-suite (test-object) |
|
525 | ((tests :initarg :set :initform nil :type list :accessor tests |
|
526 | :documentation "test-suite tests") |
|
527 | (results :initarg :results :initform nil :type list :accessor test-results |
|
528 | :documentation "test-suite results") |
|
529 | (stream :initarg :stream :initform *standard-output* :type stream :accessor test-stream) |
|
530 | (fixtures :initarg :fixtures :initform nil :type list :accessor test-fixtures)) |
|
531 | (:documentation "A class for collections of related `test' objects.")) |
|
532 | ||
533 | (defmethod print-object ((self test-suite) stream) |
|
534 | (print-unreadable-object (self stream :type t :identity t) |
|
108 | 535 | (format stream "~A [~d:~d:~d:~d]" |
96 | 536 | (test-name self) |
108 | 537 | (length (tests self)) |
96 | 538 | (count t (map-tests self #'test-lock-p)) |
539 | (count t (map-tests self #'test-persist-p)) |
|
540 | (length (test-results self))))) |
|
541 | ||
542 | ;; (defmethod reinitialize-instance ((self test-suite) &rest initargs &key &allow-other-keys)) |
|
543 | ||
544 | (deftype test-suite-designator () |
|
545 | "Either nil, a symbol, a string, or a `test-suite' object." |
|
282 | 546 | '(or null symbol string test-suite keyword)) |
547 | ||
548 | (defun find-suite (name) |
|
549 | (declare (test-suite-designator name)) |
|
550 | (find name *test-suite-list* :test #'test-name=)) |
|
96 | 551 | |
552 | (defmethod map-tests ((self test-suite) function) |
|
503 | 553 | ;; tests are stored in reverse order. run LIFO. |
554 | (mapcar function (reverse (tests self)))) |
|
96 | 555 | |
556 | (defmethod push-test ((self test) (place test-suite)) |
|
557 | (push self (tests place))) |
|
558 | ||
559 | (defmethod pop-test ((self test-suite)) |
|
560 | (pop (tests self))) |
|
561 | ||
562 | (defmethod push-result ((self test-result) (place test-suite)) |
|
563 | (with-slots (results) place |
|
564 | (push self results))) |
|
565 | ||
566 | (defmethod pop-result ((self test-suite)) |
|
567 | (pop (test-results self))) |
|
568 | ||
569 | (defmethod find-test ((self test-suite) name &key (test #'test-name=)) |
|
570 | (declare (type (or string symbol) name) |
|
571 | (type function test)) |
|
464 | 572 | (find name (tests self) :test test)) |
96 | 573 | |
574 | (defmethod do-test ((self test-suite) &optional test) |
|
575 | (push-result |
|
576 | (if test |
|
282 | 577 | (do-test |
578 | (etypecase test |
|
579 | (test test) |
|
580 | (string (find-test self test)) |
|
581 | (symbol (find-test self (symbol-name test))))) |
|
96 | 582 | (do-test (pop-test self))) |
583 | self)) |
|
584 | ||
585 | ;; HACK 2023-09-01: find better method of declaring failures from |
|
586 | ;; within the body of `deftest'. |
|
229 | 587 | (defmethod do-suite ((self test-suite) &key stream force) |
96 | 588 | (when stream (setf (test-stream self) stream)) |
589 | (with-slots (name stream) self |
|
364 | 590 | (format stream "in suite ~x:~%" |
591 | name) |
|
592 | (format stream "; with ~A~A tests~%" |
|
593 | (if force |
|
594 | "" |
|
595 | (format nil "~A/" |
|
596 | (count t (tests self) |
|
597 | :key (lambda (x) (or (test-lock-p x) (test-persist-p x)))))) |
|
598 | (length (tests self))) |
|
229 | 599 | ;; loop over each test, calling `do-test'. if locked or |
600 | ;; persistent, test is performed. if FORCE is non-nil all tests |
|
601 | ;; are performed. |
|
96 | 602 | (map-tests self |
603 | (lambda (x) |
|
229 | 604 | (when (or force (test-lock-p x) (test-persist-p x)) |
96 | 605 | (let ((res (do-test x))) |
606 | (push-result res self) |
|
607 | (format stream "~@[~<~%~:;~:@(~S~) ~>~]~%" res))))) |
|
608 | ;; compare locked vs expected |
|
609 | (let ((locked (remove-if #'null (map-tests self (lambda (x) (when (test-lock-p x) x))))) |
|
610 | (fails |
|
611 | ;; collect if locked test not expected |
|
612 | (loop for r in (test-results self) |
|
613 | unless (test-pass-p r) |
|
364 | 614 | collect r))) |
96 | 615 | (if (null locked) |
616 | (format stream "~&No tests failed.~%") |
|
617 | (progn |
|
618 | ;; RESEARCH 2023-09-04: print fails ?? |
|
619 | (format stream "~&~A out of ~A ~ |
|
620 | total tests failed: ~ |
|
621 | ~:@(~{~<~% ~1:;~S~>~ |
|
622 | ~^, ~}~)." |
|
623 | (length locked) |
|
624 | (length (tests self)) |
|
625 | locked) |
|
626 | (unless (null fails) |
|
627 | (format stream "~&~A unexpected failures: ~ |
|
628 | ~:@(~{~<~% ~1:;~S~>~ |
|
629 | ~^, ~}~)." |
|
630 | (length fails) |
|
631 | fails)))) |
|
632 | ;; close stream |
|
633 | (finish-output stream) |
|
634 | ;; return values (PASS? LOCKED) |
|
635 | (values (not fails) locked)))) |
|
636 | ||
211
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
637 | (defmethod do-suite ((self string) &key stream) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
638 | (do-suite (ensure-suite self) :stream stream)) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
639 | |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
640 | (defmethod do-suite ((self symbol) &key stream) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
641 | (do-suite (ensure-suite self) :stream stream)) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
642 | |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
643 | (defmethod do-suite ((self null) &key stream) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
644 | (do-suite *test-suite* :stream stream)) |
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
645 | |
96 | 646 | ;;; Checks |
377
49357f8b5e65
xdb fixes (one test still broken), fixed cli main test
Richard Westhaver <ellis@rwest.io>
parents:
365
diff
changeset
|
647 | (eval-always |
364 | 648 | (defun %test (val &optional form) |
649 | (let ((r |
|
650 | (if val |
|
651 | (make-test-result :pass form) |
|
652 | (make-test-result :fail form)))) |
|
653 | ;; (print r *standard-output*) |
|
654 | r))) |
|
655 | ||
656 | (defmacro is (test &rest args) |
|
657 | "The DWIM Check. |
|
96 | 658 | |
211
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
659 | (is (= 1 1)) ;=> #S(TEST-RESULT :TAG :PASS :FORM (= 1 1)) |
96 | 660 | If TEST returns a truthy value, return a PASS test-result, else return |
661 | a FAIL. The TEST is parameterized by ARGS which is a plist or nil. |
|
662 | ||
663 | If ARGS is nil, TEST is bound to to the RESULT slot of the test-result |
|
664 | and evaluated 'as-is'. |
|
665 | ||
666 | (nyi!) |
|
667 | ARGS may contain the following keywords followed by a corresponding |
|
668 | value: |
|
669 | ||
670 | :EXPECTED |
|
671 | ||
672 | :TIMEOUT |
|
673 | ||
674 | :THEN |
|
675 | ||
676 | All other values are treated as let bindings. |
|
677 | " |
|
678 | (with-gensyms (form) |
|
679 | `(if ,(null args) |
|
364 | 680 | (if *testing* |
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
681 | (push-result (trace! (funcall #'rt::%test ,test ',test)) *testing*) |
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
682 | (trace! (funcall #'rt::%test ,test ',test))) |
364 | 683 | (macrolet ((,form (test) `(let ,,(group args 2) ,test))) |
96 | 684 | ;; TODO 2023-09-21: does this work... |
685 | (if *testing* |
|
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
686 | (push-result (trace! (funcall #'rt::%test (,form ,test) ',test) *testing*)) |
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
687 | (trace! (funcall #'rt::%test (,form ,test) ',test))))))) |
96 | 688 | |
689 | (defmacro signals (condition-spec &body body) |
|
690 | "Generates a passing TEST-RESULT if body signals a condition of type |
|
691 | CONDITION-SPEC. BODY is evaluated in a block named NIL, CONDITION-SPEC |
|
692 | is not evaluated." |
|
693 | (let ((block-name (gensym))) |
|
694 | (destructuring-bind (condition &optional reason-control &rest reason-args) |
|
695 | (ensure-list condition-spec) |
|
696 | `(block ,block-name |
|
697 | (handler-bind ((,condition (lambda (c) |
|
365
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
698 | (declare (ignore c)) |
96 | 699 | ;; ok, body threw condition |
700 | ;; TODO 2023-09-05: result collectors |
|
701 | ;; (add-result 'test-passed |
|
702 | ;; :test-expr ',condition) |
|
703 | (return-from ,block-name (make-test-result :pass ',body))))) |
|
704 | (block nil |
|
365
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
705 | (locally (declare (sb-ext:muffle-conditions warning)) |
49c3f3d11432
bug fixes and more tweaks for test macros
Richard Westhaver <ellis@rwest.io>
parents:
364
diff
changeset
|
706 | ,@body))) |
96 | 707 | (fail! |
708 | ',condition |
|
709 | ,@(if reason-control |
|
710 | `(,reason-control ,@reason-args) |
|
711 | `("Failed to signal a ~S" ',condition))) |
|
712 | (return-from ,block-name nil))))) |
|
713 | ||
714 | ;;; Macros |
|
715 | (defmacro deftest (name props &body body) |
|
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
716 | "Build a test with NAME, parameterized by PROPS and with a test form of BODY. |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
717 | |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
718 | PROPS is a plist which currently accepts the following parameters: |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
719 | |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
720 | :PERSIST - re-run this test even if it passes |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
721 | |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
722 | :ARGS - nyi |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
723 | |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
724 | :PROFILE - enable profiling of this test |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
725 | |
437
83f8623a6ec3
std work, renamed :disabled in deftest to :skip
Richard Westhaver <ellis@rwest.io>
parents:
377
diff
changeset
|
726 | :SKIP - don't push this test to the current *TEST-SUITE* |
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
727 | |
364 | 728 | :BENCH - enable benchmarking of this test |
729 | ||
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
730 | BODY is parsed with SB-INT:PARSE-BODY and will fill in documentation |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
731 | and declarations for the test body. |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
732 | " |
96 | 733 | (destructuring-bind (pr doc dec fn) |
734 | (multiple-value-bind (forms dec doc) |
|
735 | ;; parse body with docstring allowed |
|
364 | 736 | (parse-body (or body) :documentation t :whole t) |
737 | `(,props ,doc ,dec ',forms)) |
|
96 | 738 | ;; TODO 2023-09-21: parse plist |
739 | `(let ((obj (make-test |
|
211
f9e0d78b7458
refreshing memory on cli and rt
Richard Westhaver <ellis@rwest.io>
parents:
110
diff
changeset
|
740 | :name ,(format nil "~A" name) |
96 | 741 | :form ,fn |
742 | ,@(when-let ((v (getf pr :persist))) `(:persist ,v)) |
|
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
743 | ,@(when-let ((v (getf pr :args))) `(:args ',v)) |
364 | 744 | ,@(when-let ((v (getf pr :bench))) `(:bench ,v)) |
96 | 745 | ,@(when-let ((v (getf pr :profile))) `(:profile ,v)) |
746 | ,@(when doc `(:doc ,doc)) |
|
514
da17bf652e48
tests and light feature annotations to support darwin (no uring, no mime types)
Richard Westhaver <ellis@rwest.io>
parents:
513
diff
changeset
|
747 | ,@(when dec `(:declare ,dec))))) |
437
83f8623a6ec3
std work, renamed :disabled in deftest to :skip
Richard Westhaver <ellis@rwest.io>
parents:
377
diff
changeset
|
748 | ,(unless (getf pr :skip) '(push-test obj *test-suite*)) |
96 | 749 | obj))) |
750 | ||
751 | (defmacro defsuite (suite-name &rest props) |
|
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
752 | "Define a TEST-SUITE with provided keys. The object returned can be |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
753 | enabled using the IN-SUITE macro, similiar to the DEFPACKAGE API." |
96 | 754 | (check-type suite-name (or symbol string)) |
755 | `(eval-when (:compile-toplevel :load-toplevel :execute) |
|
756 | (let ((obj (make-suite |
|
757 | :name (format nil "~A" ',suite-name) |
|
758 | ,@(when-let ((v (getf props :stream))) `(:stream ,v))))) |
|
759 | (setq *test-suite-list* (spush obj *test-suite-list* :test #'test-name=)) |
|
760 | obj))) |
|
761 | ||
762 | (defmacro in-suite (name) |
|
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
763 | "Set *TEST-SUITE* to the TEST-SUITE object referred to by symbol |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
109
diff
changeset
|
764 | NAME. Return the object." |
96 | 765 | (assert-suite name) |
766 | `(progn |
|
767 | (setq *test-suite* (ensure-suite ,name)))) |