KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > internal > server > runner > XMLFormatter


1 /*
2  * ========================================================================
3  *
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * ========================================================================
19  */

20 package org.apache.cactus.internal.server.runner;
21
22 import java.text.NumberFormat JavaDoc;
23 import java.util.Locale JavaDoc;
24
25 import junit.framework.AssertionFailedError;
26 import junit.framework.Test;
27 import junit.framework.TestFailure;
28 import junit.framework.TestListener;
29 import junit.framework.TestResult;
30
31 import org.apache.cactus.internal.util.JUnitVersionHelper;
32 import org.apache.cactus.internal.util.StringUtil;
33
34 /**
35  * Format the test results in XML.
36  *
37  * @version $Id: XMLFormatter.java,v 1.2 2004/08/08 09:04:08 vmassol Exp $
38  */

39 public class XMLFormatter implements XMLConstants, TestListener
40 {
41     /**
42      * Default stack filter patterns.
43      */

44     private static final String JavaDoc[] DEFAULT_STACK_FILTER_PATTERNS = new String JavaDoc[]
45         {
46             "org.apache.cactus.AbstractTestCase",
47             "org.apache.cactus.AbstractWebTestCase",
48             "org.apache.cactus.FilterTestCase",
49             "org.apache.cactus.JspTestCase",
50             "org.apache.cactus.ServletTestCase",
51             "junit.framework.TestCase",
52             "junit.framework.TestResult",
53             "junit.framework.TestSuite",
54             "junit.framework.Assert.", // don't filter AssertionFailure
55
"java.lang.reflect.Method.invoke("
56         };
57
58     /**
59      * (optional) Name of the XSL stylesheet to put in the returned XML string
60      * so that the browser will try to apply it (IE at least, I don't know
61      * about the others).
62      */

63     private String JavaDoc xslFileName;
64
65     /**
66      * The name of the test suite class.
67      */

68     private String JavaDoc suiteClassName;
69
70     /**
71      * Duration it took to execute all the tests.
72      */

73     private long totalDuration;
74
75     /**
76      * Encoding to use for the returned XML. Defaults to "UTF-8".
77      */

78     private String JavaDoc encoding = "UTF-8";
79     
80     /**
81      * Time current test was started
82      */

83     private long currentTestStartTime;
84
85     /**
86      * The number format used to convert durations into strings. Don't use the
87      * default locale for that, because the resulting string needs to use
88      * dotted decimal notation for an XSLT transformation to work correctly.
89      */

90     private NumberFormat JavaDoc durationFormat = NumberFormat.getInstance(Locale.US);
91
92     /**
93      * XML string containing executed test case results
94      */

95     private StringBuffer JavaDoc currentTestCaseResults = new StringBuffer JavaDoc();
96
97     /**
98      * Current test failure (XML string) : failure or error.
99      */

100     private String JavaDoc currentTestFailure;
101
102     /**
103      * Sets the XSL stylesheet file name to put in the returned XML string
104      * so that the browser will try to apply it (IE at least, I don't know
105      * about the others).
106      *
107      * @param theXslFileName the file name (relative to the webapp root)
108      */

109     public void setXslFileName(String JavaDoc theXslFileName)
110     {
111         this.xslFileName = theXslFileName;
112     }
113
114     /**
115      * @param theEncoding the encoding to use for the returned XML.
116      */

117     public void setEncoding(String JavaDoc theEncoding)
118     {
119         this.encoding = theEncoding;
120     }
121
122     /**
123      * @return the encoding to use for the returned XML
124      */

125     public String JavaDoc getEncoding()
126     {
127         return this.encoding;
128     }
129     
130     /**
131      * @return the suite class name
132      */

133     public String JavaDoc getSuiteClassName()
134     {
135         return this.suiteClassName;
136     }
137
138     /**
139      * Sets the suite class name that was executed.
140      *
141      * @param theSuiteClassName the suite class name
142      */

143     public void setSuiteClassName(String JavaDoc theSuiteClassName)
144     {
145         this.suiteClassName = theSuiteClassName;
146     }
147
148     /**
149      * @return the total duration as a string
150      */

151     public String JavaDoc getTotalDurationAsString()
152     {
153         return getDurationAsString(this.totalDuration);
154     }
155
156     /**
157      * Comvert a duration expressed as a long into a string.
158      *
159      * @param theDuration the duration to convert to string
160      * @return the total duration as a string
161      */

162     private String JavaDoc getDurationAsString(long theDuration)
163     {
164         return durationFormat.format((double) theDuration / 1000);
165     }
166
167     /**
168      * Sets the duration it took to execute all the tests.
169      *
170      * @param theDuration the time it took
171      */

172     public void setTotalDuration(long theDuration)
173     {
174         this.totalDuration = theDuration;
175     }
176
177     /**
178      * Formats the test result as an XML string.
179      *
180      * @param theResult the test result object
181      * @return the XML string representation of the test results
182      */

183     public String JavaDoc toXML(TestResult theResult)
184     {
185         StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
186
187         xml.append("<?xml version=\"1.0\" encoding=\"" + getEncoding()
188             + "\"?>");
189
190         if (this.xslFileName != null)
191         {
192             xml.append("<?xml-stylesheet type=\"text/xsl\" " + "href=\""
193                 + this.xslFileName + "\"?>");
194         }
195
196         xml.append("<" + TESTSUITES + ">");
197
198         xml.append("<" + TESTSUITE + " " + ATTR_NAME + "=\""
199             + getSuiteClassName() + "\" " + ATTR_TESTS + "=\""
200             + theResult.runCount() + "\" " + ATTR_FAILURES + "=\""
201             + theResult.failureCount() + "\" " + ATTR_ERRORS + "=\""
202             + theResult.errorCount() + "\" " + ATTR_TIME + "=\""
203             + getTotalDurationAsString() + "\">");
204
205         xml.append(this.currentTestCaseResults.toString());
206
207         xml.append("</" + TESTSUITE + ">");
208         xml.append("</" + TESTSUITES + ">");
209
210         return xml.toString();
211     }
212
213     /**
214      * Event called by the base test runner when the test starts.
215      *
216      * @param theTest the test object being executed
217      */

218     public void startTest(Test theTest)
219     {
220         this.currentTestStartTime = System.currentTimeMillis();
221         this.currentTestFailure = null;
222     }
223
224     /**
225      * Event called by the base test runner when the test fails with an error.
226      *
227      * @param theTest the test object that failed
228      * @param theThrowable the exception that was thrown
229      */

230     public void addError(Test theTest, Throwable JavaDoc theThrowable)
231     {
232         TestFailure failure = new TestFailure(theTest, theThrowable);
233         StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
234
235         xml.append("<" + ERROR + " " + ATTR_MESSAGE + "=\""
236             + xmlEncode(failure.thrownException().getMessage()) + "\" "
237             + ATTR_TYPE + "=\""
238             + failure.thrownException().getClass().getName() + "\">");
239         xml.append(xmlEncode(StringUtil.exceptionToString(
240             failure.thrownException(), DEFAULT_STACK_FILTER_PATTERNS)));
241         xml.append("</" + ERROR + ">");
242
243         this.currentTestFailure = xml.toString();
244     }
245
246     /**
247      * Event called by the base test runner when the test fails with a failure.
248      *
249      * @param theTest the test object that failed
250      * @param theError the exception that was thrown
251      */

252     public void addFailure(Test theTest, AssertionFailedError theError)
253     {
254         TestFailure failure = new TestFailure(theTest, theError);
255         StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
256
257         xml.append("<" + FAILURE + " " + ATTR_MESSAGE + "=\""
258             + xmlEncode(failure.thrownException().getMessage()) + "\" "
259             + ATTR_TYPE + "=\""
260             + failure.thrownException().getClass().getName() + "\">");
261         xml.append(xmlEncode(StringUtil.exceptionToString(
262             failure.thrownException(), DEFAULT_STACK_FILTER_PATTERNS)));
263         xml.append("</" + FAILURE + ">");
264
265         this.currentTestFailure = xml.toString();
266     }
267
268     /**
269      * Event called by the base test runner when the test ends.
270      *
271      * @param theTest the test object being executed
272      */

273     public void endTest(Test theTest)
274     {
275         StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
276         String JavaDoc duration = getDurationAsString(System.currentTimeMillis()
277             - this.currentTestStartTime);
278
279         xml.append("<" + TESTCASE + " " + ATTR_NAME + "=\""
280             + JUnitVersionHelper.getTestCaseName(theTest) + "\" "
281             + ATTR_TIME + "=\"" + duration + "\">");
282
283         if (this.currentTestFailure != null)
284         {
285             xml.append(this.currentTestFailure);
286         }
287
288         xml.append("</" + TESTCASE + ">");
289
290         this.currentTestCaseResults.append(xml.toString());
291     }
292
293     /**
294      * Escapes reserved XML characters.
295      *
296      * @param theString the string to escape
297      * @return the escaped string
298      */

299     private String JavaDoc xmlEncode(String JavaDoc theString)
300     {
301         String JavaDoc newString;
302
303         // It is important to replace the "&" first as the other replacements
304
// also introduces "&" chars ...
305
newString = XMLFormatter.replace(theString, '&', "&amp;");
306
307         newString = XMLFormatter.replace(newString, '<', "&lt;");
308         newString = XMLFormatter.replace(newString, '>', "&gt;");
309         newString = XMLFormatter.replace(newString, '\"', "&quot;");
310
311         return newString;
312     }
313
314     /**
315      * Replaces a character in a string by a substring.
316      *
317      * @param theBaseString the base string in which to perform replacements
318      * @param theChar the char to look for
319      * @param theNewString the string with which to replace the char
320      * @return the string with replacements done or null if the input string
321      * was null
322      */

323     private static String JavaDoc replace(String JavaDoc theBaseString, char theChar,
324         String JavaDoc theNewString)
325     {
326         if (theBaseString == null)
327         {
328             return null;
329         }
330
331         final int len = theBaseString.length() - 1;
332         int pos = -1;
333
334         while ((pos = theBaseString.indexOf(theChar, pos + 1)) > -1)
335         {
336             if (pos == 0)
337             {
338                 final String JavaDoc after = theBaseString.substring(1);
339
340                 theBaseString = theNewString + after;
341             }
342             else if (pos == len)
343             {
344                 final String JavaDoc before = theBaseString.substring(0, pos);
345
346                 theBaseString = before + theNewString;
347             }
348             else
349             {
350                 final String JavaDoc before = theBaseString.substring(0, pos);
351                 final String JavaDoc after = theBaseString.substring(pos + 1);
352
353                 theBaseString = before + theNewString + after;
354             }
355         }
356
357         return theBaseString;
358     }
359
360 }
361
Popular Tags