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