View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.report;
20  
21  import java.lang.reflect.Field;
22  import java.util.List;
23  import java.util.concurrent.ExecutionException;
24  import java.util.concurrent.FutureTask;
25  
26  import junit.framework.AssertionFailedError;
27  import junit.framework.ComparisonFailure;
28  import junit.framework.TestCase;
29  import org.apache.maven.surefire.api.util.internal.DaemonThreadFactory;
30  
31  import static org.apache.maven.surefire.report.SmartStackTraceParser.findTopmostWithClass;
32  import static org.apache.maven.surefire.report.SmartStackTraceParser.focusInsideClass;
33  import static org.apache.maven.surefire.report.SmartStackTraceParser.stackTraceWithFocusOnClassAsString;
34  
35  /**
36   *
37   */
38  @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
39  public class SmartStackTraceParserTest extends TestCase {
40      public void testGetString() {
41          ATestClass aTestClass = new ATestClass();
42          try {
43              aTestClass.failInAssert();
44          } catch (AssertionError e) {
45              SmartStackTraceParser smartStackTraceParser =
46                      new SmartStackTraceParser(ATestClass.class.getName(), e, null);
47              String res = smartStackTraceParser.getString();
48              assertEquals("ATestClass.failInAssert:30 X is not Z", res);
49          }
50      }
51  
52      public void testGetStringFromNested() {
53          OutermostClass aTestClass = new OutermostClass();
54          try {
55              aTestClass.junit();
56          } catch (AssertionError e) {
57              SmartStackTraceParser smartStackTraceParser =
58                      new SmartStackTraceParser(ATestClass.class.getName(), e, null);
59              String res = smartStackTraceParser.getString();
60              assertEquals("ATestClass.failInAssert:30 X is not Z", res);
61          }
62      }
63  
64      public void testGetStringWithMethod() {
65          OutermostClass aTestClass = new OutermostClass();
66          try {
67              aTestClass.junit();
68          } catch (AssertionError e) {
69              SmartStackTraceParser smartStackTraceParser =
70                      new SmartStackTraceParser(InnerATestClass.class.getName(), e, "myMethod");
71              String res = smartStackTraceParser.getString();
72              assertEquals("InnerATestClass.myMethod X is not Z", res);
73          }
74      }
75  
76      public void testNestedFailure() {
77          ATestClass aTestClass = new ATestClass();
78          try {
79              aTestClass.nestedFailInAssert();
80          } catch (AssertionError e) {
81              SmartStackTraceParser smartStackTraceParser =
82                      new SmartStackTraceParser(ATestClass.class.getName(), e, null);
83              String res = smartStackTraceParser.getString();
84              assertEquals("ATestClass.nestedFailInAssert:34->failInAssert:30 X is not Z", res);
85          }
86      }
87  
88      public void testNestedNpe() {
89          ATestClass aTestClass = new ATestClass();
90          try {
91              aTestClass.nestedNpe();
92          } catch (NullPointerException e) {
93              SmartStackTraceParser smartStackTraceParser =
94                      new SmartStackTraceParser(ATestClass.class.getName(), e, null);
95              String res = smartStackTraceParser.getString();
96              assertEquals("ATestClass.nestedNpe:42->npe:38 NullPointer It was null", res);
97          }
98      }
99  
100     public void testNestedNpeOutsideTest() {
101         ATestClass aTestClass = new ATestClass();
102         try {
103             aTestClass.nestedNpeOutsideTest();
104         } catch (NullPointerException e) {
105             SmartStackTraceParser smartStackTraceParser =
106                     new SmartStackTraceParser(ATestClass.class.getName(), e, null);
107             String res = smartStackTraceParser.getString();
108             assertEquals("ATestClass.nestedNpeOutsideTest:50->npeOutsideTest:46 » NullPointer", res);
109         }
110     }
111 
112     public void testLongMessageHandling() {
113         ATestClass aTestClass = new ATestClass();
114         try {
115             aTestClass.aLongTestErrorMessage();
116         } catch (RuntimeException e) {
117             SmartStackTraceParser smartStackTraceParser =
118                     new SmartStackTraceParser(ATestClass.class.getName(), e, null);
119             String res = smartStackTraceParser.getString();
120             assertEquals("ATestClass.aLongTestErrorMessage:54 Runtime " + e.getMessage(), res);
121         }
122     }
123 
124     public void testFailureInBaseClass() {
125         ASubClass aTestClass = new ASubClass();
126         try {
127             aTestClass.npe();
128         } catch (NullPointerException e) {
129             SmartStackTraceParser smartStackTraceParser = new SmartStackTraceParser(ASubClass.class.getName(), e, null);
130             String res = smartStackTraceParser.getString();
131             assertEquals("ASubClass>ABaseClass.npe:26 » NullPointer It was null", res);
132         }
133     }
134 
135     public void testClassThatWillFail() {
136         CaseThatWillFail aTestClass = new CaseThatWillFail();
137         try {
138             aTestClass.testThatWillFail();
139         } catch (ComparisonFailure e) {
140             SmartStackTraceParser smartStackTraceParser =
141                     new SmartStackTraceParser(CaseThatWillFail.class.getName(), e, null);
142             String res = smartStackTraceParser.getString();
143             assertEquals("CaseThatWillFail.testThatWillFail:25 expected:<[abc]> but was:<[def]>", res);
144         }
145     }
146 
147     private static Throwable getAThrownException() {
148         try {
149             TestClass1.InnerBTestClass.throwSomething();
150         } catch (Throwable t) {
151             return t;
152         }
153         return null;
154     }
155 
156     public void testCollections() {
157         Throwable aThrownException = getAThrownException();
158         List<StackTraceElement> innerMost = focusInsideClass(
159                 aThrownException.getCause().getStackTrace(),
160                 new ClassNameStackTraceFilter(TestClass1.InnerBTestClass.class.getName()));
161         assertEquals(2, innerMost.size());
162         StackTraceElement inner = innerMost.get(0);
163         assertEquals(TestClass1.InnerBTestClass.class.getName(), inner.getClassName());
164         StackTraceElement outer = innerMost.get(1);
165         assertEquals(TestClass1.InnerBTestClass.class.getName(), outer.getClassName());
166     }
167 
168     public void testAssertionWithNoMessage() {
169         try {
170             new AssertionNoMessage().testThrowSomething();
171         } catch (ComparisonFailure e) {
172             SmartStackTraceParser smartStackTraceParser =
173                     new SmartStackTraceParser(AssertionNoMessage.class.getName(), e, null);
174             String res = smartStackTraceParser.getString();
175             assertEquals("AssertionNoMessage.testThrowSomething:25 expected:<[abc]> but was:<[xyz]>", res);
176         }
177     }
178 
179     public void testFailWithFail() {
180         try {
181             new FailWithFail().testThatWillFail();
182         } catch (AssertionFailedError e) {
183             SmartStackTraceParser smartStackTraceParser =
184                     new SmartStackTraceParser(FailWithFail.class.getName(), e, null);
185             String res = smartStackTraceParser.getString();
186             assertEquals("FailWithFail.testThatWillFail:25 abc", res);
187         }
188     }
189 
190     public void testCollectorWithNested() {
191         try {
192             InnerATestClass.testFake();
193         } catch (Throwable t) {
194             List<StackTraceElement> stackTraceElements =
195                     focusInsideClass(t.getStackTrace(), new ClassNameStackTraceFilter(InnerATestClass.class.getName()));
196             assertNotNull(stackTraceElements);
197             assertEquals(2, stackTraceElements.size());
198             StackTraceElement innerMost = stackTraceElements.get(0);
199             assertEquals(InnerATestClass.class.getName(), innerMost.getClassName());
200             StackTraceElement outer = stackTraceElements.get(1);
201             assertEquals(InnerATestClass.class.getName(), outer.getClassName());
202         }
203     }
204 
205     public void testNonClassNameStacktrace() {
206         SmartStackTraceParser smartStackTraceParser =
207                 new SmartStackTraceParser("Not a class name", new Throwable("my message"), null);
208         assertEquals("my message", smartStackTraceParser.getString());
209     }
210 
211     public void testNullElementInStackTrace() throws Exception {
212         ATestClass aTestClass = new ATestClass();
213         try {
214             aTestClass.failInAssert();
215         } catch (AssertionError e) {
216             SmartStackTraceParser smartStackTraceParser =
217                     new SmartStackTraceParser(ATestClass.class.getName(), e, null);
218             Field stackTrace = SmartStackTraceParser.class.getDeclaredField("stackTrace");
219             stackTrace.setAccessible(true);
220             stackTrace.set(smartStackTraceParser, new StackTraceElement[0]);
221             String res = smartStackTraceParser.getString();
222             assertEquals("ATestClass X is not Z", res);
223         }
224     }
225 
226     public void testSingleNestedWithThread() {
227         ExecutionException e = getSingleNested();
228         String name = getClass().getName();
229         Throwable focus = findTopmostWithClass(e, new ClassNameStackTraceFilter(name));
230         assertSame(e, focus);
231         List<StackTraceElement> stackTraceElements =
232                 focusInsideClass(focus.getStackTrace(), new ClassNameStackTraceFilter(name));
233         assertEquals(stackTraceElements.get(stackTraceElements.size() - 1).getClassName(), name);
234     }
235 
236     public void testDoubleNestedWithThread() {
237         ExecutionException e = getDoubleNestedException();
238 
239         String name = getClass().getName();
240         Throwable focus = findTopmostWithClass(e, new ClassNameStackTraceFilter(name));
241         assertSame(e, focus);
242         List<StackTraceElement> stackTraceElements =
243                 focusInsideClass(focus.getStackTrace(), new ClassNameStackTraceFilter(name));
244         assertEquals(stackTraceElements.get(stackTraceElements.size() - 1).getClassName(), name);
245 
246         name = RunnableTestClass1.class.getName();
247         focus = findTopmostWithClass(e, new ClassNameStackTraceFilter(name));
248         assertSame(e.getCause(), focus);
249         stackTraceElements = focusInsideClass(focus.getStackTrace(), new ClassNameStackTraceFilter(name));
250         assertEquals(stackTraceElements.get(stackTraceElements.size() - 1).getClassName(), name);
251     }
252 
253     public void testStackTraceWithFocusOnClassAsString() {
254         try {
255             new StackTraceFocusedOnClass.C().c();
256             fail();
257         } catch (Exception e) {
258             String trace = stackTraceWithFocusOnClassAsString(e, StackTraceFocusedOnClass.B.class.getName());
259 
260             assertEquals(
261                     "java.lang.RuntimeException: java.lang.IllegalStateException: java.io.IOException: I/O error\n"
262                             + "\tat org.apache.maven.surefire.report.StackTraceFocusedOnClass$B.b(StackTraceFocusedOnClass.java:49)\n"
263                             + "Caused by: java.lang.IllegalStateException: java.io.IOException: I/O error\n"
264                             + "\tat org.apache.maven.surefire.report.StackTraceFocusedOnClass$B.b(StackTraceFocusedOnClass.java:47)\n"
265                             + "Caused by: java.io.IOException: I/O error\n"
266                             + "\tat org.apache.maven.surefire.report.StackTraceFocusedOnClass$B.abs(StackTraceFocusedOnClass.java:55)\n"
267                             + "\tat org.apache.maven.surefire.report.StackTraceFocusedOnClass$B.b(StackTraceFocusedOnClass.java:47)\n",
268                     trace);
269         }
270     }
271 
272     public void testNullStackTrace() {
273         try {
274             new ATestClass().aMockedException();
275         } catch (Exception e) {
276             SmartStackTraceParser smartStackTraceParser =
277                     new SmartStackTraceParser(ATestClass.class.getName(), e, null);
278             String res = smartStackTraceParser.getString();
279             assertEquals("ATestClass » SomeMocked", res);
280         }
281     }
282 
283     private ExecutionException getSingleNested() {
284         FutureTask<Object> futureTask = new FutureTask<>(new RunnableTestClass2());
285         DaemonThreadFactory.newDaemonThread(futureTask).start();
286         try {
287             futureTask.get();
288         } catch (InterruptedException e) {
289             fail();
290         } catch (ExecutionException e) {
291             return e;
292         }
293         fail();
294         return null;
295     }
296 
297     private ExecutionException getDoubleNestedException() {
298         FutureTask<Object> futureTask = new FutureTask<>(new RunnableTestClass1());
299         DaemonThreadFactory.newDaemonThread(futureTask).start();
300         try {
301             futureTask.get();
302         } catch (InterruptedException e) {
303             fail();
304         } catch (ExecutionException e) {
305             return e;
306         }
307         return null;
308     }
309 }