#|=head1 Testing code One thing is constant in any language- the need to test the code. In this system, a set of function names of tests are stored in the C<*tests*> global. |# (defparameter *tests* nil) #|When we define tests, we are actually writing a defun while, as a side effect, we addding the name of the function to a list of known tests. |# (defmacro deftest (name params &body body) "Create a defun, adding it name to the list of *tests*." `(progn (unless (member ',name *tests*) (push ',name *tests*)) (defun ,name ,params ,@body))) #|Running tests updates two counters: C and P. The C function runs one test while C runs them all. |# (let ((pass 0) (fail 0)) (defun test (want got) "Run one test, comparing 'want' to 'got'." (labels ((white (c) ; returns nil if 'c' is not white space (member c '(#\# #\\ #\Space #\Tab #\Newline #\Linefeed #\Return #\Page) :test #'char=)) (whiteout (s) ; remove all white space (remove-if #'white s)) (samep (x y) ; returns t if the blackspace of x&y, are the same (string= (whiteout (format nil "~(~a~)" x)) (whiteout (format nil "~(~a~)" y))))) (cond ((samep want got) (incf pass)) (t (incf fail) (format t "~&; fail : expected ~a~%" want))) got)) (defun tests () "Run all the tests in *tests*." (labels ((run (x) (format t "~&;testing ~a~%" x) (funcall x))) (when *tests* (setf fail 0 pass 0) (mapcar #'run (reverse *tests*)) (format t "~&; pass : ~a = ~5,1f% ~%; fail : ~a = ~5,1f% ~%" pass (* 100 (/ pass (+ pass fail))) fail (* 100 (/ fail (+ pass fail))))))) ) ;=head1 Examples (deftest ?deftest1 (&aux (a 1)) (test (+ a 1) 2)) ;In this test, we actually see a failure. (deftest ?deftest2 (&aux (a 1)) (test (+ a 1) 3)) ;Note in the following, that the test calls some other function. (deftest ?deftest3 () (test (my-complicated-thing) '(3 4 5))) (defun my-complicated-thing () (member 3 '(1 2 3 4 5))) #|=head1 Credits This code was inspired by Peter Seibel's excellent C system (see L). |#