View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.exception;
18  
19  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertNull;
24  import static org.junit.jupiter.api.Assertions.assertSame;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.io.ByteArrayOutputStream;
29  import java.io.IOException;
30  import java.io.PrintStream;
31  import java.io.PrintWriter;
32  import java.io.StringWriter;
33  import java.lang.reflect.Constructor;
34  import java.lang.reflect.Modifier;
35  import java.util.ArrayList;
36  import java.util.List;
37  import java.util.stream.Collectors;
38  
39  import org.apache.commons.lang3.AbstractLangTest;
40  import org.apache.commons.lang3.test.NotVisibleExceptionFactory;
41  import org.junit.jupiter.api.AfterEach;
42  import org.junit.jupiter.api.BeforeEach;
43  import org.junit.jupiter.api.DisplayName;
44  import org.junit.jupiter.api.Test;
45  
46  /**
47   * Tests {@link org.apache.commons.lang3.exception.ExceptionUtils}.
48   *
49   * @since 1.0
50   */
51  public class ExceptionUtilsTest extends AbstractLangTest {
52  
53      /**
54       * Provides a method with a well known chained/nested exception
55       * name which matches the full signature (e.g. has a return value
56       * of {@code Throwable}).
57       */
58      private static final class ExceptionWithCause extends Exception {
59          private static final long serialVersionUID = 1L;
60  
61          private Throwable cause;
62  
63          ExceptionWithCause(final String str, final Throwable cause) {
64              super(str);
65              setCause(cause);
66          }
67  
68          ExceptionWithCause(final Throwable cause) {
69              setCause(cause);
70          }
71  
72          @Override
73          public synchronized Throwable getCause() {
74              return cause;
75          }
76  
77          public void setCause(final Throwable cause) {
78              this.cause = cause;
79          }
80      }
81  
82      /**
83       * Provides a method with a well known chained/nested exception
84       * name which does not match the full signature (e.g. lacks a
85       * return value of {@code Throwable}).
86       */
87      private static final class ExceptionWithoutCause extends Exception {
88          private static final long serialVersionUID = 1L;
89  
90          @SuppressWarnings("unused")
91          public void getTargetException() {
92              // noop
93          }
94      }
95  
96      // Temporary classes to allow the nested exception code to be removed
97      // prior to a rewrite of this test class.
98      private static final class NestableException extends Exception {
99          private static final long serialVersionUID = 1L;
100 
101         @SuppressWarnings("unused")
102         NestableException() {
103         }
104 
105         NestableException(final Throwable t) {
106             super(t);
107         }
108     }
109 
110     public static class TestThrowable extends Throwable {
111         private static final long serialVersionUID = 1L;
112     }
113 
114     private static int redeclareCheckedException() {
115         return throwsCheckedException();
116     }
117 
118     private static int throwsCheckedException() {
119         try {
120             throw new IOException();
121         } catch (final Exception e) {
122             ExceptionUtils.asRuntimeException(e);
123             return -1;
124         }
125     }
126 
127     private ExceptionWithCause cyclicCause;
128 
129 
130     private Throwable jdkNoCause;
131 
132     private NestableException nested;
133 
134     private Throwable notVisibleException;
135 
136     private Throwable withCause;
137 
138     private Throwable withoutCause;
139 
140     private Throwable createExceptionWithCause() {
141         try {
142             try {
143                 throw new ExceptionWithCause(createExceptionWithoutCause());
144             } catch (final Throwable t) {
145                 throw new ExceptionWithCause(t);
146             }
147         } catch (final Throwable t) {
148             return t;
149         }
150     }
151 
152     private Throwable createExceptionWithoutCause() {
153         try {
154             throw new ExceptionWithoutCause();
155         } catch (final Throwable t) {
156             return t;
157         }
158     }
159 
160     @BeforeEach
161     public void setUp() {
162         withoutCause = createExceptionWithoutCause();
163         nested = new NestableException(withoutCause);
164         withCause = new ExceptionWithCause(nested);
165         jdkNoCause = new NullPointerException();
166         final ExceptionWithCause a = new ExceptionWithCause(null);
167         final ExceptionWithCause b = new ExceptionWithCause(a);
168         a.setCause(b);
169         cyclicCause = new ExceptionWithCause(a);
170         notVisibleException = NotVisibleExceptionFactory.createException(withoutCause);
171     }
172 
173     @AfterEach
174     public void tearDown() {
175         withoutCause = null;
176         nested = null;
177         withCause = null;
178         jdkNoCause = null;
179         cyclicCause = null;
180         notVisibleException = null;
181     }
182 
183     @Test
184     public void test_getMessage_Throwable() {
185         Throwable th = null;
186         assertEquals("", ExceptionUtils.getMessage(th));
187 
188         th = new IllegalArgumentException("Base");
189         assertEquals("IllegalArgumentException: Base", ExceptionUtils.getMessage(th));
190 
191         th = new ExceptionWithCause("Wrapper", th);
192         assertEquals("ExceptionUtilsTest.ExceptionWithCause: Wrapper", ExceptionUtils.getMessage(th));
193     }
194 
195     @Test
196     public void test_getRootCauseMessage_Throwable() {
197         Throwable th = null;
198         assertEquals("", ExceptionUtils.getRootCauseMessage(th));
199 
200         th = new IllegalArgumentException("Base");
201         assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
202 
203         th = new ExceptionWithCause("Wrapper", th);
204         assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
205     }
206 
207     @Test
208     public void testAsRuntimeException() {
209         final Exception expected = new InterruptedException();
210         final Exception actual = assertThrows(Exception.class, () -> ExceptionUtils.asRuntimeException(expected));
211         assertSame(expected, actual);
212     }
213 
214     @Test
215     public void testCatchTechniques() {
216         IOException ioe = assertThrows(IOException.class, ExceptionUtilsTest::throwsCheckedException);
217         assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
218 
219         ioe = assertThrows(IOException.class, ExceptionUtilsTest::redeclareCheckedException);
220         assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
221     }
222 
223     @Test
224     public void testConstructor() {
225         assertNotNull(new ExceptionUtils());
226         final Constructor<?>[] cons = ExceptionUtils.class.getDeclaredConstructors();
227         assertEquals(1, cons.length);
228         assertTrue(Modifier.isPublic(cons[0].getModifiers()));
229         assertTrue(Modifier.isPublic(ExceptionUtils.class.getModifiers()));
230         assertFalse(Modifier.isFinal(ExceptionUtils.class.getModifiers()));
231     }
232 
233     @Test
234     public void testForEach_jdkNoCause() {
235         final List<Throwable> throwables = new ArrayList<>();
236         ExceptionUtils.forEach(jdkNoCause, throwables::add);
237         assertEquals(1, throwables.size());
238         assertSame(jdkNoCause, throwables.get(0));
239     }
240 
241     @Test
242     public void testForEach_nested() {
243         final List<Throwable> throwables = new ArrayList<>();
244         ExceptionUtils.forEach(nested, throwables::add);
245         assertEquals(2, throwables.size());
246         assertSame(nested, throwables.get(0));
247         assertSame(withoutCause, throwables.get(1));
248     }
249 
250     @Test
251     public void testForEach_null() {
252         final List<Throwable> throwables = new ArrayList<>();
253         ExceptionUtils.forEach(null, throwables::add);
254         assertEquals(0, throwables.size());
255     }
256 
257     @Test
258     public void testForEach_recursiveCause() {
259         final List<Throwable> throwables = new ArrayList<>();
260         ExceptionUtils.forEach(cyclicCause, throwables::add);
261         assertEquals(3, throwables.size());
262         assertSame(cyclicCause, throwables.get(0));
263         assertSame(cyclicCause.getCause(), throwables.get(1));
264         assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
265     }
266 
267     @Test
268     public void testForEach_withCause() {
269         final List<Throwable> throwables = new ArrayList<>();
270         ExceptionUtils.forEach(withCause, throwables::add);
271         assertEquals(3, throwables.size());
272         assertSame(withCause, throwables.get(0));
273         assertSame(nested, throwables.get(1));
274         assertSame(withoutCause, throwables.get(2));
275     }
276 
277     @Test
278     public void testForEach_withoutCause() {
279         final List<Throwable> throwables = new ArrayList<>();
280         ExceptionUtils.forEach(withoutCause, throwables::add);
281         assertEquals(1, throwables.size());
282         assertSame(withoutCause, throwables.get(0));
283     }
284 
285     @SuppressWarnings("deprecation") // Specifically tests the deprecated methods
286     @Test
287     public void testGetCause_Throwable() {
288         assertSame(null, ExceptionUtils.getCause(null));
289         assertSame(null, ExceptionUtils.getCause(withoutCause));
290         assertSame(withoutCause, ExceptionUtils.getCause(nested));
291         assertSame(nested, ExceptionUtils.getCause(withCause));
292         assertSame(null, ExceptionUtils.getCause(jdkNoCause));
293         assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(cyclicCause));
294         assertSame(cyclicCause.getCause().getCause(), ExceptionUtils.getCause(cyclicCause.getCause()));
295         assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(cyclicCause.getCause().getCause()));
296         assertSame(withoutCause, ExceptionUtils.getCause(notVisibleException));
297     }
298 
299     @SuppressWarnings("deprecation") // Specifically tests the deprecated methods
300     @Test
301     public void testGetCause_ThrowableArray() {
302         assertSame(null, ExceptionUtils.getCause(null, null));
303         assertSame(null, ExceptionUtils.getCause(null, new String[0]));
304 
305         // not known type, so match on supplied method names
306         assertSame(nested, ExceptionUtils.getCause(withCause, null));  // default names
307         assertSame(null, ExceptionUtils.getCause(withCause, new String[0]));
308         assertSame(null, ExceptionUtils.getCause(withCause, new String[]{null}));
309         assertSame(nested, ExceptionUtils.getCause(withCause, new String[]{"getCause"}));
310 
311         // not known type, so match on supplied method names
312         assertSame(null, ExceptionUtils.getCause(withoutCause, null));
313         assertSame(null, ExceptionUtils.getCause(withoutCause, new String[0]));
314         assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{null}));
315         assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{"getCause"}));
316         assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{"getTargetException"}));
317     }
318 
319     @Test
320     public void testGetRootCause_Throwable() {
321         assertSame(null, ExceptionUtils.getRootCause(null));
322         assertSame(withoutCause, ExceptionUtils.getRootCause(withoutCause));
323         assertSame(withoutCause, ExceptionUtils.getRootCause(nested));
324         assertSame(withoutCause, ExceptionUtils.getRootCause(withCause));
325         assertSame(jdkNoCause, ExceptionUtils.getRootCause(jdkNoCause));
326         assertSame(cyclicCause.getCause().getCause(), ExceptionUtils.getRootCause(cyclicCause));
327     }
328 
329     @Test
330     public void testGetRootCauseStackTrace_Throwable() {
331         assertEquals(0, ExceptionUtils.getRootCauseStackTrace(null).length);
332 
333         final Throwable cause = createExceptionWithCause();
334         String[] stackTrace = ExceptionUtils.getRootCauseStackTrace(cause);
335         boolean match = false;
336         for (final String element : stackTrace) {
337             if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
338                 match = true;
339                 break;
340             }
341         }
342         assertTrue(match);
343 
344         stackTrace = ExceptionUtils.getRootCauseStackTrace(withoutCause);
345         match = false;
346         for (final String element : stackTrace) {
347             if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
348                 match = true;
349                 break;
350             }
351         }
352         assertFalse(match);
353     }
354 
355     @Test
356     public void testGetRootCauseStackTraceList_Throwable() {
357         assertEquals(0, ExceptionUtils.getRootCauseStackTraceList(null).size());
358 
359         final Throwable cause = createExceptionWithCause();
360         List<String> stackTrace = ExceptionUtils.getRootCauseStackTraceList(cause);
361         boolean match = false;
362         for (final String element : stackTrace) {
363             if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
364                 match = true;
365                 break;
366             }
367         }
368         assertTrue(match);
369 
370         stackTrace = ExceptionUtils.getRootCauseStackTraceList(withoutCause);
371         match = false;
372         for (final String element : stackTrace) {
373             if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
374                 match = true;
375                 break;
376             }
377         }
378         assertFalse(match);
379     }
380 
381     @Test
382     @DisplayName("getStackFrames returns empty string array when the argument is null")
383     public void testgetStackFramesHappyPath() {
384         final String[] actual = ExceptionUtils.getStackFrames(new Throwable() {
385             private static final long serialVersionUID = 1L;
386 
387             // provide static stack trace to make test stable
388             @Override
389             public void printStackTrace(final PrintWriter s) {
390                 s.write("org.apache.commons.lang3.exception.ExceptionUtilsTest$1\n" +
391                     "\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)\n" +
392                     "\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" +
393                     "\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)\n" +
394                     "\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)\n");
395             }
396         });
397 
398         assertArrayEquals(new String[]{
399             "org.apache.commons.lang3.exception.ExceptionUtilsTest$1",
400             "\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)",
401             "\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
402             "\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)",
403             "\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)"
404         }, actual);
405     }
406 
407     @Test
408     @DisplayName("getStackFrames returns the string array of the stack frames when there is a real exception")
409     public void testgetStackFramesNullArg() {
410         final String[] actual = ExceptionUtils.getStackFrames((Throwable) null);
411         assertEquals(0, actual.length);
412     }
413 
414     @Test
415     public void testGetThrowableCount_Throwable() {
416         assertEquals(0, ExceptionUtils.getThrowableCount(null));
417         assertEquals(1, ExceptionUtils.getThrowableCount(withoutCause));
418         assertEquals(2, ExceptionUtils.getThrowableCount(nested));
419         assertEquals(3, ExceptionUtils.getThrowableCount(withCause));
420         assertEquals(1, ExceptionUtils.getThrowableCount(jdkNoCause));
421         assertEquals(3, ExceptionUtils.getThrowableCount(cyclicCause));
422     }
423 
424     @Test
425     public void testGetThrowableList_Throwable_jdkNoCause() {
426         final List<?> throwables = ExceptionUtils.getThrowableList(jdkNoCause);
427         assertEquals(1, throwables.size());
428         assertSame(jdkNoCause, throwables.get(0));
429     }
430 
431     @Test
432     public void testGetThrowableList_Throwable_nested() {
433         final List<?> throwables = ExceptionUtils.getThrowableList(nested);
434         assertEquals(2, throwables.size());
435         assertSame(nested, throwables.get(0));
436         assertSame(withoutCause, throwables.get(1));
437     }
438 
439     @Test
440     public void testGetThrowableList_Throwable_null() {
441         final List<?> throwables = ExceptionUtils.getThrowableList(null);
442         assertEquals(0, throwables.size());
443     }
444 
445     @Test
446     public void testGetThrowableList_Throwable_recursiveCause() {
447         final List<?> throwables = ExceptionUtils.getThrowableList(cyclicCause);
448         assertEquals(3, throwables.size());
449         assertSame(cyclicCause, throwables.get(0));
450         assertSame(cyclicCause.getCause(), throwables.get(1));
451         assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
452     }
453 
454     @Test
455     public void testGetThrowableList_Throwable_withCause() {
456         final List<?> throwables = ExceptionUtils.getThrowableList(withCause);
457         assertEquals(3, throwables.size());
458         assertSame(withCause, throwables.get(0));
459         assertSame(nested, throwables.get(1));
460         assertSame(withoutCause, throwables.get(2));
461     }
462 
463     @Test
464     public void testGetThrowableList_Throwable_withoutCause() {
465         final List<?> throwables = ExceptionUtils.getThrowableList(withoutCause);
466         assertEquals(1, throwables.size());
467         assertSame(withoutCause, throwables.get(0));
468     }
469 
470     @Test
471     public void testGetThrowables_Throwable_jdkNoCause() {
472         final Throwable[] throwables = ExceptionUtils.getThrowables(jdkNoCause);
473         assertEquals(1, throwables.length);
474         assertSame(jdkNoCause, throwables[0]);
475     }
476 
477     @Test
478     public void testGetThrowables_Throwable_nested() {
479         final Throwable[] throwables = ExceptionUtils.getThrowables(nested);
480         assertEquals(2, throwables.length);
481         assertSame(nested, throwables[0]);
482         assertSame(withoutCause, throwables[1]);
483     }
484 
485     @Test
486     public void testGetThrowables_Throwable_null() {
487         assertEquals(0, ExceptionUtils.getThrowables(null).length);
488     }
489 
490     @Test
491     public void testGetThrowables_Throwable_recursiveCause() {
492         final Throwable[] throwables = ExceptionUtils.getThrowables(cyclicCause);
493         assertEquals(3, throwables.length);
494         assertSame(cyclicCause, throwables[0]);
495         assertSame(cyclicCause.getCause(), throwables[1]);
496         assertSame(cyclicCause.getCause().getCause(), throwables[2]);
497     }
498 
499     @Test
500     public void testGetThrowables_Throwable_withCause() {
501         final Throwable[] throwables = ExceptionUtils.getThrowables(withCause);
502         assertEquals(3, throwables.length);
503         assertSame(withCause, throwables[0]);
504         assertSame(nested, throwables[1]);
505         assertSame(withoutCause, throwables[2]);
506     }
507 
508     @Test
509     public void testGetThrowables_Throwable_withoutCause() {
510         final Throwable[] throwables = ExceptionUtils.getThrowables(withoutCause);
511         assertEquals(1, throwables.length);
512         assertSame(withoutCause, throwables[0]);
513     }
514 
515     @Test
516     public void testIndexOf_ThrowableClass() {
517         assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null));
518         assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class));
519 
520         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
521         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class));
522         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class));
523         assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class));
524 
525         assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null));
526         assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class));
527         assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class));
528         assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class));
529 
530         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
531         assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class));
532         assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class));
533         assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class));
534 
535         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class));
536         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class));
537     }
538 
539     @Test
540     public void testIndexOf_ThrowableClassInt() {
541         assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null, 0));
542         assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class, 0));
543 
544         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
545         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class, 0));
546         assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class, 0));
547         assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class, 0));
548 
549         assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null, 0));
550         assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class, 0));
551         assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class, 0));
552         assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class, 0));
553 
554         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
555         assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
556         assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class, 0));
557         assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class, 0));
558 
559         assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, -1));
560         assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
561         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 1));
562         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 9));
563 
564         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class, 0));
565         assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class, 0));
566     }
567 
568     @Test
569     public void testIndexOfType_ThrowableClass() {
570         assertEquals(-1, ExceptionUtils.indexOfType(null, null));
571         assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class));
572 
573         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
574         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class));
575         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class));
576         assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class));
577 
578         assertEquals(-1, ExceptionUtils.indexOfType(nested, null));
579         assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class));
580         assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class));
581         assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class));
582 
583         assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
584         assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class));
585         assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class));
586         assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class));
587 
588         assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class));
589         assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class));
590     }
591 
592     @Test
593     public void testIndexOfType_ThrowableClassInt() {
594         assertEquals(-1, ExceptionUtils.indexOfType(null, null, 0));
595         assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class, 0));
596 
597         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
598         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class, 0));
599         assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class, 0));
600         assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class, 0));
601 
602         assertEquals(-1, ExceptionUtils.indexOfType(nested, null, 0));
603         assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class, 0));
604         assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class, 0));
605         assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class, 0));
606 
607         assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
608         assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
609         assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class, 0));
610         assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class, 0));
611 
612         assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, -1));
613         assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
614         assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 1));
615         assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 9));
616 
617         assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class, 0));
618         assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class, 0));
619     }
620 
621     @Test
622     public void testIsChecked_checked() {
623         assertTrue(ExceptionUtils.isChecked(new IOException()));
624     }
625 
626     @Test
627     public void testIsChecked_error() {
628         assertFalse(ExceptionUtils.isChecked(new StackOverflowError()));
629     }
630 
631     @Test
632     public void testIsChecked_null() {
633         assertFalse(ExceptionUtils.isChecked(null));
634     }
635 
636     @Test
637     public void testIsChecked_unchecked() {
638         assertFalse(ExceptionUtils.isChecked(new IllegalArgumentException()));
639     }
640 
641     @Test
642     public void testIsCheckedCustomThrowable() {
643         assertTrue(ExceptionUtils.isChecked(new TestThrowable()));
644     }
645 
646     @Test
647     public void testIsUnchecked_checked() {
648         assertFalse(ExceptionUtils.isUnchecked(new IOException()));
649     }
650 
651     @Test
652     public void testIsUnchecked_error() {
653         assertTrue(ExceptionUtils.isUnchecked(new StackOverflowError()));
654     }
655 
656     @Test
657     public void testIsUnchecked_null() {
658         assertFalse(ExceptionUtils.isUnchecked(null));
659     }
660 
661     @Test
662     public void testIsUnchecked_unchecked() {
663         assertTrue(ExceptionUtils.isUnchecked(new IllegalArgumentException()));
664     }
665 
666     @Test
667     public void testIsUnCheckedCustomThrowable() {
668         assertFalse(ExceptionUtils.isUnchecked(new TestThrowable()));
669     }
670 
671     @Test
672     public void testPrintRootCauseStackTrace_Throwable() {
673         ExceptionUtils.printRootCauseStackTrace(null);
674         // could pipe system.err to a known stream, but not much point as
675         // internally this method calls stream method anyway
676     }
677 
678     @Test
679     public void testPrintRootCauseStackTrace_ThrowableStream() {
680         ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
681         ExceptionUtils.printRootCauseStackTrace(null, (PrintStream) null);
682         ExceptionUtils.printRootCauseStackTrace(null, new PrintStream(out));
683         assertEquals(0, out.toString().length());
684 
685         out = new ByteArrayOutputStream(1024);
686         assertThrows(
687                 NullPointerException.class,
688                 () -> ExceptionUtils.printRootCauseStackTrace(withCause, (PrintStream) null));
689 
690         out = new ByteArrayOutputStream(1024);
691         final Throwable cause = createExceptionWithCause();
692         ExceptionUtils.printRootCauseStackTrace(cause, new PrintStream(out));
693         String stackTrace = out.toString();
694         assertTrue(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
695 
696         out = new ByteArrayOutputStream(1024);
697         ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintStream(out));
698         stackTrace = out.toString();
699         assertFalse(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
700     }
701 
702     @Test
703     public void testPrintRootCauseStackTrace_ThrowableWriter() {
704         StringWriter writer = new StringWriter(1024);
705         ExceptionUtils.printRootCauseStackTrace(null, (PrintWriter) null);
706         ExceptionUtils.printRootCauseStackTrace(null, new PrintWriter(writer));
707         assertEquals(0, writer.getBuffer().length());
708 
709         writer = new StringWriter(1024);
710         assertThrows(
711                 NullPointerException.class,
712                 () -> ExceptionUtils.printRootCauseStackTrace(withCause, (PrintWriter) null));
713 
714         writer = new StringWriter(1024);
715         final Throwable cause = createExceptionWithCause();
716         ExceptionUtils.printRootCauseStackTrace(cause, new PrintWriter(writer));
717         String stackTrace = writer.toString();
718         assertTrue(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
719 
720         writer = new StringWriter(1024);
721         ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintWriter(writer));
722         stackTrace = writer.toString();
723         assertFalse(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
724     }
725 
726     @Test
727     public void testRemoveCommonFrames_ListList() {
728         assertThrows(NullPointerException.class, () -> ExceptionUtils.removeCommonFrames(null, null));
729     }
730 
731     @Test
732     public void testRethrow() {
733         final Exception expected = new InterruptedException();
734         final Exception actual = assertThrows(Exception.class, () -> ExceptionUtils.rethrow(expected));
735         assertSame(expected, actual);
736     }
737 
738     @Test
739     public void testStream_jdkNoCause() {
740         assertEquals(1, ExceptionUtils.stream(jdkNoCause).count());
741         assertSame(jdkNoCause, ExceptionUtils.stream(jdkNoCause).toArray()[0]);
742     }
743 
744     @Test
745     public void testStream_nested() {
746         assertEquals(2, ExceptionUtils.stream(nested).count());
747         final Object[] array = ExceptionUtils.stream(nested).toArray();
748         assertSame(nested, array[0]);
749         assertSame(withoutCause, array[1]);
750     }
751 
752     @Test
753     public void testStream_null() {
754         assertEquals(0, ExceptionUtils.stream(null).count());
755     }
756 
757     @Test
758     public void testStream_recursiveCause() {
759         final List<?> throwables = ExceptionUtils.stream(cyclicCause).collect(Collectors.toList());
760         assertEquals(3, throwables.size());
761         assertSame(cyclicCause, throwables.get(0));
762         assertSame(cyclicCause.getCause(), throwables.get(1));
763         assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
764     }
765 
766     @Test
767     public void testStream_withCause() {
768         final List<?> throwables = ExceptionUtils.stream(withCause).collect(Collectors.toList());
769         assertEquals(3, throwables.size());
770         assertSame(withCause, throwables.get(0));
771         assertSame(nested, throwables.get(1));
772         assertSame(withoutCause, throwables.get(2));
773     }
774 
775     @Test
776     public void testStream_withoutCause() {
777         final List<?> throwables = ExceptionUtils.stream(withoutCause).collect(Collectors.toList());
778         assertEquals(1, throwables.size());
779         assertSame(withoutCause, throwables.get(0));
780     }
781 
782     @Test
783     public void testThrowableOf_ThrowableClass() {
784         assertNull(ExceptionUtils.throwableOfThrowable(null, null));
785         assertNull(ExceptionUtils.throwableOfThrowable(null, NestableException.class));
786 
787         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, null));
788         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class));
789         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class));
790         assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class));
791 
792         assertNull(ExceptionUtils.throwableOfThrowable(nested, null));
793         assertNull(ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class));
794         assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class));
795         assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class));
796 
797         assertNull(ExceptionUtils.throwableOfThrowable(withCause, null));
798         assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class));
799         assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class));
800         assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class));
801 
802         assertNull(ExceptionUtils.throwableOfThrowable(withCause, Exception.class));
803         assertNull(ExceptionUtils.throwableOfThrowable(withCause, Throwable.class));
804     }
805 
806     @Test
807     public void testThrowableOf_ThrowableClassInt() {
808         assertNull(ExceptionUtils.throwableOfThrowable(null, null, 0));
809         assertNull(ExceptionUtils.throwableOfThrowable(null, NestableException.class, 0));
810 
811         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, null));
812         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class, 0));
813         assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class, 0));
814         assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class, 0));
815 
816         assertNull(ExceptionUtils.throwableOfThrowable(nested, null, 0));
817         assertNull(ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class, 0));
818         assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class, 0));
819         assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class, 0));
820 
821         assertNull(ExceptionUtils.throwableOfThrowable(withCause, null));
822         assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0));
823         assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class, 0));
824         assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class, 0));
825 
826         assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, -1));
827         assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0));
828         assertNull(ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 1));
829         assertNull(ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 9));
830 
831         assertNull(ExceptionUtils.throwableOfThrowable(withCause, Exception.class, 0));
832         assertNull(ExceptionUtils.throwableOfThrowable(withCause, Throwable.class, 0));
833     }
834 
835     @Test
836     public void testThrowableOfType_ThrowableClass() {
837         assertNull(ExceptionUtils.throwableOfType(null, null));
838         assertNull(ExceptionUtils.throwableOfType(null, NestableException.class));
839 
840         assertNull(ExceptionUtils.throwableOfType(withoutCause, null));
841         assertNull(ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class));
842         assertNull(ExceptionUtils.throwableOfType(withoutCause, NestableException.class));
843         assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class));
844 
845         assertNull(ExceptionUtils.throwableOfType(nested, null));
846         assertNull(ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class));
847         assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class));
848         assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class));
849 
850         assertNull(ExceptionUtils.throwableOfType(withCause, null));
851         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class));
852         assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class));
853         assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class));
854 
855         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class));
856         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class));
857     }
858 
859     @Test
860     public void testThrowableOfType_ThrowableClassInt() {
861         assertNull(ExceptionUtils.throwableOfType(null, null, 0));
862         assertNull(ExceptionUtils.throwableOfType(null, NestableException.class, 0));
863 
864         assertNull(ExceptionUtils.throwableOfType(withoutCause, null));
865         assertNull(ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class, 0));
866         assertNull(ExceptionUtils.throwableOfType(withoutCause, NestableException.class, 0));
867         assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class, 0));
868 
869         assertNull(ExceptionUtils.throwableOfType(nested, null, 0));
870         assertNull(ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class, 0));
871         assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class, 0));
872         assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class, 0));
873 
874         assertNull(ExceptionUtils.throwableOfType(withCause, null));
875         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0));
876         assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class, 0));
877         assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class, 0));
878 
879         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, -1));
880         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0));
881         assertNull(ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 1));
882         assertNull(ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 9));
883 
884         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class, 0));
885         assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class, 0));
886     }
887 
888     @Test
889     public void testWrapAndUnwrapCheckedException() {
890         final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new IOException()));
891         assertTrue(ExceptionUtils.hasCause(t, IOException.class));
892     }
893 
894     @Test
895     public void testWrapAndUnwrapError() {
896         final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new OutOfMemoryError()));
897         assertTrue(ExceptionUtils.hasCause(t, Error.class));
898     }
899 
900     @Test
901     public void testWrapAndUnwrapRuntimeException() {
902         final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new IllegalArgumentException()));
903         assertTrue(ExceptionUtils.hasCause(t, RuntimeException.class));
904     }
905 
906     @Test
907     public void testWrapAndUnwrapThrowable() {
908         final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new TestThrowable()));
909         assertTrue(ExceptionUtils.hasCause(t, TestThrowable.class));
910     }
911 }