Fix bugs in the handling and reporting of unexpected errors
[fiveam.git] / src / explain.lisp
1 ;; -*- lisp -*-
2
3 (in-package :it.bese.FiveAM)
4
5 ;;;; * Analyzing the results
6
7 ;;;; Just as important as defining and runnig the tests is
8 ;;;; understanding the results. FiveAM provides the function EXPLAIN
9 ;;;; which prints a human readable summary (number passed, number
10 ;;;; failed, what failed and why, etc.) of a list of test results.
11
12 (defmethod explain ((exp detailed-text-explainer) results &optional (stream *test-dribble*))
13   "Given a list of test results report write to stream detailed
14   human readable statistics regarding the results."
15   (multiple-value-bind (num-checks passed num-passed passed%
16                                    skipped num-skipped skipped%
17                                    failed num-failed failed%
18                                    unknown num-unknown unknown%)
19       (partition-results results)
20     (declare (ignore passed))
21     (when (zerop num-checks)
22       (format stream "~%Didn't run anything...huh?")
23       (return-from explain nil))
24     (format stream "~%Did ~D check~P.~%"
25             num-checks num-checks)
26     (format stream "   Pass: ~D (~2D%)~%" num-passed passed%)
27     (format stream "   Skip: ~D (~2D%)~%" num-skipped skipped%)
28     (format stream "   Fail: ~D (~2D%)~%" num-failed failed%)
29     (when unknown
30       (format stream "   UNKNOWN RESULTS: ~D (~2D)~%" num-unknown unknown%))
31     (terpri stream)
32     (when failed
33       (format stream "Failure Details:~%")
34       (dolist (f failed)
35         (format stream "~A ~@{[~A]~}: ~%" 
36                 (name (test-case f))
37                 (description (test-case f)))
38         (format stream "    ~A.~%" (reason f)))
39       (terpri stream))
40     (when skipped
41       (format stream "Skip Details:~%")
42       (dolist (f skipped)
43         (format stream "~A ~@{[~A]~}: ~%" 
44                 (name (test-case f))
45                 (description (test-case f)))
46         (format stream "    ~A.~%" (reason f)))
47       (terpri *test-dribble*))))
48
49 (defmethod explain ((exp simple-text-explainer) results &optional (stream *test-dribble*))
50   (multiple-value-bind (num-checks passed num-passed passed%
51                                    skipped num-skipped skipped%
52                                    failed num-failed failed%
53                                    unknown num-unknown unknown%)
54       (partition-results results)
55     (declare (ignore passed passed% skipped skipped% failed failed% unknown unknown%))
56     (format stream "~&Ran ~D checks, ~D passed" num-checks num-passed)
57     (when (plusp num-skipped)
58       (format stream ", ~D skipped " num-skipped))
59     (format stream " and ~D failed.~%" num-failed)
60     (when (plusp num-unknown)
61       (format stream "~D UNKNOWN RESULTS.~%" num-unknown))))
62
63 (defun partition-results (results-list)
64   (let ((num-checks (length results-list)))
65     (destructuring-bind (passed skipped failed unknown)
66         (partitionx results-list
67                     (lambda (res)
68                       (typep res 'test-passed))
69                     (lambda (res)
70                       (typep res 'test-skipped))
71                     (lambda (res)
72                       (typep res 'test-failure))
73                     t)
74       (if (zerop num-checks)
75           (values 0
76                   nil 0 0
77                   nil 0 0
78                   nil 0 0
79                   nil 0 0)
80           (values
81            num-checks
82            passed (length passed) (floor (* 100 (/ (length passed) num-checks)))
83            skipped (length skipped) (floor (* 100 (/ (length skipped) num-checks)))
84            failed (length failed) (floor (* 100 (/ (length failed) num-checks)))
85            unknown (length unknown) (floor (* 100 (/ (length failed) num-checks))))))))
86
87 ;; Copyright (c) 2002-2003, Edward Marco Baringer
88 ;; All rights reserved. 
89 ;; 
90 ;; Redistribution and use in source and binary forms, with or without
91 ;; modification, are permitted provided that the following conditions are
92 ;; met:
93 ;; 
94 ;;  - Redistributions of source code must retain the above copyright
95 ;;    notice, this list of conditions and the following disclaimer.
96 ;; 
97 ;;  - Redistributions in binary form must reproduce the above copyright
98 ;;    notice, this list of conditions and the following disclaimer in the
99 ;;    documentation and/or other materials provided with the distribution.
100 ;;
101 ;;  - Neither the name of Edward Marco Baringer, nor BESE, nor the names
102 ;;    of its contributors may be used to endorse or promote products
103 ;;    derived from this software without specific prior written permission.
104 ;; 
105 ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
106 ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
107 ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
108 ;; A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
109 ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
110 ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
111 ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
112 ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
113 ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
114 ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
115 ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE