1 package org.apache.maven.plugin.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.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStreamWriter;
26 import java.util.Enumeration;
27 import java.util.Properties;
28 import java.util.StringTokenizer;
29 import org.apache.maven.shared.utils.io.IOUtil;
30 import org.apache.maven.shared.utils.xml.XMLWriter;
31 import org.apache.maven.surefire.report.ReportEntry;
32 import org.apache.maven.surefire.report.ReporterException;
33 import org.apache.maven.surefire.report.SafeThrowable;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class StatelessXmlReporter
68 {
69
70 private final File reportsDirectory;
71
72 private final String reportNameSuffix;
73
74 private final boolean trimStackTrace;
75
76 private final String encoding = "UTF-8";
77
78 public StatelessXmlReporter( File reportsDirectory, String reportNameSuffix, boolean trimStackTrace )
79 {
80 this.reportsDirectory = reportsDirectory;
81 this.reportNameSuffix = reportNameSuffix;
82 this.trimStackTrace = trimStackTrace;
83 }
84
85 public void testSetCompleted( WrappedReportEntry testSetReportEntry, TestSetStats testSetStats )
86 throws ReporterException
87 {
88
89 OutputStreamWriter fw = getWriter( testSetReportEntry );
90 try
91 {
92
93 org.apache.maven.shared.utils.xml.XMLWriter ppw =
94 new org.apache.maven.shared.utils.xml.PrettyPrintXMLWriter( fw );
95 ppw.setEncoding( encoding );
96
97 createTestSuiteElement( ppw, testSetReportEntry, testSetStats, reportNameSuffix );
98
99 showProperties( ppw );
100
101 for ( WrappedReportEntry entry : testSetStats.getReportEntries() )
102 {
103 if ( ReportEntryType.success.equals( entry.getReportEntryType() ) )
104 {
105 startTestElement( ppw, entry, reportNameSuffix );
106 ppw.endElement();
107 }
108 else
109 {
110 getTestProblems( ppw, entry, trimStackTrace, reportNameSuffix );
111 }
112
113 }
114 ppw.endElement();
115
116 }
117 finally
118 {
119 IOUtil.close( fw );
120 }
121 }
122
123 private OutputStreamWriter getWriter( WrappedReportEntry testSetReportEntry )
124 {
125 File reportFile = getReportFile( testSetReportEntry, reportsDirectory, reportNameSuffix );
126
127 File reportDir = reportFile.getParentFile();
128
129
130 reportDir.mkdirs();
131
132 try
133 {
134
135 FileOutputStream fos = new FileOutputStream( reportFile );
136
137 return new OutputStreamWriter( fos, encoding );
138 }
139 catch ( IOException e )
140 {
141 throw new ReporterException( "When writing report", e );
142 }
143 }
144
145 private File getReportFile( ReportEntry report, File reportsDirectory, String reportNameSuffix )
146 {
147 File reportFile;
148
149 if ( reportNameSuffix != null && reportNameSuffix.length() > 0 )
150 {
151 reportFile = new File( reportsDirectory, "TEST-" + report.getName() + "-" + reportNameSuffix + ".xml" );
152 }
153 else
154 {
155 reportFile = new File( reportsDirectory, "TEST-" + report.getName() + ".xml" );
156 }
157
158 return reportFile;
159 }
160
161 private static void startTestElement( XMLWriter ppw, WrappedReportEntry report, String reportNameSuffix )
162 {
163 ppw.startElement( "testcase" );
164 ppw.addAttribute( "name", report.getReportName() );
165 if ( report.getGroup() != null )
166 {
167 ppw.addAttribute( "group", report.getGroup() );
168 }
169 if ( report.getSourceName() != null )
170 {
171 if ( reportNameSuffix != null && reportNameSuffix.length() > 0 )
172 {
173 ppw.addAttribute( "classname", report.getSourceName() + "(" + reportNameSuffix + ")" );
174 }
175 else
176 {
177 ppw.addAttribute( "classname", report.getSourceName() );
178 }
179 }
180 ppw.addAttribute( "time", report.elapsedTimeAsString() );
181 }
182
183 private static void createTestSuiteElement( XMLWriter ppw, WrappedReportEntry report, TestSetStats testSetStats,
184 String reportNameSuffix1 )
185 {
186 ppw.startElement( "testsuite" );
187
188 ppw.addAttribute( "name", report.getReportName( reportNameSuffix1 ) );
189
190 if ( report.getGroup() != null )
191 {
192 ppw.addAttribute( "group", report.getGroup() );
193 }
194
195 ppw.addAttribute( "time", testSetStats.getElapsedForTestSet() );
196
197 ppw.addAttribute( "tests", String.valueOf( testSetStats.getCompletedCount() ) );
198
199 ppw.addAttribute( "errors", String.valueOf( testSetStats.getErrors() ) );
200
201 ppw.addAttribute( "skipped", String.valueOf( testSetStats.getSkipped() ) );
202
203 ppw.addAttribute( "failures", String.valueOf( testSetStats.getFailures() ) );
204
205 }
206
207
208 private void getTestProblems( XMLWriter ppw, WrappedReportEntry report, boolean trimStackTrace,
209 String reportNameSuffix )
210 {
211
212 startTestElement( ppw, report, reportNameSuffix );
213
214 ppw.startElement( report.getReportEntryType().name() );
215
216 String stackTrace = report.getStackTrace( trimStackTrace );
217
218 if ( report.getMessage() != null && report.getMessage().length() > 0 )
219 {
220 ppw.addAttribute( "message", extraEscape( report.getMessage(), true ) );
221 }
222
223 if ( report.getStackTraceWriter() != null )
224 {
225
226 SafeThrowable t = report.getStackTraceWriter().getThrowable();
227 if ( t != null )
228 {
229 if ( t.getMessage() != null )
230 {
231 ppw.addAttribute( "type", ( stackTrace.contains( ":" )
232 ? stackTrace.substring( 0, stackTrace.indexOf( ":" ) )
233 : stackTrace ) );
234 }
235 else
236 {
237 ppw.addAttribute( "type", new StringTokenizer( stackTrace ).nextToken() );
238 }
239 }
240 }
241
242 if ( stackTrace != null )
243 {
244 ppw.writeText( extraEscape( stackTrace, false ) );
245 }
246
247 ppw.endElement();
248
249 addOutputStreamElement( ppw, report.getStdout(), "system-out" );
250
251 addOutputStreamElement( ppw, report.getStdErr(), "system-err" );
252
253 ppw.endElement();
254 }
255
256 private void addOutputStreamElement( XMLWriter xmlWriter, String stdOut, String name )
257 {
258 if ( stdOut != null && stdOut.trim().length() > 0 )
259 {
260 xmlWriter.startElement( name );
261 xmlWriter.writeText( extraEscape( stdOut, false ) );
262 xmlWriter.endElement();
263 }
264 }
265
266
267
268
269
270
271
272 private void showProperties( XMLWriter xmlWriter )
273 {
274 xmlWriter.startElement( "properties" );
275
276 Properties systemProperties = System.getProperties();
277
278 if ( systemProperties != null )
279 {
280 Enumeration<?> propertyKeys = systemProperties.propertyNames();
281
282 while ( propertyKeys.hasMoreElements() )
283 {
284 String key = (String) propertyKeys.nextElement();
285
286 String value = systemProperties.getProperty( key );
287
288 if ( value == null )
289 {
290 value = "null";
291 }
292
293 xmlWriter.startElement( "property" );
294
295 xmlWriter.addAttribute( "name", key );
296
297 xmlWriter.addAttribute( "value", extraEscape( value, true ));
298
299 xmlWriter.endElement();
300
301 }
302 }
303 xmlWriter.endElement();
304 }
305
306
307
308
309
310
311
312
313 private static String extraEscape( String message, boolean attribute )
314 {
315
316 if ( !containsEscapesIllegalnXml10( message ) )
317 {
318 return message;
319 }
320 return escapeXml( message, attribute );
321 }
322
323 private static boolean containsEscapesIllegalnXml10( String message )
324 {
325 int size = message.length();
326 for ( int i = 0; i < size; i++ )
327 {
328 if ( isIllegalEscape( message.charAt( i ) ) )
329 {
330 return true;
331 }
332
333 }
334 return false;
335 }
336
337 private static boolean isIllegalEscape( char c )
338 {
339 return c < 32 && c != '\n' && c != '\r' && c != '\t';
340 }
341
342 private static String escapeXml( String text, boolean attribute )
343 {
344 StringBuilder sb = new StringBuilder( text.length() * 2 );
345 for ( int i = 0; i < text.length(); i++ )
346 {
347 char c = text.charAt( i );
348 if ( isIllegalEscape( c ) )
349 {
350
351
352
353
354
355 sb.append( attribute ? "&#" : "&#" ).append( (int) c ).append(
356 ';' );
357 }
358 else
359 {
360 sb.append( c );
361 }
362 }
363 return sb.toString();
364 }
365
366 }