Coverage Report - org.apache.maven.surefire.report.SmartStackTraceParser
 
Classes in this File Line Coverage Branch Coverage Complexity
SmartStackTraceParser
93%
109/117
86%
62/72
3,812
 
 1  
 package org.apache.maven.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.util.ArrayList;
 23  
 import java.util.Arrays;
 24  
 import java.util.Collections;
 25  
 import java.util.List;
 26  
 
 27  
 import org.apache.maven.shared.utils.StringUtils;
 28  
 
 29  
 /**
 30  
  * @author Kristian Rosenvold
 31  
  */
 32  
 @SuppressWarnings( "ThrowableResultOfMethodCallIgnored" )
 33  
 public class SmartStackTraceParser
 34  
 {
 35  
 
 36  
     private final SafeThrowable throwable;
 37  
 
 38  
     private final StackTraceElement[] stackTrace;
 39  
 
 40  
     private final String simpleName;
 41  
 
 42  
     private String testClassName;
 43  
 
 44  
     private final Class testClass;
 45  
 
 46  
     private String testMethodName;
 47  
 
 48  
     public SmartStackTraceParser( Class testClass, Throwable throwable )
 49  
     {
 50  10
         this( testClass.getName(), throwable, null );
 51  10
     }
 52  
 
 53  
     public SmartStackTraceParser( String testClassName, Throwable throwable, String testMethodName )
 54  11
     {
 55  11
         this.testMethodName = testMethodName;
 56  11
         this.testClassName = testClassName;
 57  11
         this.testClass = getClass( testClassName );
 58  11
         this.simpleName = this.testClassName.substring( this.testClassName.lastIndexOf( "." ) + 1 );
 59  11
         this.throwable = new SafeThrowable( throwable );
 60  11
         stackTrace = throwable.getStackTrace();
 61  11
     }
 62  
 
 63  
     private static Class getClass( String name )
 64  
     {
 65  
         try
 66  
         {
 67  11
             return Thread.currentThread().getContextClassLoader().loadClass( name );
 68  
         }
 69  1
         catch ( ClassNotFoundException e )
 70  
         {
 71  1
             return null;
 72  
         }
 73  
     }
 74  
 
 75  
     private static String getSimpleName( String className )
 76  
     {
 77  1
         int i = className.lastIndexOf( "." );
 78  1
         return className.substring( i + 1 );
 79  
     }
 80  
 
 81  
     @SuppressWarnings( "ThrowableResultOfMethodCallIgnored" )
 82  
     public String getString()
 83  
     {
 84  11
         if ( testClass == null )
 85  
         {
 86  1
             return throwable.getLocalizedMessage();
 87  
         }
 88  
 
 89  10
         StringBuilder result = new StringBuilder();
 90  10
         List<StackTraceElement> stackTraceElements = focusOnClass( stackTrace, testClass );
 91  10
         Collections.reverse( stackTraceElements );
 92  
         StackTraceElement stackTraceElement;
 93  10
         if ( stackTraceElements.isEmpty() )
 94  
         {
 95  1
             result.append( simpleName );
 96  1
             if (StringUtils.isNotEmpty( testMethodName ))
 97  
             {
 98  0
                 result.append( "." ).append( testMethodName );
 99  
             }
 100  
         }
 101  
         else
 102  
         {
 103  21
             for ( int i = 0; i < stackTraceElements.size(); i++ )
 104  
             {
 105  12
                 stackTraceElement = stackTraceElements.get( i );
 106  12
                 if ( i == 0 )
 107  
                 {
 108  9
                     result.append( simpleName );
 109  9
                     if ( !stackTraceElement.getClassName().equals( testClassName ) )
 110  
                     {
 111  1
                         result.append( ">" );
 112  
                     }
 113  
                     else
 114  
                     {
 115  8
                         result.append( "." );
 116  
                     }
 117  
 
 118  
                 }
 119  12
                 if ( !stackTraceElement.getClassName().equals( testClassName ) )
 120  
                 {
 121  1
                     result.append( getSimpleName( stackTraceElement.getClassName() ) ); // Add the name of the superclas
 122  1
                     result.append( "." );
 123  
                 }
 124  12
                 result.append( stackTraceElement.getMethodName() ).append( ":" ).append(
 125  
                     stackTraceElement.getLineNumber() );
 126  12
                 result.append( "->" );
 127  
             }
 128  
 
 129  9
             if ( result.length() >= 2 )
 130  
             {
 131  9
                 result.deleteCharAt( result.length() - 1 );
 132  9
                 result.deleteCharAt( result.length() - 1 );
 133  
             }
 134  
         }
 135  
 
 136  10
         Throwable target = throwable.getTarget();
 137  10
         if ( target instanceof AssertionError )
 138  
         {
 139  3
             result.append( " " );
 140  3
             result.append( throwable.getMessage() );
 141  
         }
 142  7
         else if ( "junit.framework.AssertionFailedError".equals( target.getClass().getName() )
 143  
             || "junit.framework.ComparisonFailure".equals( target.getClass().getName() ) )
 144  
         {
 145  3
             result.append( " " );
 146  3
             result.append( throwable.getMessage() );
 147  
         }
 148  
         else
 149  
         {
 150  4
             result.append( rootIsInclass() ? " " : " ยป " );
 151  4
             result.append( getMinimalThrowableMiniMessage( target ) );
 152  4
             result.append( getTruncatedMessage( 77 - result.length() ) );
 153  
         }
 154  10
         return result.toString();
 155  
     }
 156  
 
 157  
     private String getMinimalThrowableMiniMessage( Throwable throwable )
 158  
     {
 159  4
         String name = throwable.getClass().getSimpleName();
 160  4
         if ( name.endsWith( "Exception" ) )
 161  
         {
 162  4
             return StringUtils.chompLast( name, "Exception" );
 163  
         }
 164  0
         if ( name.endsWith( "Error" ) )
 165  
         {
 166  0
             return StringUtils.chompLast( name, "Error" );
 167  
         }
 168  0
         return name;
 169  
     }
 170  
 
 171  
     private String getTruncatedMessage( int i )
 172  
     {
 173  4
         if ( i < 0 )
 174  
         {
 175  0
             return "";
 176  
         }
 177  4
         String msg = throwable.getMessage();
 178  4
         if ( msg == null )
 179  
         {
 180  1
             return "";
 181  
         }
 182  3
         String substring = msg.substring( 0, Math.min( i, msg.length() ) );
 183  3
         if ( i < msg.length() )
 184  
         {
 185  1
             return " " + substring + "...";
 186  
         }
 187  
         else
 188  
         {
 189  2
             return " " + substring;
 190  
         }
 191  
     }
 192  
 
 193  
     private boolean rootIsInclass()
 194  
     {
 195  4
         return stackTrace.length > 0 && stackTrace[0].getClassName().equals( testClassName );
 196  
     }
 197  
 
 198  
     static List<StackTraceElement> focusOnClass( StackTraceElement[] stackTrace, Class clazz )
 199  
     {
 200  10
         List<StackTraceElement> result = new ArrayList<StackTraceElement>();
 201  289
         for ( StackTraceElement element : stackTrace )
 202  
         {
 203  279
             if ( element != null && isInSupers( clazz, element.getClassName() ) )
 204  
             {
 205  12
                 result.add( element );
 206  
             }
 207  
         }
 208  10
         return result;
 209  
     }
 210  
 
 211  
     private static boolean isInSupers( Class testClass, String lookFor )
 212  
     {
 213  279
         if ( lookFor.startsWith( "junit.framework." ) )
 214  
         {
 215  77
             return false;
 216  
         }
 217  540
         while ( !testClass.getName().equals( lookFor ) && testClass.getSuperclass() != null )
 218  
         {
 219  338
             testClass = testClass.getSuperclass();
 220  
         }
 221  202
         return testClass.getName().equals( lookFor );
 222  
     }
 223  
 
 224  
     static Throwable findInnermostWithClass( Throwable t, String className )
 225  
     {
 226  4
         Throwable match = t;
 227  
         do
 228  
         {
 229  9
             if ( containsClassName( t.getStackTrace(), className ) )
 230  
             {
 231  4
                 match = t;
 232  
             }
 233  
 
 234  9
             t = t.getCause();
 235  
 
 236  
         }
 237  9
         while ( t != null );
 238  4
         return match;
 239  
     }
 240  
 
 241  
     public static String innerMostWithFocusOnClass( Throwable t, String className )
 242  
     {
 243  1
         Throwable innermost = findInnermostWithClass( t, className );
 244  1
         List<StackTraceElement> stackTraceElements = focusInsideClass( innermost.getStackTrace(), className );
 245  1
         String s = causeToString( innermost.getCause() );
 246  1
         return toString( t, stackTraceElements ) + s;
 247  
     }
 248  
 
 249  
     static List<StackTraceElement> focusInsideClass( StackTraceElement[] stackTrace, String className )
 250  
     {
 251  6
         List<StackTraceElement> result = new ArrayList<StackTraceElement>();
 252  6
         boolean found = false;
 253  27
         for ( StackTraceElement element : stackTrace )
 254  
         {
 255  27
             if ( !found )
 256  
             {
 257  16
                 result.add( element );
 258  
             }
 259  
 
 260  27
             if ( className.equals( element.getClassName() ) )
 261  
             {
 262  11
                 if ( found )
 263  
                 {
 264  5
                     result.add( element );
 265  
                 }
 266  11
                 found = true;
 267  
             }
 268  
             else
 269  
             {
 270  16
                 if ( found )
 271  
                 {
 272  6
                     break;
 273  
                 }
 274  
             }
 275  
         }
 276  6
         return result;
 277  
     }
 278  
 
 279  
     static boolean containsClassName( StackTraceElement[] stackTrace, String className )
 280  
     {
 281  69
         for ( StackTraceElement element : stackTrace )
 282  
         {
 283  64
             if ( className.equals( element.getClassName() ) )
 284  
             {
 285  4
                 return true;
 286  
             }
 287  
         }
 288  5
         return false;
 289  
     }
 290  
 
 291  
     public static String causeToString( Throwable cause )
 292  
     {
 293  1
         StringBuilder resp = new StringBuilder();
 294  1
         while ( cause != null )
 295  
         {
 296  0
             resp.append( "Caused by: " );
 297  0
             resp.append( toString( cause, Arrays.asList( cause.getStackTrace() ) ) );
 298  0
             cause = cause.getCause();
 299  
         }
 300  1
         return resp.toString();
 301  
     }
 302  
 
 303  
     public static String toString( Throwable t, Iterable<StackTraceElement> elements )
 304  
     {
 305  1
         StringBuilder result = new StringBuilder();
 306  1
         result.append( t.getClass().getName() );
 307  1
         result.append( ": " );
 308  1
         result.append( t.getMessage() );
 309  1
         result.append( "\n" );
 310  
 
 311  1
         for ( StackTraceElement element : elements )
 312  
         {
 313  1
             result.append( "\tat " ).append( element.toString() );
 314  1
             result.append( "\n" );
 315  
         }
 316  1
         return result.toString();
 317  
     }
 318  
 }