1 package org.apache.maven.surefire.report;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedWriter;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.OutputStreamWriter;
27 import java.io.PrintWriter;
28 import java.io.UnsupportedEncodingException;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Enumeration;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Properties;
35 import java.util.StringTokenizer;
36 import org.codehaus.plexus.util.IOUtil;
37 import org.codehaus.plexus.util.xml.Xpp3Dom;
38 import org.codehaus.plexus.util.xml.Xpp3DomWriter;
39
40
41
42
43
44
45
46 public class XMLReporter
47 extends AbstractReporter
48 {
49 private static final String LS = System.getProperty( "line.separator" );
50
51 private final File reportsDirectory;
52
53 private final boolean deleteOnStarting;
54
55 private final String reportNameSuffix;
56
57 private final List results = Collections.synchronizedList( new ArrayList() );
58
59
60 public XMLReporter( boolean trimStackTrace, File reportsDirectory )
61 {
62 this( trimStackTrace, reportsDirectory, null );
63 }
64
65 public XMLReporter( boolean trimStackTrace, File reportsDirectory, String reportNameSuffix )
66 {
67 super( trimStackTrace );
68 this.reportsDirectory = reportsDirectory;
69 this.deleteOnStarting = false;
70 this.reportNameSuffix = reportNameSuffix;
71 }
72
73
74 public void writeMessage( String message )
75 {
76 }
77
78 public void writeMessage( byte[] b, int off, int len )
79 {
80 }
81
82
83 public void testSetStarting( ReportEntry report )
84 throws ReporterException
85 {
86 super.testSetStarting( report );
87
88 if ( deleteOnStarting )
89 {
90 final File reportFile = getReportFile( report );
91 deleteIfExisting( reportFile );
92 }
93 }
94
95 public void testSetCompleted( ReportEntry report )
96 throws ReporterException
97 {
98 super.testSetCompleted( report );
99
100 long runTime = System.currentTimeMillis() - testSetStartTime;
101
102 Xpp3Dom testSuite = createTestSuiteElement( report, runTime );
103
104 showProperties( testSuite );
105
106 testSuite.setAttribute( "tests", String.valueOf( this.getNumTests() ) );
107
108 testSuite.setAttribute( "errors", String.valueOf( this.getNumErrors() ) );
109
110 testSuite.setAttribute( "skipped", String.valueOf( this.getNumSkipped() ) );
111
112 testSuite.setAttribute( "failures", String.valueOf( this.getNumFailures() ) );
113
114 for ( Iterator i = results.iterator(); i.hasNext(); )
115 {
116 Xpp3Dom testcase = (Xpp3Dom) i.next();
117 testSuite.addChild( testcase );
118 }
119
120 File reportFile = getReportFile( report );
121
122 File reportDir = reportFile.getParentFile();
123
124
125 reportDir.mkdirs();
126
127 PrintWriter writer = null;
128
129 try
130 {
131 writer = new PrintWriter(
132 new BufferedWriter( new OutputStreamWriter( new FileOutputStream( reportFile ), "UTF-8" ) ) );
133
134 writer.write( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + LS );
135
136 Xpp3DomWriter.write( new PrettyPrintXMLWriter( writer ), testSuite );
137 }
138 catch ( UnsupportedEncodingException e )
139 {
140 throw new ReporterException( "Unable to use UTF-8 encoding", e );
141 }
142 catch ( FileNotFoundException e )
143 {
144 throw new ReporterException( "Unable to create file: " + e.getMessage(), e );
145 }
146
147 finally
148 {
149 IOUtil.close( writer );
150 }
151 }
152
153 private File getReportFile( ReportEntry report )
154 {
155 File reportFile;
156
157 if ( reportNameSuffix != null && reportNameSuffix.length() > 0)
158 {
159 reportFile = new File( reportsDirectory, "TEST-" + report.getName() + "-" + reportNameSuffix + ".xml" );
160 }
161 else
162 {
163 reportFile = new File( reportsDirectory, "TEST-" + report.getName() + ".xml" );
164 }
165
166 return reportFile;
167 }
168
169 private String getReportName( ReportEntry report )
170 {
171 String reportName;
172
173 if ( report.getName().indexOf( "(" ) > 0 )
174 {
175 reportName = report.getName().substring( 0, report.getName().indexOf( "(" ) );
176 }
177 else
178 {
179 reportName = report.getName();
180 }
181 return reportName;
182 }
183
184 public void testSucceeded( ReportEntry report )
185 {
186 super.testSucceeded( report );
187
188 long runTime = getActualRunTime( report );
189
190 Xpp3Dom testCase = createTestElement( report, runTime );
191
192 results.add( testCase );
193 }
194
195 private Xpp3Dom createTestElement( ReportEntry report, long runTime )
196 {
197 Xpp3Dom testCase = new Xpp3Dom( "testcase" );
198 testCase.setAttribute( "name", getReportName( report ) );
199 if ( report.getGroup() != null )
200 {
201 testCase.setAttribute( "group", report.getGroup() );
202 }
203 if ( report.getSourceName() != null )
204 {
205 if ( reportNameSuffix != null && reportNameSuffix.length() > 0)
206 {
207 testCase.setAttribute( "classname", report.getSourceName() + "(" + reportNameSuffix + ")" );
208 }
209 else
210 {
211 testCase.setAttribute( "classname", report.getSourceName() );
212 }
213 }
214 testCase.setAttribute( "time", elapsedTimeAsString( runTime ) );
215 return testCase;
216 }
217
218 private Xpp3Dom createTestSuiteElement( ReportEntry report, long runTime )
219 {
220 Xpp3Dom testCase = new Xpp3Dom( "testsuite" );
221
222 if ( reportNameSuffix != null && reportNameSuffix.length() > 0)
223 {
224 testCase.setAttribute( "name", getReportName( report ) + "(" + reportNameSuffix + ")" );
225 }
226 else
227 {
228 testCase.setAttribute( "name", getReportName( report ) );
229 }
230 if ( report.getGroup() != null )
231 {
232 testCase.setAttribute( "group", report.getGroup() );
233 }
234 testCase.setAttribute( "time", elapsedTimeAsString( runTime ) );
235 return testCase;
236 }
237
238 public void testError( ReportEntry report, String stdOut, String stdErr )
239 {
240 super.testError( report, stdOut, stdErr );
241
242 writeTestProblems( report, stdOut, stdErr, "error" );
243 }
244
245 public void testFailed( ReportEntry report, String stdOut, String stdErr )
246 {
247 super.testFailed( report, stdOut, stdErr );
248
249 writeTestProblems( report, stdOut, stdErr, "failure" );
250 }
251
252 public void testSkipped( ReportEntry report )
253 {
254 super.testSkipped( report );
255 writeTestProblems( report, null, null, "skipped" );
256 }
257
258 private void writeTestProblems( ReportEntry report, String stdOut, String stdErr, String name )
259 {
260 long runTime = getActualRunTime( report );
261
262 Xpp3Dom testCase = createTestElement( report, runTime );
263
264 Xpp3Dom element = createElement( testCase, name );
265
266 String stackTrace = getStackTrace( report );
267
268 Throwable t = null;
269 if ( report.getStackTraceWriter() != null )
270 {
271
272 t = report.getStackTraceWriter().getThrowable();
273 }
274
275 if ( t != null )
276 {
277
278 String message = t.getMessage();
279
280 if ( message != null )
281 {
282 element.setAttribute( "message", message );
283
284 element.setAttribute( "type", ( stackTrace.indexOf( ":" ) > -1
285 ? stackTrace.substring( 0, stackTrace.indexOf( ":" ) )
286 : stackTrace ) );
287 }
288 else
289 {
290 element.setAttribute( "type", new StringTokenizer( stackTrace ).nextToken() );
291 }
292 }
293
294 if ( stackTrace != null )
295 {
296 element.setValue( stackTrace );
297 }
298
299 addOutputStreamElement( stdOut, "system-out", testCase );
300
301 addOutputStreamElement( stdErr, "system-err", testCase );
302
303 results.add( testCase );
304 }
305
306 private void addOutputStreamElement( String stdOut, String name, Xpp3Dom testCase )
307 {
308 if ( stdOut != null && stdOut.trim().length() > 0 )
309 {
310 createElement( testCase, name ).setValue( stdOut );
311 }
312 }
313
314 private Xpp3Dom createElement( Xpp3Dom element, String name )
315 {
316 Xpp3Dom component = new Xpp3Dom( name );
317
318 element.addChild( component );
319
320 return component;
321 }
322
323
324
325
326
327
328 private void showProperties( Xpp3Dom testSuite )
329 {
330 Xpp3Dom properties = createElement( testSuite, "properties" );
331
332 Properties systemProperties = System.getProperties();
333
334 if ( systemProperties != null )
335 {
336 Enumeration propertyKeys = systemProperties.propertyNames();
337
338 while ( propertyKeys.hasMoreElements() )
339 {
340 String key = (String) propertyKeys.nextElement();
341
342 String value = systemProperties.getProperty( key );
343
344 if ( value == null )
345 {
346 value = "null";
347 }
348
349 Xpp3Dom property = createElement( properties, "property" );
350
351 property.setAttribute( "name", key );
352
353 property.setAttribute( "value", value );
354
355 }
356 }
357 }
358
359 public Iterator getResults()
360 {
361 return results.iterator();
362 }
363
364 public void reset()
365 {
366 results.clear();
367 super.reset();
368 }
369 }