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