View Javadoc

1   /*
2    * Copyright  2000-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *
16   */
17  
18  package org.woopi.ant.taskdefs.junit;
19  import java.io.BufferedWriter;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.io.OutputStreamWriter;
23  import java.io.Writer;
24  import java.util.Enumeration;
25  import java.util.Hashtable;
26  import java.util.Properties;
27  import javax.xml.parsers.DocumentBuilder;
28  import javax.xml.parsers.DocumentBuilderFactory;
29  import junit.framework.AssertionFailedError;
30  import junit.framework.Test;
31  import org.apache.tools.ant.BuildException;
32  import org.apache.tools.ant.util.DOMElementWriter;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  import org.w3c.dom.Text;
36  
37  
38  /***
39   * Prints XML output of the test to a specified Writer.
40   *
41   *
42   * @see FormatterElement
43   */
44  
45  public class JavadocXMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants {
46  
47      private static DocumentBuilder getDocumentBuilder() {
48          try {
49              return DocumentBuilderFactory.newInstance().newDocumentBuilder();
50          } catch (Exception exc) {
51              throw new ExceptionInInitializerError(exc);
52          }
53      }
54  
55      /***
56       * The XML document.
57       */
58      private Document doc;
59      /***
60       * The wrapper for the whole testsuite.
61       */
62      private Element rootElement;
63      /***
64       * Element for the current test.
65       */
66      private Hashtable testElements = new Hashtable();
67      /***
68       * tests that failed.
69       */
70      private Hashtable failedTests = new Hashtable();
71      /***
72       * Timing helper.
73       */
74      private Hashtable testStarts = new Hashtable();
75      /***
76       * Where to write the log to.
77       */
78      private OutputStream out;
79  
80      public JavadocXMLJUnitResultFormatter() {
81      }
82  
83      public void setOutput(OutputStream out) {
84          this.out = out;
85      }
86  
87      public void setSystemOutput(String out) {
88          formatOutput(SYSTEM_OUT, out);
89      }
90  
91      public void setSystemError(String out) {
92          formatOutput(SYSTEM_ERR, out);
93      }
94  
95      /***
96       * The whole testsuite started.
97       */
98      public void startTestSuite(JUnitTest suite) {
99          doc = getDocumentBuilder().newDocument();
100         rootElement = doc.createElement(TESTSUITE);
101         rootElement.setAttribute(ATTR_NAME, suite.getName());
102 
103         // Output properties
104         Element propsElement = doc.createElement(PROPERTIES);
105         rootElement.appendChild(propsElement);
106         Properties props = suite.getProperties();
107         if (props != null) {
108             Enumeration e = props.propertyNames();
109             while (e.hasMoreElements()) {
110                 String name = (String) e.nextElement();
111                 Element propElement = doc.createElement(PROPERTY);
112                 propElement.setAttribute(ATTR_NAME, name);
113                 propElement.setAttribute(ATTR_VALUE, props.getProperty(name));
114                 propsElement.appendChild(propElement);
115             }
116         }
117     }
118 
119     /***
120      * The whole testsuite ended.
121      */
122     public void endTestSuite(JUnitTest suite) throws BuildException {
123         rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount());
124         rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount());
125         rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount());
126         rootElement.setAttribute(ATTR_TIME, "" + (suite.getRunTime() / 1000.0));
127         if (out != null) {
128             Writer wri = null;
129             try {
130                 wri = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
131                 wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
132                 (new DOMElementWriter()).write(rootElement, wri, 0, "  ");
133                 wri.flush();
134             } catch (IOException exc) {
135                 throw new BuildException("Unable to write log file", exc);
136             } finally {
137                 if (out != System.out && out != System.err) {
138                     if (wri != null) {
139                         try {
140                             wri.close();
141                         } catch (IOException e) {
142                             // ignore
143                         }
144                     }
145                 }
146             }
147         }
148     }
149 
150     /***
151      * Interface TestListener.
152      *
153      * <p>A new Test is started.
154      */
155     public void startTest(Test t) {
156         testStarts.put(t, new Long(System.currentTimeMillis()));
157     }
158 
159     /***
160      * Interface TestListener.
161      *
162      * <p>A Test is finished.
163      */
164     public void endTest(Test test) {
165         // Fix for bug #5637 - if a junit.extensions.TestSetup is
166         // used and throws an exception during setUp then startTest
167         // would never have been called
168         if (!testStarts.containsKey(test)) {
169             startTest(test);
170         }
171 
172         Element currentTest = null;
173         if (!failedTests.containsKey(test)) {
174             currentTest = doc.createElement(TESTCASE);
175             currentTest.setAttribute(ATTR_NAME,
176                                      JUnitVersionHelper.getTestCaseName(test));
177             // a TestSuite can contain Tests from multiple classes,
178             // even tests with the same name - disambiguate them.
179             currentTest.setAttribute(ATTR_CLASSNAME,
180                                      test.getClass().getName());
181             if (test instanceof Documented) {
182               Documented documented = (Documented)test;         
183               System.out.println("handle Documented : "+ JUnitVersionHelper.getTestCaseName(test));   
184               String javadocData = documented.getMethodDoc(JUnitVersionHelper.getTestCaseName(test));
185               if (javadocData != null && !javadocData.trim().equals("")) { 
186                 Element nested = doc.createElement(JAVADOC);
187                 currentTest.appendChild(nested);
188                 nested.appendChild(doc.createCDATASection(javadocData));
189               }
190             } else {
191               System.out.println(test.getClass().getName()+" is no instance of Documented");
192             }
193             rootElement.appendChild(currentTest);
194             testElements.put(test, currentTest);
195         
196         } else {
197             currentTest = (Element) testElements.get(test);
198         }
199 
200         Long l = (Long) testStarts.get(test);
201         currentTest.setAttribute(ATTR_TIME,
202             "" + ((System.currentTimeMillis() - l.longValue()) / 1000.0));
203     }
204 
205     /***
206      * Interface TestListener for JUnit &lt;= 3.4.
207      *
208      * <p>A Test failed.
209      */
210     public void addFailure(Test test, Throwable t) {
211         formatError(FAILURE, test, t);
212     }
213 
214     /***
215      * Interface TestListener for JUnit &gt; 3.4.
216      *
217      * <p>A Test failed.
218      */
219     public void addFailure(Test test, AssertionFailedError t) {
220         addFailure(test, (Throwable) t);
221     }
222 
223     /***
224      * Interface TestListener.
225      *
226      * <p>An error occurred while running the test.
227      */
228     public void addError(Test test, Throwable t) {
229         formatError(ERROR, test, t);
230     }
231 
232     private void formatError(String type, Test test, Throwable t) {
233         if (test != null) {
234             endTest(test);
235             failedTests.put(test, test);
236         }
237 
238         Element nested = doc.createElement(type);
239         Element currentTest = null;
240         if (test != null) {
241             currentTest = (Element) testElements.get(test);
242         } else {
243             currentTest = rootElement;
244         }
245 
246         currentTest.appendChild(nested);
247 
248         String message = t.getMessage();
249         if (message != null && message.length() > 0) {
250             nested.setAttribute(ATTR_MESSAGE, t.getMessage());
251         }
252         nested.setAttribute(ATTR_TYPE, t.getClass().getName());
253 
254         String strace = JUnitTestRunner.getFilteredTrace(t);
255         Text trace = doc.createTextNode(strace);
256         nested.appendChild(trace);
257     }
258 
259     private void formatOutput(String type, String output) {
260         Element nested = doc.createElement(type);
261         rootElement.appendChild(nested);
262         nested.appendChild(doc.createCDATASection(output));
263     }
264 
265 } // JavadocXMLJUnitResultFormatter