View Javadoc

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