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 803879 2009-08-13 13:43:01Z vsiveton $
43   */
44  public class TestSuiteXmlParser
45      extends DefaultHandler
46  {
47      private ReportTestSuite defaultSuite;
48      private ReportTestSuite currentSuite;
49      private Map classesToSuites;
50      private 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                     currentSuite.setTimeElapsed( time.floatValue() + currentSuite.getTimeElapsed() );
157                 }
158             }
159             else if ( "failure".equals( qName ) )
160             {
161                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
162                 currentSuite.setNumberOfFailures( 1 + currentSuite.getNumberOfFailures() );
163             }
164             else if ( "error".equals( qName ) )
165             {
166                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
167                 currentSuite.setNumberOfErrors( 1 + currentSuite.getNumberOfErrors() );
168             }
169             else if ( "skipped".equals( qName ) )
170             {
171                 testCase.addFailure( "skipped", "skipped" ); // TODO extract real reasons
172                 currentSuite.setNumberOfSkipped( 1 + currentSuite.getNumberOfSkipped() );
173             }
174         }
175         catch ( ParseException e )
176         {
177             throw new SAXException( e.getMessage(), e );
178         }
179     }
180 
181     /** {@inheritDoc} */
182     public void endElement( String uri, String localName, String qName )
183         throws SAXException
184     {
185         if ( "testcase".equals( qName ) )
186         {
187             currentSuite.getTestCases().add( testCase );
188         }
189         else if ( "failure".equals( qName ) )
190         {
191             Map failure = testCase.getFailure();
192 
193             failure.put( "detail", parseCause( currentElement.toString() ) );
194         }
195         else if ( "error".equals( qName ) )
196         {
197             Map error = testCase.getFailure();
198 
199             error.put( "detail", parseCause( currentElement.toString() ) );
200         }
201         else if ( "time".equals( qName ) )
202         {
203             try {
204                 Number time = numberFormat.parse( currentElement.toString() );
205                 defaultSuite.setTimeElapsed( time.floatValue() );
206             }
207             catch ( ParseException e )
208             {
209                 throw new SAXException( e.getMessage(), e );
210             }
211         }
212         // TODO extract real skipped reasons
213     }
214 
215     /** {@inheritDoc} */
216     public void characters( char[] ch, int start, int length )
217         throws SAXException
218     {
219         String s = new String( ch, start, length );
220 
221         if ( !"".equals( s.trim() ) )
222         {
223             currentElement.append( s );
224         }
225     }
226 
227     private List parseCause( String detail )
228     {
229         String fullName = testCase.getFullName();
230         String name = fullName.substring( fullName.lastIndexOf( "." ) + 1 );
231         return parseCause( detail, name );
232     }
233 
234     private List parseCause( String detail, String compareTo )
235     {
236         StringTokenizer stringTokenizer = new StringTokenizer( detail, "\n" );
237         List parsedDetail = new ArrayList( stringTokenizer.countTokens() );
238 
239         while ( stringTokenizer.hasMoreTokens() )
240         {
241             String lineString = stringTokenizer.nextToken().trim();
242             parsedDetail.add( lineString );
243             if ( lineString.indexOf( compareTo ) >= 0 )
244             {
245                 break;
246             }
247         }
248 
249         return parsedDetail;
250     }
251 
252 }