KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quilt > reports > XMLFormatter


1 /* XMLFormatter.java */
2
3 package org.quilt.reports;
4
5 import java.io.OutputStream JavaDoc;
6 import java.io.Writer JavaDoc;
7 import java.io.OutputStreamWriter JavaDoc;
8 import java.io.IOException JavaDoc;
9 import java.util.Properties JavaDoc;
10 import java.util.Enumeration JavaDoc;
11 import java.util.Hashtable JavaDoc;
12 import javax.xml.parsers.DocumentBuilder JavaDoc;
13 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
14
15 import org.w3c.dom.Document JavaDoc;
16 import org.w3c.dom.Element JavaDoc;
17 import org.w3c.dom.Text JavaDoc;
18
19 import org.apache.tools.ant.BuildException;
20 import org.apache.tools.ant.util.DOMElementWriter;
21
22 import junit.framework.*;
23
24 import org.quilt.framework.*;
25 import org.quilt.runner.Runner;
26
27 /**
28  * Produce an XML document containing the test data for the run.
29  * This will in general contain the results of many tests, but
30  * only those resulting from one QuiltTest.
31  *
32  * @todo Restructure to produce one XML document for the entire
33  * Ant/Quilt run. This needs to be held by the class
34  * managing the whole run, QuiltTask if it is an Ant run.
35  * Simplest solution: when the test is not forked, pass back
36  * the document as a tree instead of serializing it in text
37  * form to output. The manager can then merge the trees and
38  * output a single document for the run.
39  *
40  * @todo Add flag to suppress generation of (quite verbose) properties
41  * element.
42  */

43 public class XMLFormatter implements Formatter {
44
45     /** Whether to filter Ant/Quilt/JUnit stack traces. */
46     private boolean filtertrace = false;
47    
48     // MODIFY TO EXTEND BaseFormatter, then drop this ///////////////
49
/**
50      * Root around in a junit Test and find a name, should there be one.
51      * @return Test/suite name.
52      */

53     protected static String JavaDoc getTestName (Test test) {
54         if ( test instanceof TestSuite ) {
55             return ( (TestSuite) test ) . getName();
56         } else if ( test instanceof TestCase ) {
57             return ( (TestCase) test ) . getName();
58         } else {
59             return "unknown";
60         }
61     }
62     // END BaseFormatter CODE ///////////////////////////////////////
63

64     private static DocumentBuilderFactory JavaDoc dbf = null;
65
66     // none of this is thread safe; JavaDocs recommend ensuring that
67
// there is only one DocumentBuilder per thread
68
private static DocumentBuilder JavaDoc getDocumentBuilder() {
69         try {
70             if (dbf == null) {
71                 dbf = DocumentBuilderFactory.newInstance();
72             }
73             return dbf.newDocumentBuilder();
74         } catch (Exception JavaDoc exc) {
75             throw new ExceptionInInitializerError JavaDoc(exc);
76         }
77     }
78
79     /**
80      * The XML document. Unfortunately one XML Document is produced
81      * per QuiltTest. Generally there will be many QuiltTests per run.
82      */

83     private Document JavaDoc doc;
84     /** Where the output goes. */
85     private OutputStream JavaDoc out;
86     /** Root node, the Ant/Quilt test run as a whole. */
87     private Element JavaDoc rootNode;
88     /** The runner, usually an instance of runner.BaseTestRunner. */
89     private Runner runner = null;
90     /** Nodes in the document that tests hang off of. */
91     private Hashtable JavaDoc testNodes = new Hashtable JavaDoc(); // key = Test test
92
/** Hash holding information about individual tests. */
93     private Hashtable JavaDoc testStarts = new Hashtable JavaDoc();
94
95     public XMLFormatter() {}
96
97     // FORMATTER INTERFACE //////////////////////////////////////////
98

99     /** Method called at end of test run. */
100     
101     public void endTestSuite(QuiltTest qt) throws BuildException {
102         rootNode.setAttribute("tests", "" + qt.runCount());
103         rootNode.setAttribute("errors", "" + qt.errorCount());
104         rootNode.setAttribute("failures", "" + qt.failureCount());
105         rootNode.setAttribute("time", "" + (qt.getRunTime() / 1000.0));
106         if (out != null) {
107             Writer JavaDoc wri = null;
108             try {
109                 wri = new OutputStreamWriter JavaDoc(out, "UTF8");
110                 wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
111                 (new DOMElementWriter())
112                     .write(rootNode, wri, 0, " ");
113                 wri.flush();
114             } catch (IOException JavaDoc e) {
115                 throw new BuildException("Unable to write log file", e);
116             } finally {
117                 if (out != System.out && out != System.err) {
118                     if (wri != null) {
119                         try {
120                             wri.close();
121                         } catch (IOException JavaDoc e) {}
122                     }
123                 }
124             }
125         }
126     }
127     /** Enable filtering of Ant/Quilt/JUnit lines from stack traces. */
128     public void setFiltertrace (boolean b) {
129         filtertrace = b;
130     }
131     /** Set the output file. */
132     public void setOutput(OutputStream JavaDoc out) {
133         this.out = out;
134     }
135     /** Set the test runner to be used. */
136     public void setRunner(Runner testrunner) {
137         runner = testrunner;
138     }
139     /** Direct the error output. */
140     public void setSystemError(String JavaDoc out) {
141         formatOutput("system-err", out);
142     }
143     /** Direct standard output. */
144     public void setSystemOutput(String JavaDoc out) {
145         formatOutput("system-out", out);
146     }
147     /** Method called at the beginning of the test run. */
148     public void startTestSuite(QuiltTest qt) {
149         doc = getDocumentBuilder().newDocument();
150         rootNode = doc.createElement("testsuite");
151         rootNode.setAttribute("name", qt.getName());
152
153         // Output properties - this creates a lot of meaningless
154
// data, far exceeding the JUnit data of real interest.
155
Element JavaDoc propsElement = doc.createElement("properties");
156         rootNode.appendChild(propsElement);
157         Properties JavaDoc props = qt.getProperties();
158         if (props != null) {
159             Enumeration JavaDoc e = props.propertyNames();
160             while (e.hasMoreElements()) {
161                 String JavaDoc name = (String JavaDoc) e.nextElement();
162                 Element JavaDoc propElement = doc.createElement("property");
163                 propElement.setAttribute("name", name);
164                 propElement.setAttribute("value", props.getProperty(name));
165                 propsElement.appendChild(propElement);
166             }
167         }
168     }
169
170     // TESTLISTENER INTERFACE ///////////////////////////////////////
171
/** Method called when an unexpected error occurs. */
172     public void addError(Test test, Throwable JavaDoc t) {
173         formatError("error", test, t);
174     }
175     /** Method called when a failure (or unexpected error) occurs. */
176     public void addFailure(Test test, Throwable JavaDoc t) {
177         formatError("failure", test, t);
178     }
179     /** Method called when a failure (or unexpected error) occurs. */
180     public void addFailure(Test test, AssertionFailedError t) {
181         addFailure(test, (Throwable JavaDoc) t);
182     }
183     /** Method called when a JUnit test ends. */
184     public void endTest(Test test) {
185         Element JavaDoc testNode = (Element JavaDoc) testNodes.get(test);
186         if (testNode == null) {
187             startTest(test);
188             testNode = (Element JavaDoc) testNodes.get(test);
189         }
190         Long JavaDoc l = (Long JavaDoc) testStarts.get(test);
191         testNode.setAttribute("time",
192             "" + ((System.currentTimeMillis() - l.longValue()) / 1000.0));
193     }
194     /** Called at the beginning of a JUnit test. */
195     public void startTest(Test test) {
196         testStarts.put(test, new Long JavaDoc(System.currentTimeMillis()));
197         Element JavaDoc testNode = doc.createElement("testcase");
198         testNode.setAttribute("name", getTestName(test));
199         rootNode.appendChild(testNode);
200         testNodes.put(test, testNode);
201     }
202
203     // OTHER METHODS ////////////////////////////////////////////////
204
/** Hang an error message off the document tree. */
205     private void formatError(String JavaDoc type, Test test, Throwable JavaDoc t) {
206         if (test != null) {
207             endTest(test);
208         }
209         Element JavaDoc msgNode = doc.createElement(type);
210         Element JavaDoc curNode = null;
211         if (test != null) {
212             curNode = (Element JavaDoc) testNodes.get(test);
213         } else {
214             curNode = rootNode;
215         }
216
217         curNode.appendChild(msgNode);
218
219         String JavaDoc message = t.getMessage();
220         if (message != null && message.length() > 0) {
221             msgNode.setAttribute("message", t.getMessage());
222         }
223         msgNode.setAttribute("type", t.getClass().getName());
224
225         String JavaDoc strace = runner.getFilteredTrace(t, filtertrace);
226         Text JavaDoc trace = doc.createTextNode(strace);
227         msgNode.appendChild(trace);
228     }
229     /**
230      * Hang a text message off the document tree. The message
231      * might be quite long, for example all System.err output
232      * for the run.
233      */

234     private void formatOutput(String JavaDoc type, String JavaDoc output) {
235         Element JavaDoc txtNode = doc.createElement(type);
236         rootNode.appendChild(txtNode);
237         txtNode.appendChild(doc.createCDATASection(output));
238     }
239 }
240
Popular Tags