Coverage Report - org.apache.maven.plugins.surefire.report.TestSuiteXmlParser
 
Classes in this File Line Coverage Branch Coverage Complexity
TestSuiteXmlParser
88%
97/109
83%
40/48
5
 
 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.FileInputStream;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.InputStreamReader;
 27  
 import java.text.NumberFormat;
 28  
 import java.text.ParseException;
 29  
 import java.util.ArrayList;
 30  
 import java.util.Collection;
 31  
 import java.util.HashMap;
 32  
 import java.util.List;
 33  
 import java.util.Locale;
 34  
 import java.util.Map;
 35  
 import java.util.StringTokenizer;
 36  
 
 37  
 import javax.xml.parsers.ParserConfigurationException;
 38  
 import javax.xml.parsers.SAXParser;
 39  
 import javax.xml.parsers.SAXParserFactory;
 40  
 
 41  
 import org.xml.sax.Attributes;
 42  
 import org.xml.sax.InputSource;
 43  
 import org.xml.sax.SAXException;
 44  
 import org.xml.sax.helpers.DefaultHandler;
 45  
 
 46  
 /**
 47  
  *
 48  
  */
 49  4
 public class TestSuiteXmlParser
 50  
     extends DefaultHandler
 51  
 {
 52  
     private ReportTestSuite defaultSuite;
 53  
 
 54  
     private ReportTestSuite currentSuite;
 55  
 
 56  
     private Map<String, ReportTestSuite> classesToSuites;
 57  
 
 58  4
     private final NumberFormat numberFormat = NumberFormat.getInstance( Locale.ENGLISH );
 59  
 
 60  
     /**
 61  
      * @noinspection StringBufferField
 62  
      */
 63  
     private StringBuffer currentElement;
 64  
 
 65  
     private ReportTestCase testCase;
 66  
 
 67  
     private boolean valid;
 68  
 
 69  
     public Collection<ReportTestSuite> parse( String xmlPath )
 70  
         throws ParserConfigurationException, SAXException, IOException
 71  
     {
 72  
 
 73  10
         File f = new File( xmlPath );
 74  
 
 75  10
         FileInputStream fileInputStream = new FileInputStream( f );
 76  
 
 77  10
         InputStreamReader  inputStreamReader = new InputStreamReader( fileInputStream, "UTF-8" );
 78  
 
 79  
         try
 80  
         {
 81  10
             return parse( inputStreamReader );
 82  
         }
 83  
         finally
 84  
         {
 85  10
             inputStreamReader.close();
 86  10
             fileInputStream.close();
 87  
         }
 88  
     }
 89  
 
 90  
     public Collection<ReportTestSuite> parse( InputStreamReader stream )
 91  
         throws ParserConfigurationException, SAXException, IOException
 92  
     {
 93  11
         SAXParserFactory factory = SAXParserFactory.newInstance();
 94  
 
 95  11
         SAXParser saxParser = factory.newSAXParser();
 96  
 
 97  11
         valid = true;
 98  
 
 99  11
         classesToSuites = new HashMap<String, ReportTestSuite>();
 100  
 
 101  11
         saxParser.parse( new InputSource( stream ), this );
 102  
 
 103  11
         if ( currentSuite != defaultSuite )
 104  
         { // omit the defaultSuite if it's empty and there are alternatives
 105  1
             if ( defaultSuite.getNumberOfTests() == 0 )
 106  
             {
 107  1
                 classesToSuites.remove( defaultSuite.getFullClassName() );
 108  
             }
 109  
         }
 110  
 
 111  11
         return classesToSuites.values();
 112  
     }
 113  
 
 114  
     /**
 115  
      * {@inheritDoc}
 116  
      */
 117  
     public void startElement( String uri, String localName, String qName, Attributes attributes )
 118  
         throws SAXException
 119  
     {
 120  540
         if ( !valid )
 121  
         {
 122  5
             return;
 123  
         }
 124  
         try
 125  
         {
 126  535
             if ( "testsuite".equals( qName ) )
 127  
             {
 128  10
                 currentSuite = defaultSuite = new ReportTestSuite();
 129  
 
 130  
                 try
 131  
                 {
 132  10
                     Number time = numberFormat.parse( attributes.getValue( "time" ) );
 133  
 
 134  9
                     defaultSuite.setTimeElapsed( time.floatValue() );
 135  
                 }
 136  1
                 catch ( NullPointerException npe )
 137  
                 {
 138  1
                     System.err.println( "WARNING: no time attribute found on testsuite element" );
 139  9
                 }
 140  
 
 141  
                 //check if group attribute is existing
 142  10
                 if ( attributes.getValue( "group" ) != null && !"".equals( attributes.getValue( "group" ) ) )
 143  
                 {
 144  0
                     String packageName = attributes.getValue( "group" );
 145  0
                     String name = attributes.getValue( "name" );
 146  
 
 147  0
                     defaultSuite.setFullClassName( packageName + "." + name );
 148  0
                 }
 149  
                 else
 150  
                 {
 151  10
                     String fullClassName = attributes.getValue( "name" );
 152  10
                     defaultSuite.setFullClassName( fullClassName );
 153  
                 }
 154  
 
 155  10
                 classesToSuites.put( defaultSuite.getFullClassName(), defaultSuite );
 156  
             }
 157  525
             else if ( "testcase".equals( qName ) )
 158  
             {
 159  33
                 currentElement = new StringBuffer();
 160  
 
 161  33
                 testCase = new ReportTestCase();
 162  
 
 163  33
                 testCase.setName( attributes.getValue( "name" ) );
 164  
 
 165  33
                 String fullClassName = attributes.getValue( "classname" );
 166  
 
 167  
                 // if the testcase declares its own classname, it may need to belong to its own suite
 168  33
                 if ( fullClassName != null )
 169  
                 {
 170  10
                     currentSuite = classesToSuites.get( fullClassName );
 171  10
                     if ( currentSuite == null )
 172  
                     {
 173  2
                         currentSuite = new ReportTestSuite();
 174  2
                         currentSuite.setFullClassName( fullClassName );
 175  2
                         classesToSuites.put( fullClassName, currentSuite );
 176  
                     }
 177  
                 }
 178  
 
 179  33
                 testCase.setFullClassName( currentSuite.getFullClassName() );
 180  33
                 testCase.setClassName( currentSuite.getName() );
 181  33
                 testCase.setFullName( currentSuite.getFullClassName() + "." + testCase.getName() );
 182  
 
 183  33
                 String timeAsString = attributes.getValue( "time" );
 184  
 
 185  33
                 Number time = 0;
 186  
 
 187  33
                 if ( timeAsString != null )
 188  
                 {
 189  30
                     time = numberFormat.parse( timeAsString );
 190  
                 }
 191  
 
 192  33
                 testCase.setTime( time.floatValue() );
 193  
 
 194  33
                 if ( currentSuite != defaultSuite )
 195  
                 {
 196  2
                     currentSuite.setTimeElapsed( time.floatValue() + currentSuite.getTimeElapsed() );
 197  
                 }
 198  33
             }
 199  492
             else if ( "failure".equals( qName ) )
 200  
             {
 201  13
                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
 202  13
                 currentSuite.setNumberOfFailures( 1 + currentSuite.getNumberOfFailures() );
 203  
             }
 204  479
             else if ( "error".equals( qName ) )
 205  
             {
 206  1
                 testCase.addFailure( attributes.getValue( "message" ), attributes.getValue( "type" ) );
 207  1
                 currentSuite.setNumberOfErrors( 1 + currentSuite.getNumberOfErrors() );
 208  
             }
 209  478
             else if ( "skipped".equals( qName ) )
 210  
             {
 211  0
                 final String message = attributes.getValue( "message" );
 212  0
                 testCase.addFailure( message != null ? message : "skipped", "skipped" );
 213  0
                 currentSuite.setNumberOfSkipped( 1 + currentSuite.getNumberOfSkipped() );
 214  0
             }
 215  478
             else if ( "failsafe-summary".equals( qName ) )
 216  
             {
 217  1
                 valid = false;
 218  
             }
 219  
         }
 220  0
         catch ( ParseException e )
 221  
         {
 222  0
             throw new SAXException( e.getMessage(), e );
 223  535
         }
 224  535
     }
 225  
 
 226  
     /**
 227  
      * {@inheritDoc}
 228  
      */
 229  
     public void endElement( String uri, String localName, String qName )
 230  
         throws SAXException
 231  
     {
 232  540
         if ( "testcase".equals( qName ) )
 233  
         {
 234  33
             currentSuite.getTestCases().add( testCase );
 235  
         }
 236  507
         else if ( "failure".equals( qName ) )
 237  
         {
 238  13
             Map<String, Object> failure = testCase.getFailure();
 239  
 
 240  13
             failure.put( "detail", parseCause( currentElement.toString() ) );
 241  13
         }
 242  494
         else if ( "error".equals( qName ) )
 243  
         {
 244  1
             Map<String, Object> error = testCase.getFailure();
 245  
 
 246  1
             error.put( "detail", parseCause( currentElement.toString() ) );
 247  1
         }
 248  493
         else if ( "time".equals( qName ) )
 249  
         {
 250  
             try
 251  
             {
 252  2
                 Number time = numberFormat.parse( currentElement.toString() );
 253  2
                 defaultSuite.setTimeElapsed( time.floatValue() );
 254  
             }
 255  0
             catch ( ParseException e )
 256  
             {
 257  0
                 throw new SAXException( e.getMessage(), e );
 258  2
             }
 259  
         }
 260  
         // TODO extract real skipped reasons
 261  540
     }
 262  
 
 263  
     /**
 264  
      * {@inheritDoc}
 265  
      */
 266  
     public void characters( char[] ch, int start, int length )
 267  
         throws SAXException
 268  
     {
 269  872
         if ( !valid )
 270  
         {
 271  10
             return;
 272  
         }
 273  862
         String s = new String( ch, start, length );
 274  
 
 275  862
         if ( !"".equals( s.trim() ) )
 276  
         {
 277  294
             currentElement.append( s );
 278  
         }
 279  862
     }
 280  
 
 281  
     private List<String> parseCause( String detail )
 282  
     {
 283  14
         String fullName = testCase.getFullName();
 284  14
         String name = fullName.substring( fullName.lastIndexOf( "." ) + 1 );
 285  14
         return parseCause( detail, name );
 286  
     }
 287  
 
 288  
     private List<String> parseCause( String detail, String compareTo )
 289  
     {
 290  14
         StringTokenizer stringTokenizer = new StringTokenizer( detail, "\n" );
 291  14
         List<String> parsedDetail = new ArrayList<String>( stringTokenizer.countTokens() );
 292  
 
 293  61
         while ( stringTokenizer.hasMoreTokens() )
 294  
         {
 295  61
             String lineString = stringTokenizer.nextToken().trim();
 296  61
             parsedDetail.add( lineString );
 297  61
             if ( lineString.contains( compareTo ) )
 298  
             {
 299  14
                 break;
 300  
             }
 301  47
         }
 302  
 
 303  14
         return parsedDetail;
 304  
     }
 305  
 
 306  
     public boolean isValid()
 307  
     {
 308  2
         return valid;
 309  
     }
 310  
 }