1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.exception;
18
19 import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertNotSame;
25 import static org.junit.jupiter.api.Assertions.assertNull;
26 import static org.junit.jupiter.api.Assertions.assertSame;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29 import static org.junit.jupiter.api.Assertions.fail;
30
31 import java.io.ByteArrayOutputStream;
32 import java.io.IOException;
33 import java.io.PrintStream;
34 import java.io.PrintWriter;
35 import java.io.StringWriter;
36 import java.lang.reflect.Constructor;
37 import java.lang.reflect.Modifier;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.stream.Collectors;
42
43 import org.apache.commons.lang3.AbstractLangTest;
44 import org.apache.commons.lang3.test.NotVisibleExceptionFactory;
45 import org.junit.jupiter.api.AfterEach;
46 import org.junit.jupiter.api.BeforeEach;
47 import org.junit.jupiter.api.Test;
48
49
50
51
52 class ExceptionUtilsTest extends AbstractLangTest {
53
54 private static final class CountingException extends Exception {
55 private static final long serialVersionUID = 1L;
56
57 private int causeCalls;
58
59 CountingException(final Throwable cause) {
60 super(null, cause, false, false);
61 }
62
63 @Override
64 public boolean equals(final Object obj) {
65 throw new AssertionError("Chain walking must not invoke equals");
66 }
67
68 @Override
69 public synchronized Throwable getCause() {
70 causeCalls++;
71 return super.getCause();
72 }
73
74 @Override
75 public int hashCode() {
76 throw new AssertionError("Chain walking must not invoke hashCode");
77 }
78 }
79
80 private static final class EqualException extends Exception {
81 private static final long serialVersionUID = 1L;
82
83 @Override
84 public boolean equals(final Object obj) {
85 return obj instanceof EqualException;
86 }
87
88 @Override
89 public int hashCode() {
90 return 1;
91 }
92 }
93
94
95
96
97
98
99 private static final class ExceptionWithCause extends Exception {
100 private static final long serialVersionUID = 1L;
101
102 private Throwable cause;
103
104 ExceptionWithCause(final String str, final Throwable cause) {
105 super(str);
106 setCause(cause);
107 }
108
109 ExceptionWithCause(final Throwable cause) {
110 setCause(cause);
111 }
112
113 @Override
114 public synchronized Throwable getCause() {
115 return cause;
116 }
117
118 public void setCause(final Throwable cause) {
119 this.cause = cause;
120 }
121 }
122
123
124
125
126
127
128 private static final class ExceptionWithoutCause extends Exception {
129 private static final long serialVersionUID = 1L;
130
131 @SuppressWarnings("unused")
132 public void getTargetException() {
133
134 }
135 }
136
137
138
139 private static final class NestableException extends Exception {
140 private static final long serialVersionUID = 1L;
141
142 @SuppressWarnings("unused")
143 NestableException() {
144 }
145
146 NestableException(final Throwable t) {
147 super(t);
148 }
149 }
150
151 public static class TestThrowable extends Throwable {
152 private static final long serialVersionUID = 1L;
153 }
154
155 private static int redeclareCheckedException() {
156 return throwsCheckedException();
157 }
158
159 private static int throwsCheckedException() {
160 try {
161 throw new IOException();
162 } catch (final Exception e) {
163 ExceptionUtils.asRuntimeException(e);
164 return -1;
165 }
166 }
167
168 private ExceptionWithCause cyclicCause;
169
170 private Throwable jdkNoCause;
171
172 private NestableException nested;
173
174 private Throwable notVisibleException;
175
176 private Throwable withCause;
177
178 private Throwable withoutCause;
179
180 private Throwable createExceptionWithCause() {
181 try {
182 try {
183 throw new ExceptionWithCause(createExceptionWithoutCause());
184 } catch (final Throwable t) {
185 throw new ExceptionWithCause(t);
186 }
187 } catch (final Throwable t) {
188 return t;
189 }
190 }
191
192 private Throwable createExceptionWithoutCause() {
193 try {
194 throw new ExceptionWithoutCause();
195 } catch (final Throwable t) {
196 return t;
197 }
198 }
199
200 @BeforeEach
201 public void setUp() {
202 withoutCause = createExceptionWithoutCause();
203 nested = new NestableException(withoutCause);
204 withCause = new ExceptionWithCause(nested);
205 jdkNoCause = new NullPointerException();
206 final ExceptionWithCause a = new ExceptionWithCause(null);
207 final ExceptionWithCause b = new ExceptionWithCause(a);
208 a.setCause(b);
209 cyclicCause = new ExceptionWithCause(a);
210 notVisibleException = NotVisibleExceptionFactory.createException(withoutCause);
211 }
212
213 @AfterEach
214 public void tearDown() {
215 withoutCause = null;
216 nested = null;
217 withCause = null;
218 jdkNoCause = null;
219 cyclicCause = null;
220 notVisibleException = null;
221 }
222
223 @Test
224 void test_getMessage_Throwable() {
225 Throwable th = null;
226 assertEquals("", ExceptionUtils.getMessage(th));
227
228 th = new IllegalArgumentException("Base");
229 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getMessage(th));
230
231 th = new ExceptionWithCause("Wrapper", th);
232 assertEquals("ExceptionUtilsTest.ExceptionWithCause: Wrapper", ExceptionUtils.getMessage(th));
233 }
234
235 @Test
236 void test_getRootCauseMessage_Throwable() {
237 Throwable th = null;
238 assertEquals("", ExceptionUtils.getRootCauseMessage(th));
239
240 th = new IllegalArgumentException("Base");
241 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
242
243 th = new ExceptionWithCause("Wrapper", th);
244 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
245 }
246
247 @Test
248 void testAsRuntimeException() {
249 final Exception expected = new InterruptedException();
250 assertSame(expected, assertThrows(Exception.class, () -> ExceptionUtils.asRuntimeException(expected)));
251 assertNotSame(expected, assertThrows(Exception.class, () -> ExceptionUtils.asRuntimeException(new InterruptedException())));
252
253 assertThrows(expected.getClass(), () -> {
254 @SuppressWarnings("unused")
255 final Object retVal = ExceptionUtils.asRuntimeException(expected);
256 });
257
258 assertThrows(expected.getClass(), () -> {
259 @SuppressWarnings("unused")
260 final RuntimeException retVal = ExceptionUtils.asRuntimeException(expected);
261 });
262
263 assertThrows(expected.getClass(), () -> {
264 @SuppressWarnings("unused")
265 final IllegalStateException retVal = ExceptionUtils.asRuntimeException(expected);
266 });
267 }
268
269 @Test
270 void testCatchTechniques() {
271 IOException ioe = assertThrows(IOException.class, ExceptionUtilsTest::throwsCheckedException);
272 assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
273
274 ioe = assertThrows(IOException.class, ExceptionUtilsTest::redeclareCheckedException);
275 assertEquals(1, ExceptionUtils.getThrowableCount(ioe));
276 }
277
278 @Test
279 void testConstructor() {
280 assertNotNull(new ExceptionUtils());
281 final Constructor<?>[] cons = ExceptionUtils.class.getDeclaredConstructors();
282 assertEquals(1, cons.length);
283 assertTrue(Modifier.isPublic(cons[0].getModifiers()));
284 assertTrue(Modifier.isPublic(ExceptionUtils.class.getModifiers()));
285 assertFalse(Modifier.isFinal(ExceptionUtils.class.getModifiers()));
286 }
287
288 @Test
289 void testForEach_jdkNoCause() {
290 final List<Throwable> throwables = new ArrayList<>();
291 ExceptionUtils.forEach(jdkNoCause, throwables::add);
292 assertEquals(1, throwables.size());
293 assertSame(jdkNoCause, throwables.get(0));
294 }
295
296 @Test
297 void testForEach_nested() {
298 final List<Throwable> throwables = new ArrayList<>();
299 ExceptionUtils.forEach(nested, throwables::add);
300 assertEquals(2, throwables.size());
301 assertSame(nested, throwables.get(0));
302 assertSame(withoutCause, throwables.get(1));
303 }
304
305 @Test
306 void testForEach_null() {
307 final List<Throwable> throwables = new ArrayList<>();
308 ExceptionUtils.forEach(null, throwables::add);
309 assertEquals(0, throwables.size());
310 }
311
312 @Test
313 void testForEach_recursiveCause() {
314 final List<Throwable> throwables = new ArrayList<>();
315 ExceptionUtils.forEach(cyclicCause, throwables::add);
316 assertEquals(3, throwables.size());
317 assertSame(cyclicCause, throwables.get(0));
318 assertSame(cyclicCause.getCause(), throwables.get(1));
319 assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
320 }
321
322 @Test
323 void testForEach_withCause() {
324 final List<Throwable> throwables = new ArrayList<>();
325 ExceptionUtils.forEach(withCause, throwables::add);
326 assertEquals(3, throwables.size());
327 assertSame(withCause, throwables.get(0));
328 assertSame(nested, throwables.get(1));
329 assertSame(withoutCause, throwables.get(2));
330 }
331
332 @Test
333 void testForEach_withoutCause() {
334 final List<Throwable> throwables = new ArrayList<>();
335 ExceptionUtils.forEach(withoutCause, throwables::add);
336 assertEquals(1, throwables.size());
337 assertSame(withoutCause, throwables.get(0));
338 }
339
340 @SuppressWarnings("deprecation")
341 @Test
342 void testGetCause_Throwable() {
343 assertSame(null, ExceptionUtils.getCause(null));
344 assertSame(null, ExceptionUtils.getCause(withoutCause));
345 assertSame(withoutCause, ExceptionUtils.getCause(nested));
346 assertSame(nested, ExceptionUtils.getCause(withCause));
347 assertSame(null, ExceptionUtils.getCause(jdkNoCause));
348 assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(cyclicCause));
349 assertSame(cyclicCause.getCause().getCause(), ExceptionUtils.getCause(cyclicCause.getCause()));
350 assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(cyclicCause.getCause().getCause()));
351 assertSame(withoutCause, ExceptionUtils.getCause(notVisibleException));
352 }
353
354 @SuppressWarnings("deprecation")
355 @Test
356 void testGetCause_ThrowableArray() {
357 assertSame(null, ExceptionUtils.getCause(null, null));
358 assertSame(null, ExceptionUtils.getCause(null, new String[0]));
359
360
361 assertSame(nested, ExceptionUtils.getCause(withCause, null));
362 assertSame(null, ExceptionUtils.getCause(withCause, new String[0]));
363 assertSame(null, ExceptionUtils.getCause(withCause, new String[]{null}));
364 assertSame(nested, ExceptionUtils.getCause(withCause, new String[]{"getCause"}));
365
366
367 assertSame(null, ExceptionUtils.getCause(withoutCause, null));
368 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[0]));
369 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{null}));
370 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{"getCause"}));
371 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[]{"getTargetException"}));
372 }
373
374 @Test
375 void testGetRootCause_Throwable() {
376 assertSame(null, ExceptionUtils.getRootCause(null));
377 assertSame(withoutCause, ExceptionUtils.getRootCause(withoutCause));
378 assertSame(withoutCause, ExceptionUtils.getRootCause(nested));
379 assertSame(withoutCause, ExceptionUtils.getRootCause(withCause));
380 assertSame(jdkNoCause, ExceptionUtils.getRootCause(jdkNoCause));
381 assertSame(cyclicCause.getCause().getCause(), ExceptionUtils.getRootCause(cyclicCause));
382 }
383
384 @Test
385 void testGetRootCauseStackTrace_Throwable() {
386 assertEquals(0, ExceptionUtils.getRootCauseStackTrace(null).length);
387
388 final Throwable cause = createExceptionWithCause();
389 String[] stackTrace = ExceptionUtils.getRootCauseStackTrace(cause);
390 boolean match = false;
391 for (final String element : stackTrace) {
392 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
393 match = true;
394 break;
395 }
396 }
397 assertTrue(match);
398
399 stackTrace = ExceptionUtils.getRootCauseStackTrace(withoutCause);
400 match = false;
401 for (final String element : stackTrace) {
402 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
403 match = true;
404 break;
405 }
406 }
407 assertFalse(match);
408 }
409
410 @Test
411 void testGetRootCauseStackTraceList_Throwable() {
412 assertEquals(0, ExceptionUtils.getRootCauseStackTraceList(null).size());
413
414 final Throwable cause = createExceptionWithCause();
415 List<String> stackTrace = ExceptionUtils.getRootCauseStackTraceList(cause);
416 boolean match = false;
417 for (final String element : stackTrace) {
418 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
419 match = true;
420 break;
421 }
422 }
423 assertTrue(match);
424
425 stackTrace = ExceptionUtils.getRootCauseStackTraceList(withoutCause);
426 match = false;
427 for (final String element : stackTrace) {
428 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
429 match = true;
430 break;
431 }
432 }
433 assertFalse(match);
434 }
435
436
437
438
439
440
441 @Test
442 void testGetRootCauseStackTraceMessageLinesNotMistakenForFrames() {
443 final Throwable t = new IllegalArgumentException(
444 "denied" + System.lineSeparator() + " attack detected" + System.lineSeparator() + "at your request, more text");
445 final String[] stackTrace = ExceptionUtils.getRootCauseStackTrace(t);
446
447 boolean sawRealFrame = false;
448 for (int i = 1; i < stackTrace.length; i++) {
449 final String element = stackTrace[i];
450 if (element.contains("attack detected") || element.contains("at your request")) {
451 fail("message text classified as a stack frame: " + element);
452 }
453 if (element.contains(getClass().getSimpleName())) {
454 sawRealFrame = true;
455 }
456 }
457
458 assertTrue(sawRealFrame, "real frames were suppressed");
459 }
460
461
462
463
464
465
466
467 @Test
468 void testGetStackFrameListAcceptsAllRealFrameShapes() {
469 final String[] frames = {
470 "\tat com.example.Foo.bar(Foo.java:42)",
471 "\tat app//com.foo.Main.main(Main.java:10)", // class loader prefix
472 "\tat com.foo.mod@1.0.3/com.foo.Helper.help(Helper.java:7)",
473 "\tat java.base/java.lang.Thread.run(Thread.java:833)",
474 "\tat com.foo.Main$$Lambda$17/0x0000000800c02a48.run(Unknown Source)",
475 "\tat com.example.Foo.<init>(Foo.java:5)",
476 "\tat java.base/java.lang.Object.wait(Native Method)"
477 };
478 final StringBuilder text = new StringBuilder("java.lang.RuntimeException: boom").append(System.lineSeparator());
479 for (final String frame : frames) {
480 text.append(frame).append(System.lineSeparator());
481 }
482 final Throwable fixed = new RuntimeException("boom") {
483 private static final long serialVersionUID = 1L;
484
485 @Override
486 public void printStackTrace(final PrintWriter writer) {
487 writer.print(text);
488 }
489 };
490 final List<String> list = ExceptionUtils.getStackFrameList(fixed);
491 assertEquals(Arrays.asList(frames), list, "a legitimate frame shape was rejected (and frames below it dropped)");
492 }
493
494
495
496
497
498 @Test
499 void testGetStackFrameListRejectsForgedMessageLines() {
500 final String[] forged = {
501 " attack detected",
502 "at your request, more text",
503 "\tat your request, more text",
504 "\tat forged frame entry(Evil.java:1)",
505 "\tat (Evil.java:1)"
506 };
507 final StringBuilder text = new StringBuilder("java.lang.RuntimeException: boom").append(System.lineSeparator());
508 for (final String line : forged) {
509 text.append(line).append(System.lineSeparator());
510 }
511 text.append("\tat com.example.Foo.bar(Foo.java:42)").append(System.lineSeparator());
512 final Throwable fixed = new RuntimeException("boom") {
513 private static final long serialVersionUID = 1L;
514
515 @Override
516 public void printStackTrace(final PrintWriter writer) {
517 writer.print(text);
518 }
519 };
520 final List<String> list = ExceptionUtils.getStackFrameList(fixed);
521 assertEquals(Arrays.asList("\tat com.example.Foo.bar(Foo.java:42)"), list,
522 "forged message text was classified as a stack frame");
523 }
524
525 @Test
526
527 void testgetStackFramesHappyPath() {
528 final String[] actual = ExceptionUtils.getStackFrames(new Throwable() {
529 private static final long serialVersionUID = 1L;
530
531
532 @Override
533 public void printStackTrace(final PrintWriter s) {
534 s.write("org.apache.commons.lang3.exception.ExceptionUtilsTest$1\n" +
535 "\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)\n" +
536 "\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" +
537 "\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)\n" +
538 "\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)\n");
539 }
540 });
541
542 assertArrayEquals(new String[]{
543 "org.apache.commons.lang3.exception.ExceptionUtilsTest$1",
544 "\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)",
545 "\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
546 "\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)",
547 "\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)"
548 }, actual);
549 }
550
551 @Test
552
553 void testgetStackFramesNullArg() {
554 final String[] actual = ExceptionUtils.getStackFrames((Throwable) null);
555 assertEquals(0, actual.length);
556 }
557
558 @Test
559 void testGetThrowableCount_Throwable() {
560 assertEquals(0, ExceptionUtils.getThrowableCount(null));
561 assertEquals(1, ExceptionUtils.getThrowableCount(withoutCause));
562 assertEquals(2, ExceptionUtils.getThrowableCount(nested));
563 assertEquals(3, ExceptionUtils.getThrowableCount(withCause));
564 assertEquals(1, ExceptionUtils.getThrowableCount(jdkNoCause));
565 assertEquals(3, ExceptionUtils.getThrowableCount(cyclicCause));
566 }
567
568 @Test
569 void testGetThrowableList_Throwable_jdkNoCause() {
570 final List<?> throwables = ExceptionUtils.getThrowableList(jdkNoCause);
571 assertEquals(1, throwables.size());
572 assertSame(jdkNoCause, throwables.get(0));
573 }
574
575 @Test
576 void testGetThrowableList_Throwable_nested() {
577 final List<?> throwables = ExceptionUtils.getThrowableList(nested);
578 assertEquals(2, throwables.size());
579 assertSame(nested, throwables.get(0));
580 assertSame(withoutCause, throwables.get(1));
581 }
582
583 @Test
584 void testGetThrowableList_Throwable_null() {
585 final List<?> throwables = ExceptionUtils.getThrowableList(null);
586 assertEquals(0, throwables.size());
587 }
588
589 @Test
590 void testGetThrowableList_Throwable_recursiveCause() {
591 final List<?> throwables = ExceptionUtils.getThrowableList(cyclicCause);
592 assertEquals(3, throwables.size());
593 assertSame(cyclicCause, throwables.get(0));
594 assertSame(cyclicCause.getCause(), throwables.get(1));
595 assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
596 }
597
598 @Test
599 void testGetThrowableList_Throwable_withCause() {
600 final List<?> throwables = ExceptionUtils.getThrowableList(withCause);
601 assertEquals(3, throwables.size());
602 assertSame(withCause, throwables.get(0));
603 assertSame(nested, throwables.get(1));
604 assertSame(withoutCause, throwables.get(2));
605 }
606
607 @Test
608 void testGetThrowableList_Throwable_withoutCause() {
609 final List<?> throwables = ExceptionUtils.getThrowableList(withoutCause);
610 assertEquals(1, throwables.size());
611 assertSame(withoutCause, throwables.get(0));
612 }
613
614 @Test
615 void testGetThrowableListDeepChain() {
616 final CountingException[] chain = new CountingException[10_000];
617 for (int i = chain.length - 1; i >= 0; i--) {
618 chain[i] = new CountingException(i + 1 < chain.length ? chain[i + 1] : null);
619 }
620 final List<Throwable> throwables = ExceptionUtils.getThrowableList(chain[0]);
621 assertEquals(chain.length, throwables.size());
622 for (int i = 0; i < chain.length; i++) {
623 assertSame(chain[i], throwables.get(i));
624 assertEquals(1, chain[i].causeCalls);
625 }
626 assertEquals(chain.length, ExceptionUtils.getThrowableCount(chain[0]));
627 assertSame(chain[chain.length - 1], ExceptionUtils.getRootCause(chain[0]));
628 final Throwable[] array = ExceptionUtils.getThrowables(chain[0]);
629 final Throwable[] stream = ExceptionUtils.stream(chain[0]).toArray(Throwable[]::new);
630 assertEquals(chain.length, array.length);
631 assertEquals(chain.length, stream.length);
632 for (int i = 0; i < chain.length; i++) {
633 assertSame(chain[i], array[i]);
634 assertSame(chain[i], stream[i]);
635 }
636 }
637
638 @Test
639 void testGetThrowableListEqualExceptions() {
640 final EqualException first = new EqualException();
641 final EqualException second = new EqualException();
642 final EqualException third = new EqualException();
643 first.initCause(second);
644 second.initCause(third);
645 final List<Throwable> throwables = ExceptionUtils.getThrowableList(first);
646 assertEquals(3, throwables.size());
647 assertSame(first, throwables.get(0));
648 assertSame(second, throwables.get(1));
649 assertSame(third, throwables.get(2));
650 third.initCause(second);
651 final List<Throwable> cyclic = ExceptionUtils.getThrowableList(first);
652 assertEquals(3, cyclic.size());
653 assertSame(first, cyclic.get(0));
654 assertSame(second, cyclic.get(1));
655 assertSame(third, cyclic.get(2));
656 }
657
658 @Test
659 void testGetThrowableListSelfCause() {
660 final ExceptionWithCause exception = new ExceptionWithCause(null);
661 exception.setCause(exception);
662 final List<Throwable> throwables = ExceptionUtils.getThrowableList(exception);
663 assertEquals(1, throwables.size());
664 assertSame(exception, throwables.get(0));
665 }
666
667 @Test
668 void testGetThrowables_Throwable_jdkNoCause() {
669 final Throwable[] throwables = ExceptionUtils.getThrowables(jdkNoCause);
670 assertEquals(1, throwables.length);
671 assertSame(jdkNoCause, throwables[0]);
672 }
673
674 @Test
675 void testGetThrowables_Throwable_nested() {
676 final Throwable[] throwables = ExceptionUtils.getThrowables(nested);
677 assertEquals(2, throwables.length);
678 assertSame(nested, throwables[0]);
679 assertSame(withoutCause, throwables[1]);
680 }
681
682 @Test
683 void testGetThrowables_Throwable_null() {
684 assertEquals(0, ExceptionUtils.getThrowables(null).length);
685 }
686
687 @Test
688 void testGetThrowables_Throwable_recursiveCause() {
689 final Throwable[] throwables = ExceptionUtils.getThrowables(cyclicCause);
690 assertEquals(3, throwables.length);
691 assertSame(cyclicCause, throwables[0]);
692 assertSame(cyclicCause.getCause(), throwables[1]);
693 assertSame(cyclicCause.getCause().getCause(), throwables[2]);
694 }
695
696 @Test
697 void testGetThrowables_Throwable_withCause() {
698 final Throwable[] throwables = ExceptionUtils.getThrowables(withCause);
699 assertEquals(3, throwables.length);
700 assertSame(withCause, throwables[0]);
701 assertSame(nested, throwables[1]);
702 assertSame(withoutCause, throwables[2]);
703 }
704
705 @Test
706 void testGetThrowables_Throwable_withoutCause() {
707 final Throwable[] throwables = ExceptionUtils.getThrowables(withoutCause);
708 assertEquals(1, throwables.length);
709 assertSame(withoutCause, throwables[0]);
710 }
711
712 @Test
713 void testIndexOf_ThrowableClass() {
714 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null));
715 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class));
716
717 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
718 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class));
719 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class));
720 assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class));
721
722 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null));
723 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class));
724 assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class));
725 assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class));
726
727 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
728 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class));
729 assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class));
730 assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class));
731
732 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class));
733 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class));
734 }
735
736 @Test
737 void testIndexOf_ThrowableClassInt() {
738 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null, 0));
739 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class, 0));
740
741 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
742 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class, 0));
743 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class, 0));
744 assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class, 0));
745
746 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null, 0));
747 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class, 0));
748 assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class, 0));
749 assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class, 0));
750
751 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
752 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
753 assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class, 0));
754 assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class, 0));
755
756 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, -1));
757 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
758 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 1));
759 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 9));
760
761 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class, 0));
762 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class, 0));
763 }
764
765 @Test
766 void testIndexOfType_ThrowableClass() {
767 assertEquals(-1, ExceptionUtils.indexOfType(null, null));
768 assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class));
769
770 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
771 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class));
772 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class));
773 assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class));
774
775 assertEquals(-1, ExceptionUtils.indexOfType(nested, null));
776 assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class));
777 assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class));
778 assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class));
779
780 assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
781 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class));
782 assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class));
783 assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class));
784
785 assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class));
786 assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class));
787 }
788
789 @Test
790 void testIndexOfType_ThrowableClassInt() {
791 assertEquals(-1, ExceptionUtils.indexOfType(null, null, 0));
792 assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class, 0));
793
794 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
795 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class, 0));
796 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class, 0));
797 assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class, 0));
798
799 assertEquals(-1, ExceptionUtils.indexOfType(nested, null, 0));
800 assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class, 0));
801 assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class, 0));
802 assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class, 0));
803
804 assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
805 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
806 assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class, 0));
807 assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class, 0));
808
809 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, -1));
810 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
811 assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 1));
812 assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 9));
813
814 assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class, 0));
815 assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class, 0));
816 }
817
818 @Test
819 void testIsChecked_checked() {
820 assertTrue(ExceptionUtils.isChecked(new IOException()));
821 }
822
823 @Test
824 void testIsChecked_error() {
825 assertFalse(ExceptionUtils.isChecked(new StackOverflowError()));
826 }
827
828 @Test
829 void testIsChecked_null() {
830 assertFalse(ExceptionUtils.isChecked(null));
831 }
832
833 @Test
834 void testIsChecked_unchecked() {
835 assertFalse(ExceptionUtils.isChecked(new IllegalArgumentException()));
836 }
837
838 @Test
839 void testIsCheckedCustomThrowable() {
840 assertTrue(ExceptionUtils.isChecked(new TestThrowable()));
841 }
842
843 @Test
844 void testIsUnchecked_checked() {
845 assertFalse(ExceptionUtils.isUnchecked(new IOException()));
846 }
847
848 @Test
849 void testIsUnchecked_error() {
850 assertTrue(ExceptionUtils.isUnchecked(new StackOverflowError()));
851 }
852
853 @Test
854 void testIsUnchecked_null() {
855 assertFalse(ExceptionUtils.isUnchecked(null));
856 }
857
858 @Test
859 void testIsUnchecked_unchecked() {
860 assertTrue(ExceptionUtils.isUnchecked(new IllegalArgumentException()));
861 }
862
863 @Test
864 void testIsUnCheckedCustomThrowable() {
865 assertFalse(ExceptionUtils.isUnchecked(new TestThrowable()));
866 }
867
868 @Test
869 void testPrintRootCauseStackTrace_Throwable() {
870 ExceptionUtils.printRootCauseStackTrace(null);
871
872
873 }
874
875 @Test
876 void testPrintRootCauseStackTrace_ThrowableStream() {
877 ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
878 ExceptionUtils.printRootCauseStackTrace(null, (PrintStream) null);
879 ExceptionUtils.printRootCauseStackTrace(null, new PrintStream(out));
880 assertEquals(0, out.toString().length());
881 assertNullPointerException(() -> ExceptionUtils.printRootCauseStackTrace(withCause, (PrintStream) null));
882 out = new ByteArrayOutputStream(1024);
883 final Throwable cause = createExceptionWithCause();
884 ExceptionUtils.printRootCauseStackTrace(cause, new PrintStream(out));
885 String stackTrace = out.toString();
886 assertTrue(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
887 out = new ByteArrayOutputStream(1024);
888 ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintStream(out));
889 stackTrace = out.toString();
890 assertFalse(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
891 }
892
893 @Test
894 void testPrintRootCauseStackTrace_ThrowableWriter() {
895 StringWriter writer = new StringWriter(1024);
896 ExceptionUtils.printRootCauseStackTrace(null, (PrintWriter) null);
897 ExceptionUtils.printRootCauseStackTrace(null, new PrintWriter(writer));
898 assertEquals(0, writer.getBuffer().length());
899 assertNullPointerException(() -> ExceptionUtils.printRootCauseStackTrace(withCause, (PrintWriter) null));
900 writer = new StringWriter(1024);
901 final Throwable cause = createExceptionWithCause();
902 ExceptionUtils.printRootCauseStackTrace(cause, new PrintWriter(writer));
903 String stackTrace = writer.toString();
904 assertTrue(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
905 writer = new StringWriter(1024);
906 ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintWriter(writer));
907 stackTrace = writer.toString();
908 assertFalse(stackTrace.contains(ExceptionUtils.WRAPPED_MARKER));
909 }
910
911 @Test
912 void testRemoveCommonFrames_ListList() {
913 assertNullPointerException(() -> ExceptionUtils.removeCommonFrames(null, null));
914 }
915
916 @Test
917 void testRethrow() {
918 final Exception expected = new InterruptedException();
919
920 assertThrows(expected.getClass(), () -> {
921 @SuppressWarnings("unused")
922 final Object retVal = ExceptionUtils.rethrow(expected);
923 });
924
925 assertThrows(expected.getClass(), () -> {
926 @SuppressWarnings("unused")
927 final String retVal = ExceptionUtils.rethrow(expected);
928 });
929
930 assertThrows(expected.getClass(), () -> {
931 @SuppressWarnings("unused")
932 final int retVal = ExceptionUtils.rethrow(expected);
933 });
934
935 assertSame(expected, assertThrows(expected.getClass(), () -> ExceptionUtils.rethrow(expected)));
936 assertNotSame(expected, assertThrows(expected.getClass(), () -> ExceptionUtils.rethrow(new InterruptedException())));
937 }
938
939 @Test
940 void testStream_jdkNoCause() {
941 assertEquals(1, ExceptionUtils.stream(jdkNoCause).count());
942 assertSame(jdkNoCause, ExceptionUtils.stream(jdkNoCause).toArray()[0]);
943 }
944
945 @Test
946 void testStream_nested() {
947 assertEquals(2, ExceptionUtils.stream(nested).count());
948 final Object[] array = ExceptionUtils.stream(nested).toArray();
949 assertSame(nested, array[0]);
950 assertSame(withoutCause, array[1]);
951 }
952
953 @Test
954 void testStream_null() {
955 assertEquals(0, ExceptionUtils.stream(null).count());
956 }
957
958 @Test
959 void testStream_recursiveCause() {
960 final List<?> throwables = ExceptionUtils.stream(cyclicCause).collect(Collectors.toList());
961 assertEquals(3, throwables.size());
962 assertSame(cyclicCause, throwables.get(0));
963 assertSame(cyclicCause.getCause(), throwables.get(1));
964 assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
965 }
966
967 @Test
968 void testStream_withCause() {
969 final List<?> throwables = ExceptionUtils.stream(withCause).collect(Collectors.toList());
970 assertEquals(3, throwables.size());
971 assertSame(withCause, throwables.get(0));
972 assertSame(nested, throwables.get(1));
973 assertSame(withoutCause, throwables.get(2));
974 }
975
976 @Test
977 void testStream_withoutCause() {
978 final List<?> throwables = ExceptionUtils.stream(withoutCause).collect(Collectors.toList());
979 assertEquals(1, throwables.size());
980 assertSame(withoutCause, throwables.get(0));
981 }
982
983 @Test
984 void testThrowableOf_ThrowableClass() {
985 assertNull(ExceptionUtils.throwableOfThrowable(null, null));
986 assertNull(ExceptionUtils.throwableOfThrowable(null, NestableException.class));
987
988 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, null));
989 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class));
990 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class));
991 assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class));
992
993 assertNull(ExceptionUtils.throwableOfThrowable(nested, null));
994 assertNull(ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class));
995 assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class));
996 assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class));
997
998 assertNull(ExceptionUtils.throwableOfThrowable(withCause, null));
999 assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class));
1000 assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class));
1001 assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class));
1002
1003 assertNull(ExceptionUtils.throwableOfThrowable(withCause, Exception.class));
1004 assertNull(ExceptionUtils.throwableOfThrowable(withCause, Throwable.class));
1005 }
1006
1007 @Test
1008 void testThrowableOf_ThrowableClassInt() {
1009 assertNull(ExceptionUtils.throwableOfThrowable(null, null, 0));
1010 assertNull(ExceptionUtils.throwableOfThrowable(null, NestableException.class, 0));
1011
1012 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, null));
1013 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class, 0));
1014 assertNull(ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class, 0));
1015 assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class, 0));
1016
1017 assertNull(ExceptionUtils.throwableOfThrowable(nested, null, 0));
1018 assertNull(ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class, 0));
1019 assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class, 0));
1020 assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class, 0));
1021
1022 assertNull(ExceptionUtils.throwableOfThrowable(withCause, null));
1023 assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0));
1024 assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class, 0));
1025 assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class, 0));
1026
1027 assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, -1));
1028 assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0));
1029 assertNull(ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 1));
1030 assertNull(ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 9));
1031
1032 assertNull(ExceptionUtils.throwableOfThrowable(withCause, Exception.class, 0));
1033 assertNull(ExceptionUtils.throwableOfThrowable(withCause, Throwable.class, 0));
1034 }
1035
1036 @Test
1037 void testThrowableOfType_ThrowableClass() {
1038 assertNull(ExceptionUtils.throwableOfType(null, null));
1039 assertNull(ExceptionUtils.throwableOfType(null, NestableException.class));
1040
1041 assertNull(ExceptionUtils.throwableOfType(withoutCause, null));
1042 assertNull(ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class));
1043 assertNull(ExceptionUtils.throwableOfType(withoutCause, NestableException.class));
1044 assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class));
1045
1046 assertNull(ExceptionUtils.throwableOfType(nested, null));
1047 assertNull(ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class));
1048 assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class));
1049 assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class));
1050
1051 assertNull(ExceptionUtils.throwableOfType(withCause, null));
1052 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class));
1053 assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class));
1054 assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class));
1055
1056 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class));
1057 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class));
1058 }
1059
1060 @Test
1061 void testThrowableOfType_ThrowableClassInt() {
1062 assertNull(ExceptionUtils.throwableOfType(null, null, 0));
1063 assertNull(ExceptionUtils.throwableOfType(null, NestableException.class, 0));
1064
1065 assertNull(ExceptionUtils.throwableOfType(withoutCause, null));
1066 assertNull(ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class, 0));
1067 assertNull(ExceptionUtils.throwableOfType(withoutCause, NestableException.class, 0));
1068 assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class, 0));
1069
1070 assertNull(ExceptionUtils.throwableOfType(nested, null, 0));
1071 assertNull(ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class, 0));
1072 assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class, 0));
1073 assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class, 0));
1074
1075 assertNull(ExceptionUtils.throwableOfType(withCause, null));
1076 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0));
1077 assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class, 0));
1078 assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class, 0));
1079
1080 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, -1));
1081 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0));
1082 assertNull(ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 1));
1083 assertNull(ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 9));
1084
1085 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class, 0));
1086 assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class, 0));
1087 }
1088
1089 @Test
1090 void testWrapAndUnwrapCheckedException() {
1091 final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new IOException()));
1092 assertTrue(ExceptionUtils.hasCause(t, IOException.class));
1093 }
1094
1095 @Test
1096 void testWrapAndUnwrapError() {
1097 final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new OutOfMemoryError()));
1098 assertTrue(ExceptionUtils.hasCause(t, Error.class));
1099 }
1100
1101 @Test
1102 void testWrapAndUnwrapRuntimeException() {
1103 final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new IllegalArgumentException()));
1104 assertTrue(ExceptionUtils.hasCause(t, RuntimeException.class));
1105 }
1106
1107 @Test
1108 void testWrapAndUnwrapThrowable() {
1109 final Throwable t = assertThrows(Throwable.class, () -> ExceptionUtils.wrapAndThrow(new TestThrowable()));
1110 assertTrue(ExceptionUtils.hasCause(t, TestThrowable.class));
1111 }
1112 }