View Javadoc

1   package org.apache.maven.plugins.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.File;
23  import java.io.IOException;
24  import java.text.NumberFormat;
25  import java.text.ParseException;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.StringTokenizer;
32  
33  import javax.xml.parsers.ParserConfigurationException;
34  import javax.xml.parsers.SAXParser;
35  import javax.xml.parsers.SAXParserFactory;
36  
37  import org.xml.sax.Attributes;
38  import org.xml.sax.SAXException;
39  import org.xml.sax.helpers.DefaultHandler;
40  
41  /**
42   * @version $Id: TestSuiteXmlParser.java 1063892 2011-01-26 22:04:57Z krosenvold $
43   */
44  public class TestSuiteXmlParser
45      extends DefaultHandler
46  {
47      private ReportTestSuite defaultSuite;
48      private ReportTestSuite currentSuite;
49      private Map classesToSuites;
50      private final NumberFormat numberFormat = NumberFormat.getInstance();
51  
52      /**
53       * @noinspection StringBufferField
54       */
55      private StringBuffer currentElement;
56  
57      private ReportTestCase testCase;
58  
59      public Collection parse( String xmlPath )
60          throws ParserConfigurationException, SAXException, IOException
61      {
62          SAXParserFactory factory = SAXParserFactory.newInstance();
63  
64          SAXParser saxParser = factory.newSAXParser();
65  
66          classesToSuites = new HashMap();
67  
68          saxParser.parse( new File( xmlPath ), this );
69  
70          if ( currentSuite != defaultSuite )
71          { // omit the defaultSuite if it's empty and there are alternatives
72              if ( defaultSuite.getNumberOfTests() == 0 )
73              {
74                  classesToSuites.remove( defaultSuite.getFullClassName() );
75              }
76          }
77  
78          return classesToSuites.values();
79      }
80  
81      /** {@inheritDoc} */
82      public void startElement( String uri, String localName, String qName, Attributes attributes )
83          throws SAXException
84      {
85          try
86          {
87              if ( "testsuite".equals( qName ) )
88              {
89                  currentSuite = defaultSuite = new ReportTestSuite();
90  
91                  try
92                  {
93                      Number time = numberFormat.parse( attributes.getValue( "time" ) );
94  
95                      defaultSuite.setTimeElapsed( time.floatValue() );
96                  }
97                  catch ( NullPointerException npe )
98                  {
99                      System.err.println( "WARNING: no time attribute found on testsuite element" );
100                 }
101 
102                 //check if group attribute is existing
103                 if ( attributes.getValue( "group" ) != null && !"".equals( attributes.getValue( "group" ) ) )
104                 {
105                     String packageName = attributes.getValue( "group" );
106                     String name = attributes.getValue( "name" );
107 
108                     defaultSuite.setFullClassName( packageName + "." + name );
109                 }
110                 else
111                 {
112                     String fullClassName = attributes.getValue( "name" );
113                     defaultSuite.setFullClassName( fullClassName );
114                 }
115 
116                 classesToSuites.put( defaultSuite.getFullClassName(), defaultSuite );
117             }
118             else if ( "testcase".equals( qName ) )
119             {
120                 currentElement = new StringBuffer();
121 
122                 testCase = new ReportTestCase();
123 
124                 testCase.setName( attributes.getValue( "name" ) );
125 
126                 String fullClassName = attributes.getValue( "classname" );
127 
128                 // if the testcase declares its own classname, it may need to belong to its own suite
129                 if ( fullClassName != null )
130                 {
131                     currentSuite = (ReportTestSuite) classesToSuites.get( fullClassName );
132                     if ( currentSuite == null )
133                     {
134                         currentSuite = new ReportTestSuite();
135                         currentSuite.setFullClassName( fullClassName );
136                         classesToSuites.put( fullClassName, currentSuite );
137                     }
138                 }
139 
140                 testCase.setFullClassName( currentSuite.getFullClassName() );
141                 testCase.setClassName( currentSuite.getName() );
142                 testCase.setFullName( currentSuite.getFullClassName() + "." + testCase.getName() );
143 
144                 String timeAsString = attributes.getValue( "time" );
145 
146                 Number time = new Integer( 0 );
147 
148                 if ( timeAsString != null )
149                 {
150                     time = numberFormat.parse( timeAsString );
151                 }
152 
153                 testCase.setTime( time.floatValue() );
154 
155                 if ( currentSuite != defaultSuite )
156                 {
157                     currentSuite.setTimeElapsed( time.floatValue() + currentSuite.getTimeElapsed() );
158                 }
159             }
160             else if ( "failure".equals( qName ) )
161             {
162                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
163                 currentSuite.setNumberOfFailures( 1 + currentSuite.getNumberOfFailures() );
164             }
165             else if ( "error".equals( qName ) )
166             {
167                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
168                 currentSuite.setNumberOfErrors( 1 + currentSuite.getNumberOfErrors() );
169             }
170             else if ( "skipped".equals( qName ) )
171             {
172                 testCase.addFailure( "skipped", "skipped" ); // TODO extract real reasons
173                 currentSuite.setNumberOfSkipped( 1 + currentSuite.getNumberOfSkipped() );
174             }
175         }
176         catch ( ParseException e )
177         {
178             throw new SAXException( e.getMessage(), e );
179         }
180     }
181 
182     /** {@inheritDoc} */
183     public void endElement( String uri, String localName, String qName )
184         throws SAXException
185     {
186         if ( "testcase".equals( qName ) )
187         {
188             currentSuite.getTestCases().add( testCase );
189         }
190         else if ( "failure".equals( qName ) )
191         {
192             Map failure = testCase.getFailure();
193 
194             failure.put( "detail", parseCause( currentElement.toString() ) );
195         }
196         else if ( "error".equals( qName ) )
197         {
198             Map error = testCase.getFailure();
199 
200             error.put( "detail", parseCause( currentElement.toString() ) );
201         }
202         else if ( "time".equals( qName ) )
203         {
204             try
205             {
206                 Number time = numberFormat.parse( currentElement.toString() );
207                 defaultSuite.setTimeElapsed( time.floatValue() );
208             }
209             catch ( ParseException e )
210             {
211                 throw new SAXException( e.getMessage(), e );
212             }
213         }
214         // TODO extract real skipped reasons
215     }
216 
217     /** {@inheritDoc} */
218     public void characters( char[] ch, int start, int length )
219         throws SAXException
220     {
221         String s = new String( ch, start, length );
222 
223         if ( !"".equals( s.trim() ) )
224         {
225             currentElement.append( s );
226         }
227     }
228 
229     private List parseCause( String detail )
230     {
231         String fullName = testCase.getFullName();
232         String name = fullName.substring( fullName.lastIndexOf( "." ) + 1 );
233         return parseCause( detail, name );
234     }
235 
236     private List parseCause( String detail, String compareTo )
237     {
238         StringTokenizer stringTokenizer = new StringTokenizer( detail, "\n" );
239         List parsedDetail = new ArrayList( stringTokenizer.countTokens() );
240 
241         while ( stringTokenizer.hasMoreTokens() )
242         {
243             String lineString = stringTokenizer.nextToken().trim();
244             parsedDetail.add( lineString );
245             if ( lineString.indexOf( compareTo ) >= 0 )
246             {
247                 break;
248             }
249         }
250 
251         return parsedDetail;
252     }
253 
254 }