1 package junitour;
2
3 import org.apache.tools.ant.BuildException;
4 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner;
5 import org.apache.tools.ant.taskdefs.optional.junit.XMLConstants;
6 import org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper;
7 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
8 import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
9 import org.apache.tools.ant.util.DOMElementWriter;
10 import org.w3c.dom.Document;
11 import org.w3c.dom.Element;
12 import org.w3c.dom.Text;
13
14 import java.util.Hashtable;
15 import java.util.Properties;
16 import java.util.Enumeration;
17 import java.util.Map;
18 import java.io.*;
19
20 import junit.framework.Test;
21 import junit.framework.AssertionFailedError;
22
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class UnitourResultFormatter implements JUnitResultFormatter {
48
49 private static final String INCOMPLETE = "incomplete";
50 private static final String ATTR_INCOMPLETES = "incompletes";
51 private int currentSuiteIncompleteCounter;
52 private int suiteErrorCompensationCounter;
53 private int suiteFailureCompensationCounter;
54 static final double THOUSAND_DOUBLE = 1000.0;
55
56
57
58
59 private static final String [] XTRA_TRACE_FILTERS = {
60 "com.werken.werkz",
61 "org.apache.maven.jelly",
62 "org.apache.commons.jelly",
63 "java.lang.reflect",
64 "sun.reflect.NativeMethodAccessorImpl.invoke",
65 "sun.reflect.DelegatingMethodAccessorImpl.invoke",
66 "com.werken.forehead",
67 };
68
69 public UnitourResultFormatter() {
70 }
71
72 private static DocumentBuilder getDocumentBuilder() {
73 try {
74 return DocumentBuilderFactory.newInstance().newDocumentBuilder();
75 }
76 catch (ParserConfigurationException ex) {
77 throw new ExceptionInInitializerError(ex);
78 }
79 }
80
81
82 private Document doc;
83
84 private Element rootElement;
85
86 private Map<Test,Element> testElements = new Hashtable<Test,Element> (10);
87
88 private Map<Test,Long> testStarts = new Hashtable<Test,Long>(10);
89
90 private OutputStream out;
91
92 public void setOutput(OutputStream out) {
93 this.out = out;
94 }
95
96 public void setSystemOutput(String out) {
97 formatOutput(XMLConstants.SYSTEM_OUT, out);
98 }
99
100 public void setSystemError(String out) {
101 formatOutput(XMLConstants.SYSTEM_ERR, out);
102 }
103
104
105
106
107 public void startTestSuite(JUnitTest suite) {
108
109
110
111 currentSuiteIncompleteCounter = 0;
112 suiteFailureCompensationCounter = 0;
113 suiteErrorCompensationCounter = 0;
114
115 doc = getDocumentBuilder().newDocument();
116 rootElement = doc.createElement(XMLConstants.TESTSUITE);
117 rootElement.setAttribute(XMLConstants.ATTR_NAME, suite.getName());
118
119
120 Element propsElement = doc.createElement(XMLConstants.PROPERTIES);
121 rootElement.appendChild(propsElement);
122 Properties props = suite.getProperties();
123
124 filterProperties(doc, props, propsElement);
125 }
126
127
128
129
130
131
132
133
134
135
136 static void filterProperties(Document document, Properties props, Element propsElement) {
137 if (props != null) {
138 Enumeration e = props.propertyNames();
139 while (e.hasMoreElements()) {
140 String name = (String) e.nextElement();
141 if (name.startsWith("java.")) continue;
142 if (name.startsWith("maven.")) continue;
143 if (name.startsWith("sun.")) continue;
144 if (name.startsWith("line.separator")) continue;
145 Element propElement = document.createElement(XMLConstants.PROPERTY);
146 propElement.setAttribute(XMLConstants.ATTR_NAME, name);
147 propElement.setAttribute(XMLConstants.ATTR_VALUE, props.getProperty(name));
148 propsElement.appendChild(propElement);
149 }
150 }
151 }
152
153
154
155
156 public void endTestSuite(JUnitTest suite) throws BuildException {
157
158 rootElement.setAttribute(XMLConstants.ATTR_TESTS, "" + suite.runCount());
159 rootElement.setAttribute(XMLConstants.ATTR_FAILURES, "" + (suite.failureCount()-suiteFailureCompensationCounter));
160 rootElement.setAttribute(XMLConstants.ATTR_ERRORS, "" + (suite.errorCount()-suiteErrorCompensationCounter));
161
162
163 rootElement.setAttribute(ATTR_INCOMPLETES, "" + currentSuiteIncompleteCounter);
164
165 rootElement.setAttribute(XMLConstants.ATTR_TIME, "" + (suite.getRunTime() / THOUSAND_DOUBLE));
166 if (out != null) {
167 Writer wri = null;
168 try {
169 wri = new OutputStreamWriter(out, "UTF8");
170 wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
171 (new DOMElementWriter()).write(rootElement, wri, 0, " ");
172 wri.flush();
173 }
174 catch (UnsupportedEncodingException exc) {
175 throw new BuildException("Unable to write log file", exc);
176 }
177 catch (IOException ex) {
178 throw new BuildException("Unable to write log file", ex);
179 }
180 finally {
181 if (out != System.out && out != System.err) {
182 if (wri != null) {
183 try {
184 wri.close();
185 }
186 catch (IOException e) {
187 }
188 }
189 }
190 }
191 }
192 }
193
194
195
196
197
198
199 public void startTest(Test t) {
200 testStarts.put(t, new Long(System.currentTimeMillis()));
201
202 Element currentTest = doc.createElement(XMLConstants.TESTCASE);
203 currentTest.setAttribute(XMLConstants.ATTR_NAME,
204 JUnitVersionHelper.getTestCaseName(t));
205 rootElement.appendChild(currentTest);
206 testElements.put(t, currentTest);
207 }
208
209
210
211
212
213
214 public void endTest(Test test) {
215 Element currentTest = testElements.get(test);
216
217
218
219
220 if (currentTest == null) {
221 startTest(test);
222 currentTest = testElements.get(test);
223 }
224
225 Long testStartTime = testStarts.get(test);
226 currentTest.setAttribute(XMLConstants.ATTR_TIME, String.valueOf((double) (System.currentTimeMillis() -
227 testStartTime.longValue()) / THOUSAND_DOUBLE));
228 }
229
230
231
232
233
234
235 public void addFailure(Test test, Throwable t) {
236
237 final String name = t.getClass().getName();
238 debug(name, "addFailure", "testing type");
239 final boolean instance = UnitTestIncomplete.class.isInstance(t);
240 debug(name, "addFailure", "instance of UnitTestIncomplete ?" + instance);
241
242
243 if (UnitourResultFormatter.isIncompleteTest(t) ||
244 UnitTestIncomplete.class.isAssignableFrom(t.getClass())) {
245 debug(name, "addFailure", "THIS is AN IN-COMPLETE TEST !!!!!!!!!!!!!!!!");
246 addIncomplete(test, t);
247 suiteFailureCompensationCounter++;
248 }
249 else {
250 debug(name, "addFailure", "THIS is an normal error, instead of an IN-COMPLETE TEST !!!!!!!!!!!!!!!!");
251 formatError(XMLConstants.FAILURE, test, t);
252 }
253 }
254
255 private void addIncomplete(Test test, Throwable t) {
256 formatError(INCOMPLETE, test, t);
257 currentSuiteIncompleteCounter++;
258 }
259
260 private void debug(final String name, String method, String message) {
261
262
263
264
265 }
266
267
268
269
270
271
272 public void addFailure(Test test, AssertionFailedError t) {
273 addFailure(test, (Throwable) t);
274 }
275
276
277
278
279
280
281 public void addError(Test test, Throwable t) {
282
283
284
285
286
287
288
289
290
291
292
293 if (isIncompleteTest(t)) {
294 addIncomplete(test, t);
295 suiteErrorCompensationCounter++;
296 }
297 else {
298 formatError(XMLConstants.ERROR, test, t);
299 }
300 }
301
302 static boolean isIncompleteTest(Throwable t) {
303 final boolean is = UnitTestIncompleteError.isTestIncompleteError(t) ||
304 UnitTestIncomplete.class.isAssignableFrom(t.getClass());
305 return is;
306 }
307
308
309
310 private void formatError(String type, Test test, Throwable t) {
311 if (test != null) {
312 endTest(test);
313 }
314
315 Element nested = doc.createElement(type);
316 Element currentTest;
317 if (test != null) {
318 currentTest = (Element) testElements.get(test);
319 }
320 else {
321 currentTest = rootElement;
322 }
323
324 currentTest.appendChild(nested);
325
326 String message = t.getMessage();
327 if (message != null && message.length() > 0) {
328 nested.setAttribute(XMLConstants.ATTR_MESSAGE, t.getMessage());
329 }
330 nested.setAttribute(XMLConstants.ATTR_TYPE, t.getClass().getName());
331
332 String strace = filterStack(JUnitTestRunner.getFilteredTrace(t));
333 Text trace = doc.createTextNode(strace);
334 nested.appendChild(trace);
335 }
336
337 private void formatOutput(String type, String output) {
338 Element nested = doc.createElement(type);
339 rootElement.appendChild(nested);
340 nested.appendChild(doc.createCDATASection(output));
341 }
342
343
344
345
346
347
348 public String filterStack(String stack) {
349 StringWriter sw = new StringWriter();
350 PrintWriter pw = new PrintWriter(sw);
351 StringReader sr = new StringReader(stack);
352 BufferedReader br = new BufferedReader(sr);
353
354 String line;
355 try {
356 while ((line = br.readLine()) != null) {
357 if (!filterLineByJunitour(line)) {
358 pw.println(line);
359 }
360 }
361 } catch (Exception IOException) {
362 return stack;
363 }
364 return sw.toString();
365 }
366
367
368
369
370
371
372
373
374
375
376
377
378 boolean filterLineByJunitour(String line) {
379 for (int i = 0; i < XTRA_TRACE_FILTERS.length; i++) {
380 if (line.indexOf(XTRA_TRACE_FILTERS[i]) > 0) {
381 return true;
382 }
383 }
384 return false;
385 }
386
387 }