• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
20 import static com.google.common.base.Throwables.getStackTraceAsString;
21 import static com.google.common.base.Throwables.lazyStackTrace;
22 import static com.google.common.base.Throwables.lazyStackTraceIsLazy;
23 import static com.google.common.base.Throwables.throwIfInstanceOf;
24 import static com.google.common.base.Throwables.throwIfUnchecked;
25 import static com.google.common.truth.Truth.assertThat;
26 import static java.util.Arrays.asList;
27 import static java.util.regex.Pattern.quote;
28 import static org.junit.Assert.assertThrows;
29 
30 import com.google.common.annotations.GwtCompatible;
31 import com.google.common.annotations.GwtIncompatible;
32 import com.google.common.annotations.J2ktIncompatible;
33 import com.google.common.collect.Iterables;
34 import com.google.common.primitives.Ints;
35 import com.google.common.testing.NullPointerTester;
36 import java.util.List;
37 import junit.framework.TestCase;
38 
39 /**
40  * Unit test for {@link Throwables}.
41  *
42  * @author Kevin Bourrillion
43  */
44 @GwtCompatible(emulated = true)
45 public class ThrowablesTest extends TestCase {
testThrowIfUnchecked_Unchecked()46   public void testThrowIfUnchecked_Unchecked() {
47     try {
48       throwIfUnchecked(new SomeUncheckedException());
49       fail();
50     } catch (SomeUncheckedException expected) {
51     }
52   }
53 
testThrowIfUnchecked_Error()54   public void testThrowIfUnchecked_Error() {
55     try {
56       throwIfUnchecked(new SomeError());
57       fail();
58     } catch (SomeError expected) {
59     }
60   }
61 
62   @SuppressWarnings("ThrowIfUncheckedKnownChecked")
testThrowIfUnchecked_Checked()63   public void testThrowIfUnchecked_Checked() {
64     throwIfUnchecked(new SomeCheckedException());
65   }
66 
67   @J2ktIncompatible
68   @GwtIncompatible // propagateIfPossible
testPropagateIfPossible_NoneDeclared_NoneThrown()69   public void testPropagateIfPossible_NoneDeclared_NoneThrown() {
70     Sample sample =
71         new Sample() {
72           @Override
73           public void noneDeclared() {
74             try {
75               methodThatDoesntThrowAnything();
76             } catch (Throwable t) {
77               Throwables.propagateIfPossible(t);
78               throw new SomeChainingException(t);
79             }
80           }
81         };
82 
83     // Expect no exception to be thrown
84     sample.noneDeclared();
85   }
86 
87   @J2ktIncompatible
88   @GwtIncompatible // propagateIfPossible
testPropagateIfPossible_NoneDeclared_UncheckedThrown()89   public void testPropagateIfPossible_NoneDeclared_UncheckedThrown() {
90     Sample sample =
91         new Sample() {
92           @Override
93           public void noneDeclared() {
94             try {
95               methodThatThrowsUnchecked();
96             } catch (Throwable t) {
97               Throwables.propagateIfPossible(t);
98               throw new SomeChainingException(t);
99             }
100           }
101         };
102 
103     // Expect the unchecked exception to propagate as-is
104     assertThrows(SomeUncheckedException.class, () -> sample.noneDeclared());
105   }
106 
107   @J2ktIncompatible
108   @GwtIncompatible // propagateIfPossible
testPropagateIfPossible_NoneDeclared_UndeclaredThrown()109   public void testPropagateIfPossible_NoneDeclared_UndeclaredThrown() {
110     Sample sample =
111         new Sample() {
112           @Override
113           public void noneDeclared() {
114             try {
115               methodThatThrowsUndeclaredChecked();
116             } catch (Throwable t) {
117               Throwables.propagateIfPossible(t);
118               throw new SomeChainingException(t);
119             }
120           }
121         };
122 
123     // Expect the undeclared exception to have been chained inside another
124     assertThrows(SomeChainingException.class, () -> sample.noneDeclared());
125   }
126 
127   @J2ktIncompatible
128   @GwtIncompatible // propagateIfPossible(Throwable, Class)
testPropagateIfPossible_OneDeclared_NoneThrown()129   public void testPropagateIfPossible_OneDeclared_NoneThrown() throws SomeCheckedException {
130     Sample sample =
131         new Sample() {
132           @Override
133           public void oneDeclared() throws SomeCheckedException {
134             try {
135               methodThatDoesntThrowAnything();
136             } catch (Throwable t) {
137               // yes, this block is never reached, but for purposes of illustration
138               // we're keeping it the same in each test
139               Throwables.propagateIfPossible(t, SomeCheckedException.class);
140               throw new SomeChainingException(t);
141             }
142           }
143         };
144 
145     // Expect no exception to be thrown
146     sample.oneDeclared();
147   }
148 
149   @J2ktIncompatible
150   @GwtIncompatible // propagateIfPossible(Throwable, Class)
testPropagateIfPossible_OneDeclared_UncheckedThrown()151   public void testPropagateIfPossible_OneDeclared_UncheckedThrown() throws SomeCheckedException {
152     Sample sample =
153         new Sample() {
154           @Override
155           public void oneDeclared() throws SomeCheckedException {
156             try {
157               methodThatThrowsUnchecked();
158             } catch (Throwable t) {
159               Throwables.propagateIfPossible(t, SomeCheckedException.class);
160               throw new SomeChainingException(t);
161             }
162           }
163         };
164 
165     // Expect the unchecked exception to propagate as-is
166     assertThrows(SomeUncheckedException.class, () -> sample.oneDeclared());
167   }
168 
169   @J2ktIncompatible
170   @GwtIncompatible // propagateIfPossible(Throwable, Class)
testPropagateIfPossible_OneDeclared_CheckedThrown()171   public void testPropagateIfPossible_OneDeclared_CheckedThrown() {
172     Sample sample =
173         new Sample() {
174           @Override
175           public void oneDeclared() throws SomeCheckedException {
176             try {
177               methodThatThrowsChecked();
178             } catch (Throwable t) {
179               Throwables.propagateIfPossible(t, SomeCheckedException.class);
180               throw new SomeChainingException(t);
181             }
182           }
183         };
184 
185     // Expect the checked exception to propagate as-is
186     assertThrows(SomeCheckedException.class, () -> sample.oneDeclared());
187   }
188 
189   @J2ktIncompatible
190   @GwtIncompatible // propagateIfPossible(Throwable, Class)
testPropagateIfPossible_OneDeclared_UndeclaredThrown()191   public void testPropagateIfPossible_OneDeclared_UndeclaredThrown() throws SomeCheckedException {
192     Sample sample =
193         new Sample() {
194           @Override
195           public void oneDeclared() throws SomeCheckedException {
196             try {
197               methodThatThrowsUndeclaredChecked();
198             } catch (Throwable t) {
199               Throwables.propagateIfPossible(t, SomeCheckedException.class);
200               throw new SomeChainingException(t);
201             }
202           }
203         };
204 
205     // Expect the undeclared exception to have been chained inside another
206     assertThrows(SomeChainingException.class, () -> sample.oneDeclared());
207   }
208 
209   @J2ktIncompatible
210   @GwtIncompatible // propagateIfPossible(Throwable, Class, Class)
testPropagateIfPossible_TwoDeclared_NoneThrown()211   public void testPropagateIfPossible_TwoDeclared_NoneThrown()
212       throws SomeCheckedException, SomeOtherCheckedException {
213     Sample sample =
214         new Sample() {
215           @Override
216           public void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {
217             try {
218               methodThatDoesntThrowAnything();
219             } catch (Throwable t) {
220               Throwables.propagateIfPossible(
221                   t, SomeCheckedException.class, SomeOtherCheckedException.class);
222               throw new SomeChainingException(t);
223             }
224           }
225         };
226 
227     // Expect no exception to be thrown
228     sample.twoDeclared();
229   }
230 
231   @J2ktIncompatible
232   @GwtIncompatible // propagateIfPossible(Throwable, Class, Class)
testPropagateIfPossible_TwoDeclared_UncheckedThrown()233   public void testPropagateIfPossible_TwoDeclared_UncheckedThrown()
234       throws SomeCheckedException, SomeOtherCheckedException {
235     Sample sample =
236         new Sample() {
237           @Override
238           public void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {
239             try {
240               methodThatThrowsUnchecked();
241             } catch (Throwable t) {
242               Throwables.propagateIfPossible(
243                   t, SomeCheckedException.class, SomeOtherCheckedException.class);
244               throw new SomeChainingException(t);
245             }
246           }
247         };
248 
249     // Expect the unchecked exception to propagate as-is
250     assertThrows(SomeUncheckedException.class, () -> sample.twoDeclared());
251   }
252 
253   @J2ktIncompatible
254   @GwtIncompatible // propagateIfPossible(Throwable, Class, Class)
testPropagateIfPossible_TwoDeclared_CheckedThrown()255   public void testPropagateIfPossible_TwoDeclared_CheckedThrown() throws SomeOtherCheckedException {
256     Sample sample =
257         new Sample() {
258           @Override
259           public void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {
260             try {
261               methodThatThrowsChecked();
262             } catch (Throwable t) {
263               Throwables.propagateIfPossible(
264                   t, SomeCheckedException.class, SomeOtherCheckedException.class);
265               throw new SomeChainingException(t);
266             }
267           }
268         };
269 
270     // Expect the checked exception to propagate as-is
271     assertThrows(SomeCheckedException.class, () -> sample.twoDeclared());
272   }
273 
274   @J2ktIncompatible
275   @GwtIncompatible // propagateIfPossible(Throwable, Class, Class)
testPropagateIfPossible_TwoDeclared_OtherCheckedThrown()276   public void testPropagateIfPossible_TwoDeclared_OtherCheckedThrown() throws SomeCheckedException {
277     Sample sample =
278         new Sample() {
279           @Override
280           public void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {
281             try {
282               methodThatThrowsOtherChecked();
283             } catch (Throwable t) {
284               Throwables.propagateIfPossible(
285                   t, SomeCheckedException.class, SomeOtherCheckedException.class);
286               throw new SomeChainingException(t);
287             }
288           }
289         };
290 
291     // Expect the checked exception to propagate as-is
292     assertThrows(SomeOtherCheckedException.class, () -> sample.twoDeclared());
293   }
294 
testThrowIfUnchecked_null()295   public void testThrowIfUnchecked_null() throws SomeCheckedException {
296     try {
297       throwIfUnchecked(null);
298       fail();
299     } catch (NullPointerException expected) {
300     }
301   }
302 
303   @J2ktIncompatible
304   @GwtIncompatible // propagateIfPossible
testPropageIfPossible_null()305   public void testPropageIfPossible_null() throws SomeCheckedException {
306     Throwables.propagateIfPossible(null);
307   }
308 
309   @J2ktIncompatible
310   @GwtIncompatible // propagateIfPossible(Throwable, Class)
testPropageIfPossible_OneDeclared_null()311   public void testPropageIfPossible_OneDeclared_null() throws SomeCheckedException {
312     Throwables.propagateIfPossible(null, SomeCheckedException.class);
313   }
314 
315   @J2ktIncompatible
316   @GwtIncompatible // propagateIfPossible(Throwable, Class, Class)
testPropageIfPossible_TwoDeclared_null()317   public void testPropageIfPossible_TwoDeclared_null() throws SomeCheckedException {
318     Throwables.propagateIfPossible(null, SomeCheckedException.class, SomeUncheckedException.class);
319   }
320 
321   @J2ktIncompatible
322   @GwtIncompatible // propagate
testPropagate_NoneDeclared_NoneThrown()323   public void testPropagate_NoneDeclared_NoneThrown() {
324     Sample sample =
325         new Sample() {
326           @Override
327           public void noneDeclared() {
328             try {
329               methodThatDoesntThrowAnything();
330             } catch (Throwable t) {
331               throw Throwables.propagate(t);
332             }
333           }
334         };
335 
336     // Expect no exception to be thrown
337     sample.noneDeclared();
338   }
339 
340   @J2ktIncompatible
341   @GwtIncompatible // propagate
testPropagate_NoneDeclared_UncheckedThrown()342   public void testPropagate_NoneDeclared_UncheckedThrown() {
343     Sample sample =
344         new Sample() {
345           @Override
346           public void noneDeclared() {
347             try {
348               methodThatThrowsUnchecked();
349             } catch (Throwable t) {
350               throw Throwables.propagate(t);
351             }
352           }
353         };
354 
355     // Expect the unchecked exception to propagate as-is
356     assertThrows(SomeUncheckedException.class, () -> sample.noneDeclared());
357   }
358 
359   @J2ktIncompatible
360   @GwtIncompatible // propagate
testPropagate_NoneDeclared_ErrorThrown()361   public void testPropagate_NoneDeclared_ErrorThrown() {
362     Sample sample =
363         new Sample() {
364           @Override
365           public void noneDeclared() {
366             try {
367               methodThatThrowsError();
368             } catch (Throwable t) {
369               throw Throwables.propagate(t);
370             }
371           }
372         };
373 
374     // Expect the error to propagate as-is
375     assertThrows(SomeError.class, () -> sample.noneDeclared());
376   }
377 
378   @J2ktIncompatible
379   @GwtIncompatible // propagate
testPropagate_NoneDeclared_CheckedThrown()380   public void testPropagate_NoneDeclared_CheckedThrown() {
381     Sample sample =
382         new Sample() {
383           @Override
384           public void noneDeclared() {
385             try {
386               methodThatThrowsChecked();
387             } catch (Throwable t) {
388               throw Throwables.propagate(t);
389             }
390           }
391         };
392 
393     // Expect the undeclared exception to have been chained inside another
394     RuntimeException expected = assertThrows(RuntimeException.class, () -> sample.noneDeclared());
395     assertThat(expected).hasCauseThat().isInstanceOf(SomeCheckedException.class);
396   }
397 
398   @J2ktIncompatible
399   @GwtIncompatible // throwIfInstanceOf
testThrowIfInstanceOf_Unchecked()400   public void testThrowIfInstanceOf_Unchecked() throws SomeCheckedException {
401     throwIfInstanceOf(new SomeUncheckedException(), SomeCheckedException.class);
402   }
403 
404   @J2ktIncompatible
405   @GwtIncompatible // throwIfInstanceOf
testThrowIfInstanceOf_CheckedDifferent()406   public void testThrowIfInstanceOf_CheckedDifferent() throws SomeCheckedException {
407     throwIfInstanceOf(new SomeOtherCheckedException(), SomeCheckedException.class);
408   }
409 
410   @J2ktIncompatible
411   @GwtIncompatible // throwIfInstanceOf
testThrowIfInstanceOf_CheckedSame()412   public void testThrowIfInstanceOf_CheckedSame() {
413     assertThrows(
414         SomeCheckedException.class,
415         () -> throwIfInstanceOf(new SomeCheckedException(), SomeCheckedException.class));
416   }
417 
418   @J2ktIncompatible
419   @GwtIncompatible // throwIfInstanceOf
testThrowIfInstanceOf_CheckedSubclass()420   public void testThrowIfInstanceOf_CheckedSubclass() {
421     assertThrows(
422         SomeCheckedException.class,
423         () -> throwIfInstanceOf(new SomeCheckedException() {}, SomeCheckedException.class));
424   }
425 
426   @J2ktIncompatible
427   @GwtIncompatible // throwIfInstanceOf
testPropagateIfInstanceOf_NoneThrown()428   public void testPropagateIfInstanceOf_NoneThrown() throws SomeCheckedException {
429     Sample sample =
430         new Sample() {
431           @Override
432           public void oneDeclared() throws SomeCheckedException {
433             try {
434               methodThatDoesntThrowAnything();
435             } catch (Throwable t) {
436               Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
437               throw Throwables.propagate(t);
438             }
439           }
440         };
441 
442     // Expect no exception to be thrown
443     sample.oneDeclared();
444   }
445 
446   @J2ktIncompatible
447   @GwtIncompatible // throwIfInstanceOf
testPropagateIfInstanceOf_DeclaredThrown()448   public void testPropagateIfInstanceOf_DeclaredThrown() {
449     Sample sample =
450         new Sample() {
451           @Override
452           public void oneDeclared() throws SomeCheckedException {
453             try {
454               methodThatThrowsChecked();
455             } catch (Throwable t) {
456               Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
457               throw Throwables.propagate(t);
458             }
459           }
460         };
461 
462     // Expect declared exception to be thrown as-is
463     assertThrows(SomeCheckedException.class, () -> sample.oneDeclared());
464   }
465 
466   @J2ktIncompatible
467   @GwtIncompatible // throwIfInstanceOf
testPropagateIfInstanceOf_UncheckedThrown()468   public void testPropagateIfInstanceOf_UncheckedThrown() throws SomeCheckedException {
469     Sample sample =
470         new Sample() {
471           @Override
472           public void oneDeclared() throws SomeCheckedException {
473             try {
474               methodThatThrowsUnchecked();
475             } catch (Throwable t) {
476               Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
477               throw Throwables.propagate(t);
478             }
479           }
480         };
481 
482     // Expect unchecked exception to be thrown as-is
483     assertThrows(SomeUncheckedException.class, () -> sample.oneDeclared());
484   }
485 
486   @J2ktIncompatible
487   @GwtIncompatible // throwIfInstanceOf
testPropagateIfInstanceOf_UndeclaredThrown()488   public void testPropagateIfInstanceOf_UndeclaredThrown() throws SomeCheckedException {
489     Sample sample =
490         new Sample() {
491           @Override
492           public void oneDeclared() throws SomeCheckedException {
493             try {
494               methodThatThrowsOtherChecked();
495             } catch (Throwable t) {
496               Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
497               throw Throwables.propagate(t);
498             }
499           }
500         };
501 
502     // Expect undeclared exception wrapped by RuntimeException to be thrown
503     RuntimeException expected = assertThrows(RuntimeException.class, () -> sample.oneDeclared());
504     assertThat(expected).hasCauseThat().isInstanceOf(SomeOtherCheckedException.class);
505   }
506 
507   @J2ktIncompatible
508   @GwtIncompatible // throwIfInstanceOf
testThrowIfInstanceOf_null()509   public void testThrowIfInstanceOf_null() throws SomeCheckedException {
510     assertThrows(
511         NullPointerException.class, () -> throwIfInstanceOf(null, SomeCheckedException.class));
512   }
513 
514   @J2ktIncompatible
515   @GwtIncompatible // throwIfInstanceOf
testPropageIfInstanceOf_null()516   public void testPropageIfInstanceOf_null() throws SomeCheckedException {
517     Throwables.propagateIfInstanceOf(null, SomeCheckedException.class);
518   }
519 
testGetRootCause_NoCause()520   public void testGetRootCause_NoCause() {
521     SomeCheckedException exception = new SomeCheckedException();
522     assertSame(exception, Throwables.getRootCause(exception));
523   }
524 
testGetRootCause_SingleWrapped()525   public void testGetRootCause_SingleWrapped() {
526     SomeCheckedException cause = new SomeCheckedException();
527     SomeChainingException exception = new SomeChainingException(cause);
528     assertSame(cause, Throwables.getRootCause(exception));
529   }
530 
testGetRootCause_DoubleWrapped()531   public void testGetRootCause_DoubleWrapped() {
532     SomeCheckedException cause = new SomeCheckedException();
533     SomeChainingException exception = new SomeChainingException(new SomeChainingException(cause));
534     assertSame(cause, Throwables.getRootCause(exception));
535   }
536 
testGetRootCause_Loop()537   public void testGetRootCause_Loop() {
538     Exception cause = new Exception();
539     Exception exception = new Exception(cause);
540     cause.initCause(exception);
541     try {
542       Throwables.getRootCause(cause);
543       fail("Should have throw IAE");
544     } catch (IllegalArgumentException expected) {
545       assertThat(expected).hasCauseThat().isSameInstanceAs(cause);
546     }
547   }
548 
549   private static class SomeError extends Error {}
550 
551   private static class SomeCheckedException extends Exception {}
552 
553   private static class SomeOtherCheckedException extends Exception {}
554 
555   private static class SomeUncheckedException extends RuntimeException {}
556 
557   private static class SomeUndeclaredCheckedException extends Exception {}
558 
559   private static class SomeChainingException extends RuntimeException {
SomeChainingException(Throwable cause)560     public SomeChainingException(Throwable cause) {
561       super(cause);
562     }
563   }
564 
565   static class Sample {
noneDeclared()566     void noneDeclared() {}
567 
oneDeclared()568     void oneDeclared() throws SomeCheckedException {}
569 
twoDeclared()570     void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {}
571   }
572 
methodThatDoesntThrowAnything()573   static void methodThatDoesntThrowAnything() {}
574 
methodThatThrowsError()575   static void methodThatThrowsError() {
576     throw new SomeError();
577   }
578 
methodThatThrowsUnchecked()579   static void methodThatThrowsUnchecked() {
580     throw new SomeUncheckedException();
581   }
582 
methodThatThrowsChecked()583   static void methodThatThrowsChecked() throws SomeCheckedException {
584     throw new SomeCheckedException();
585   }
586 
methodThatThrowsOtherChecked()587   static void methodThatThrowsOtherChecked() throws SomeOtherCheckedException {
588     throw new SomeOtherCheckedException();
589   }
590 
methodThatThrowsUndeclaredChecked()591   static void methodThatThrowsUndeclaredChecked() throws SomeUndeclaredCheckedException {
592     throw new SomeUndeclaredCheckedException();
593   }
594 
595   @J2ktIncompatible
596   @GwtIncompatible // getStackTraceAsString(Throwable)
testGetStackTraceAsString()597   public void testGetStackTraceAsString() {
598     class StackTraceException extends Exception {
599       StackTraceException(String message) {
600         super(message);
601       }
602     }
603 
604     StackTraceException e = new StackTraceException("my message");
605 
606     String firstLine = quote(e.getClass().getName() + ": " + e.getMessage());
607     String secondLine = "\\s*at " + ThrowablesTest.class.getName() + "\\..*";
608     String moreLines = "(?:.*" + System.lineSeparator() + "?)*";
609     String expected =
610         firstLine + System.lineSeparator() + secondLine + System.lineSeparator() + moreLines;
611     assertThat(getStackTraceAsString(e)).matches(expected);
612   }
613 
testGetCausalChain()614   public void testGetCausalChain() {
615     SomeUncheckedException sue = new SomeUncheckedException();
616     IllegalArgumentException iae = new IllegalArgumentException(sue);
617     RuntimeException re = new RuntimeException(iae);
618     IllegalStateException ex = new IllegalStateException(re);
619 
620     assertEquals(asList(ex, re, iae, sue), Throwables.getCausalChain(ex));
621     assertSame(sue, Iterables.getOnlyElement(Throwables.getCausalChain(sue)));
622 
623     List<Throwable> causes = Throwables.getCausalChain(ex);
624     try {
625       causes.add(new RuntimeException());
626       fail("List should be unmodifiable");
627     } catch (UnsupportedOperationException expected) {
628     }
629   }
630 
testGetCasualChainNull()631   public void testGetCasualChainNull() {
632     try {
633       Throwables.getCausalChain(null);
634       fail("Should have throw NPE");
635     } catch (NullPointerException expected) {
636     }
637   }
638 
testGetCasualChainLoop()639   public void testGetCasualChainLoop() {
640     Exception cause = new Exception();
641     Exception exception = new Exception(cause);
642     cause.initCause(exception);
643     try {
644       Throwables.getCausalChain(cause);
645       fail("Should have throw IAE");
646     } catch (IllegalArgumentException expected) {
647       assertThat(expected).hasCauseThat().isSameInstanceAs(cause);
648     }
649   }
650 
651   @J2ktIncompatible
652   @GwtIncompatible // Throwables.getCauseAs(Throwable, Class)
testGetCauseAs()653   public void testGetCauseAs() {
654     SomeCheckedException cause = new SomeCheckedException();
655     SomeChainingException thrown = new SomeChainingException(cause);
656 
657     assertThat(thrown).hasCauseThat().isSameInstanceAs(cause);
658     assertThat(Throwables.getCauseAs(thrown, SomeCheckedException.class)).isSameInstanceAs(cause);
659     assertThat(Throwables.getCauseAs(thrown, Exception.class)).isSameInstanceAs(cause);
660 
661     ClassCastException expected =
662         assertThrows(
663             ClassCastException.class,
664             () -> Throwables.getCauseAs(thrown, IllegalStateException.class));
665     assertThat(expected).hasCauseThat().isSameInstanceAs(thrown);
666   }
667 
668   @AndroidIncompatible // No getJavaLangAccess in Android (at least not in the version we use).
669   @J2ktIncompatible
670   @GwtIncompatible // lazyStackTraceIsLazy()
testLazyStackTraceWorksInProd()671   public void testLazyStackTraceWorksInProd() {
672     // TODO(b/64442212): Remove this guard once lazyStackTrace() works in Java 9+.
673     Integer javaVersion = Ints.tryParse(JAVA_SPECIFICATION_VERSION.value());
674     if (javaVersion != null && javaVersion >= 9) {
675       return;
676     }
677     // Obviously this isn't guaranteed in every environment, but it works well enough for now:
678     assertTrue(lazyStackTraceIsLazy());
679   }
680 
681   @J2ktIncompatible
682   @GwtIncompatible // lazyStackTrace(Throwable)
testLazyStackTrace()683   public void testLazyStackTrace() {
684     Exception e = new Exception();
685     StackTraceElement[] originalStackTrace = e.getStackTrace();
686 
687     assertThat(lazyStackTrace(e)).containsExactly((Object[]) originalStackTrace).inOrder();
688 
689     assertThrows(UnsupportedOperationException.class, () -> lazyStackTrace(e).set(0, null));
690 
691     // Now we test a property that holds only for the lazy implementation.
692 
693     if (!lazyStackTraceIsLazy()) {
694       return;
695     }
696 
697     e.setStackTrace(new StackTraceElement[0]);
698     assertThat(lazyStackTrace(e)).containsExactly((Object[]) originalStackTrace).inOrder();
699   }
700 
701   @J2ktIncompatible
702   @GwtIncompatible // lazyStackTrace
doTestLazyStackTraceFallback()703   private void doTestLazyStackTraceFallback() {
704     assertFalse(lazyStackTraceIsLazy());
705 
706     Exception e = new Exception();
707 
708     assertThat(lazyStackTrace(e)).containsExactly((Object[]) e.getStackTrace()).inOrder();
709 
710     try {
711       lazyStackTrace(e).set(0, null);
712       fail();
713     } catch (UnsupportedOperationException expected) {
714     }
715 
716     e.setStackTrace(new StackTraceElement[0]);
717     assertThat(lazyStackTrace(e)).isEmpty();
718   }
719 
720   @J2ktIncompatible
721   @GwtIncompatible // NullPointerTester
testNullPointers()722   public void testNullPointers() {
723     new NullPointerTester().testAllPublicStaticMethods(Throwables.class);
724   }
725 }
726