Mercurial > lasercutter
comparison src/clojure/test/junit.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
1 ; Copyright (c) Rich Hickey. All rights reserved. | |
2 ; The use and distribution terms for this software are covered by the | |
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 ; By using this software in any fashion, you are agreeing to be bound by | |
6 ; the terms of this license. | |
7 ; You must not remove this notice, or any other, from this software. | |
8 | |
9 ;; test/junit.clj: Extension to clojure.test for JUnit-compatible XML output | |
10 | |
11 ;; by Jason Sankey | |
12 ;; June 2009 | |
13 | |
14 ;; DOCUMENTATION | |
15 ;; | |
16 | |
17 (ns ^{:doc "clojure.test extension for JUnit-compatible XML output. | |
18 | |
19 JUnit (http://junit.org/) is the most popular unit-testing library | |
20 for Java. As such, tool support for JUnit output formats is | |
21 common. By producing compatible output from tests, this tool | |
22 support can be exploited. | |
23 | |
24 To use, wrap any calls to clojure.test/run-tests in the | |
25 with-junit-output macro, like this: | |
26 | |
27 (use 'clojure.test) | |
28 (use 'clojure.test.junit) | |
29 | |
30 (with-junit-output | |
31 (run-tests 'my.cool.library)) | |
32 | |
33 To write the output to a file, rebind clojure.test/*test-out* to | |
34 your own PrintWriter (perhaps opened using | |
35 clojure.java.io/writer)." | |
36 :author "Jason Sankey"} | |
37 clojure.test.junit | |
38 (:require [clojure.stacktrace :as stack] | |
39 [clojure.test :as t])) | |
40 | |
41 ;; copied from clojure.contrib.lazy-xml | |
42 (def ^{:private true} | |
43 escape-xml-map | |
44 (zipmap "'<>\"&" (map #(str \& % \;) '[apos lt gt quot amp]))) | |
45 (defn- escape-xml [text] | |
46 (apply str (map #(escape-xml-map % %) text))) | |
47 | |
48 (def *var-context*) | |
49 (def *depth*) | |
50 | |
51 (defn indent | |
52 [] | |
53 (dotimes [n (* *depth* 4)] (print " "))) | |
54 | |
55 (defn start-element | |
56 [tag pretty & [attrs]] | |
57 (if pretty (indent)) | |
58 (print (str "<" tag)) | |
59 (if (seq attrs) | |
60 (doseq [[key value] attrs] | |
61 (print (str " " (name key) "=\"" (escape-xml value) "\"")))) | |
62 (print ">") | |
63 (if pretty (println)) | |
64 (set! *depth* (inc *depth*))) | |
65 | |
66 (defn element-content | |
67 [content] | |
68 (print (escape-xml content))) | |
69 | |
70 (defn finish-element | |
71 [tag pretty] | |
72 (set! *depth* (dec *depth*)) | |
73 (if pretty (indent)) | |
74 (print (str "</" tag ">")) | |
75 (if pretty (println))) | |
76 | |
77 (defn test-name | |
78 [vars] | |
79 (apply str (interpose "." | |
80 (reverse (map #(:name (meta %)) vars))))) | |
81 | |
82 (defn package-class | |
83 [name] | |
84 (let [i (.lastIndexOf name ".")] | |
85 (if (< i 0) | |
86 [nil name] | |
87 [(.substring name 0 i) (.substring name (+ i 1))]))) | |
88 | |
89 (defn start-case | |
90 [name classname] | |
91 (start-element 'testcase true {:name name :classname classname})) | |
92 | |
93 (defn finish-case | |
94 [] | |
95 (finish-element 'testcase true)) | |
96 | |
97 (defn suite-attrs | |
98 [package classname] | |
99 (let [attrs {:name classname}] | |
100 (if package | |
101 (assoc attrs :package package) | |
102 attrs))) | |
103 | |
104 (defn start-suite | |
105 [name] | |
106 (let [[package classname] (package-class name)] | |
107 (start-element 'testsuite true (suite-attrs package classname)))) | |
108 | |
109 (defn finish-suite | |
110 [] | |
111 (finish-element 'testsuite true)) | |
112 | |
113 (defn message-el | |
114 [tag message expected-str actual-str] | |
115 (indent) | |
116 (start-element tag false (if message {:message message} {})) | |
117 (element-content | |
118 (let [[file line] (t/file-position 5) | |
119 detail (apply str (interpose | |
120 "\n" | |
121 [(str "expected: " expected-str) | |
122 (str " actual: " actual-str) | |
123 (str " at: " file ":" line)]))] | |
124 (if message (str message "\n" detail) detail))) | |
125 (finish-element tag false) | |
126 (println)) | |
127 | |
128 (defn failure-el | |
129 [message expected actual] | |
130 (message-el 'failure message (pr-str expected) (pr-str actual))) | |
131 | |
132 (defn error-el | |
133 [message expected actual] | |
134 (message-el 'error | |
135 message | |
136 (pr-str expected) | |
137 (if (instance? Throwable actual) | |
138 (with-out-str (stack/print-cause-trace actual t/*stack-trace-depth*)) | |
139 (prn actual)))) | |
140 | |
141 ;; This multimethod will override test-is/report | |
142 (defmulti junit-report :type) | |
143 | |
144 (defmethod junit-report :begin-test-ns [m] | |
145 (t/with-test-out | |
146 (start-suite (name (ns-name (:ns m)))))) | |
147 | |
148 (defmethod junit-report :end-test-ns [_] | |
149 (t/with-test-out | |
150 (finish-suite))) | |
151 | |
152 (defmethod junit-report :begin-test-var [m] | |
153 (t/with-test-out | |
154 (let [var (:var m)] | |
155 (binding [*var-context* (conj *var-context* var)] | |
156 (start-case (test-name *var-context*) (name (ns-name (:ns (meta var))))))))) | |
157 | |
158 (defmethod junit-report :end-test-var [m] | |
159 (t/with-test-out | |
160 (finish-case))) | |
161 | |
162 (defmethod junit-report :pass [m] | |
163 (t/with-test-out | |
164 (t/inc-report-counter :pass))) | |
165 | |
166 (defmethod junit-report :fail [m] | |
167 (t/with-test-out | |
168 (t/inc-report-counter :fail) | |
169 (failure-el (:message m) | |
170 (:expected m) | |
171 (:actual m)))) | |
172 | |
173 (defmethod junit-report :error [m] | |
174 (t/with-test-out | |
175 (t/inc-report-counter :error) | |
176 (error-el (:message m) | |
177 (:expected m) | |
178 (:actual m)))) | |
179 | |
180 (defmethod junit-report :default [_]) | |
181 | |
182 (defmacro with-junit-output | |
183 "Execute body with modified test-is reporting functions that write | |
184 JUnit-compatible XML output." | |
185 {:added "1.1"} | |
186 [& body] | |
187 `(binding [t/report junit-report | |
188 *var-context* (list) | |
189 *depth* 1] | |
190 (println "<?xml version=\"1.0\" encoding=\"UTF-8\"?>") | |
191 (println "<testsuites>") | |
192 (let [result# ~@body] | |
193 (println "</testsuites>") | |
194 result#))) |