r5449: *** empty log message ***
[xlunit.git] / fixture.lisp
diff --git a/fixture.lisp b/fixture.lisp
new file mode 100644 (file)
index 0000000..8408cc8
--- /dev/null
@@ -0,0 +1,124 @@
+;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
+;;;; *************************************************************************
+;;;; FILE IDENTIFICATION
+;;;;
+;;;; Name:        fixture.lisp
+;;;; Purpose:     eXtreme Lisp Test Suite
+;;;; Authors:     Kevin Rosenberg and Craig Brozefsky
+;;;;
+;;;; $Id: fixture.lisp,v 1.1 2003/08/04 12:01:54 kevin Exp $
+;;;; *************************************************************************
+
+(in-package #:xlunit)
+
+
+(defclass test-fixture ()
+  ((test-thunk
+    :initarg :test-thunk :reader test-thunk
+    :initform 'perform-test
+    :documentation
+    "A thunk or symbol which will be applied to this instance, a
+test-case, to perform that test-case. Defaults to 'perform-test")
+   (test-name
+    :initarg :test-name
+    :reader test-name
+    :documentation
+    "The name of this test-case, used in reports.")
+   (test-description
+    :initarg :description
+    :reader description
+    :documentation
+    "Short description of this test-case, uses in reports"))
+  (:documentation
+   "Base class for test-fixtures.  Test-cases are instances of test-fixtures."))
+
+(defgeneric setup (test)
+  (:documentation
+   "Method called before performing a test, should set up the
+environment the test-case needs to operate in."))
+
+(defmethod setup ((test test-fixture))
+  t)
+
+(defgeneric teardown (test)
+  (:documentation
+   "Method called after performing a test.  Should reverse everything
+that the setup method did for this instance."))
+
+(defmethod teardown ((test test-fixture))
+  t)
+
+
+(defmacro handler-case-if (test form &body cases)
+  `(if ,test
+       (handler-case
+        ,form
+       ,@cases)
+     ,form))
+
+(defmacro unwind-protect-if (test protected cleanup)
+  `(if ,test
+       (unwind-protect
+          ,protected
+        ,cleanup)
+     (progn ,protected ,cleanup)))
+
+
+(defmethod run-test ((test test-fixture)
+                    &key (result (make-instance 'test-result))
+                    (handle-errors t))
+  "Perform the test represented by the given test-case or test-suite.
+Returns one or more test-result objects, one for each test-case
+performed."
+  (incf (test-count result))
+  (with-slots (failures errors) result
+    (unwind-protect-if handle-errors
+       (handler-case-if handle-errors
+        (let ((res (progn (setup test)
+                          (funcall (test-thunk test) test))))
+          (if (typep res 'test-failure-condition)
+              (push (make-instance 'test-failure
+                      :failed-test test
+                      :thrown-condition res)
+                    failures)))
+        (test-failure-condition (failure)
+                                (push (make-instance 'test-failure
+                                        :failed-test test
+                                        :thrown-condition failure)
+                                      failures))
+        (error (err)
+               (push (make-instance 'test-failure 
+                       :failed-test test 
+                       :thrown-condition err)
+                     errors)))
+       (if handle-errors
+           (handler-case
+               (teardown test)
+             (error (err)
+               (push 
+                (make-instance 'test-failure
+                  :failed-test test :thrown-condition err)
+                errors)))
+         (teardown test))))
+  result)
+
+
+(defun make-test (fixture name &key test-thunk test-suite description)
+  "Create a test-case which is an instance of FIXTURE.  TEST-THUNK is
+the method that will be invoked when perfoming this test, and can be a
+symbol or a lambda taking a single argument, the test-fixture
+instance.  DESCRIPTION is obviously what it says it is."
+  (let ((newtest (make-instance fixture
+                  :test-name (etypecase name
+                               (symbol
+                                (string-downcase (symbol-name name)))
+                               (string
+                                name))
+                  :test-thunk 
+                  (if(and (symbolp name) (null test-thunk))
+                      name
+                    test-thunk)
+                  :description description)))
+       (if test-suite (add-test newtest test-suite))
+       newtest))
+