public
Description: BDD for Common Lisp
Homepage:
Clone URL: git://github.com/osteele/cl-spec.git
osteele (author)
Tue Jan 15 07:31:35 -0800 2008
commit  86ec419166158682ab6de9dbe6e4d8458435ddca
tree    98705085f67e3a78d86bbd57d4313892bb1eb478
parent  90633abd1672f695d57edb3e1e06830213ac1a7f
cl-spec / runners.lisp
100644 97 lines (85 sloc) 3.766 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
;;; Copyright 2008 by Oliver Steele. Released under the MIT License.
 
(in-package #:cl-spec)
 
;;;
;;; Running
;;;
 
(defun run-spec (&rest rest)
  "An abbreviation for run-specification."
  (apply #'run-specification rest))
 
(defmethod run-specification ((self specification) &key onsuccess onerror)
  "Run all the examples. Returns a SPECIFICATION-RESULTS.
 
Applies ONSUCCESS or ONERROR to each example name, depending on
whether the example passes. Callbacks are used so that the caller can
show incremental progress during execution."
  (flet ((run-example (name fn)
           "Returns values success and condition"
           (if (specification-setup self)
               (funcall (specification-setup self)))
           (handler-case (progn
                           (funcall fn)
                           (if onsuccess
                               (funcall onsuccess name))
                           t)
             (t (condition)
               (if onerror
                   (funcall onerror name condition))
               (values nil condition)))))
    (multiple-value-bind (results elapsed-time)
        (with-elapsed-time
          (loop for (name . fn) in (specification-examples self)
             collect (multiple-value-bind (success condition)
                         (run-example name fn)
                         (make-instance 'example-result
                                        :name name
                                        :success success
                                        :condition condition))))
      (make-instance 'specification-results
                     :specification self
                     :elapsed-time elapsed-time
                     :examples results))))
 
 
(defmacro with-collecting-specifications (&body body)
  `(let ((*collect-specifications* t)
         (*run-specifications* nil)
         (*specifications* nil))
     ,@body
     (nreverse *specifications*)))
 
;; FIXME: this shouldn't be in the same gf as the method on SPECIFICATION
(defmethod run-specification ((pathname pathname)
                              &rest args
                              &key
                              (format 'text))
  "Run the specifications in PATHNAME reporting ,results to standard output."
  (labels ((write-progress-char (char)
             (format t char)
             (force-output))
           (note-success (&rest rest)
             (declare (ignore rest))
             (write-progress-char "."))
           (note-failure (&rest rest)
             (declare (ignore rest))
             (write-progress-char "F")))
    (let* ((formatter-class
            (concatenate-symbol format "-SPECIFICATION-FORMATTER"))
           (specifications
            (with-collecting-specifications
              (load pathname)))
           (results-children
            (loop for spec in specifications
               collect (run-specification spec
                                     :onsuccess #'note-success
                                     :onerror #'note-failure)))
           (results
            (make-instance 'specification-results-group
                           :children results-children)))
      (apply #'format-specification-results
       (make-instance formatter-class)
       results
       :pathname pathname
       args))))
 
(defmethod run-specification ((string string) &rest args &key &allow-other-keys)
  (apply #'run-specification (pathname string) args))
 
(defmethod specification-runner ((pathname pathname) &key &allow-other-keys)
  "Run the specifications in PATHNAME reporting results to standard output."
  (run-specification pathname))
 
(defmethod specification-runner ((string string) &rest args &key &allow-other-keys)
  (apply #'run-specification (pathname string) args))