View Javadoc

1   package org.apache.maven.surefire.report;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * XML format reporter.
42   *
43   * @author <a href="mailto:jruiz@exist.com">Johnny R. Ruiz III</a>
44   * @version $Id: XMLReporter.java 1143207 2011-07-05 21:37:57Z pgier $
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         //noinspection ResultOfMethodCallIgnored
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             //noinspection ThrowableResultOfMethodCallIgnored
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      * Adds system properties to the XML report.
325      *
326      * @param testSuite The test suite to report to
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 }