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