Home | History | Annotate | Download | only in base
      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.Throwables.getStackTraceAsString;
     20 import static java.util.Arrays.asList;
     21 import static java.util.regex.Pattern.quote;
     22 
     23 import com.google.common.collect.Iterables;
     24 import com.google.common.testing.NullPointerTester;
     25 
     26 import junit.framework.TestCase;
     27 
     28 import java.io.FileNotFoundException;
     29 import java.util.List;
     30 
     31 /**
     32  * Unit test for {@link Throwables}.
     33  *
     34  * @author Kevin Bourrillion
     35  */
     36 public class ThrowablesTest extends TestCase {
     37   public void testPropagateIfPossible_NoneDeclared_NoneThrown() {
     38     Sample sample = new Sample() {
     39       @Override public void noneDeclared() {
     40         try {
     41           methodThatDoesntThrowAnything();
     42         } catch (Throwable t) {
     43           Throwables.propagateIfPossible(t);
     44           throw new SomeChainingException(t);
     45         }
     46       }
     47     };
     48 
     49     // Expect no exception to be thrown
     50     sample.noneDeclared();
     51   }
     52 
     53   public void testPropagateIfPossible_NoneDeclared_UncheckedThrown() {
     54     Sample sample = new Sample() {
     55       @Override public void noneDeclared() {
     56         try {
     57           methodThatThrowsUnchecked();
     58         } catch (Throwable t) {
     59           Throwables.propagateIfPossible(t);
     60           throw new SomeChainingException(t);
     61         }
     62       }
     63     };
     64 
     65     // Expect the unchecked exception to propagate as-is
     66     try {
     67       sample.noneDeclared();
     68       fail();
     69     } catch (SomeUncheckedException expected) {
     70     }
     71   }
     72 
     73   public void testPropagateIfPossible_NoneDeclared_UndeclaredThrown() {
     74     Sample sample = new Sample() {
     75       @Override public void noneDeclared() {
     76         try {
     77           methodThatThrowsUndeclaredChecked();
     78         } catch (Throwable t) {
     79           Throwables.propagateIfPossible(t);
     80           throw new SomeChainingException(t);
     81         }
     82       }
     83     };
     84 
     85     // Expect the undeclared exception to have been chained inside another
     86     try {
     87       sample.noneDeclared();
     88       fail();
     89     } catch (SomeChainingException expected) {
     90     }
     91   }
     92 
     93   public void testPropagateIfPossible_OneDeclared_NoneThrown()
     94       throws SomeCheckedException {
     95     Sample sample = new Sample() {
     96       @Override public void oneDeclared() throws SomeCheckedException {
     97         try {
     98           methodThatDoesntThrowAnything();
     99         } catch (Throwable t) {
    100           // yes, this block is never reached, but for purposes of illustration
    101           // we're keeping it the same in each test
    102           Throwables.propagateIfPossible(t, SomeCheckedException.class);
    103           throw new SomeChainingException(t);
    104         }
    105       }
    106     };
    107 
    108     // Expect no exception to be thrown
    109     sample.oneDeclared();
    110   }
    111 
    112   public void testPropagateIfPossible_OneDeclared_UncheckedThrown()
    113       throws SomeCheckedException {
    114     Sample sample = new Sample() {
    115       @Override public void oneDeclared() throws SomeCheckedException {
    116         try {
    117           methodThatThrowsUnchecked();
    118         } catch (Throwable t) {
    119           Throwables.propagateIfPossible(t, SomeCheckedException.class);
    120           throw new SomeChainingException(t);
    121         }
    122       }
    123     };
    124 
    125     // Expect the unchecked exception to propagate as-is
    126     try {
    127       sample.oneDeclared();
    128       fail();
    129     } catch (SomeUncheckedException expected) {
    130     }
    131   }
    132 
    133   public void testPropagateIfPossible_OneDeclared_CheckedThrown() {
    134     Sample sample = new Sample() {
    135       @Override public void oneDeclared() throws SomeCheckedException {
    136         try {
    137           methodThatThrowsChecked();
    138         } catch (Throwable t) {
    139           Throwables.propagateIfPossible(t, SomeCheckedException.class);
    140           throw new SomeChainingException(t);
    141         }
    142       }
    143     };
    144 
    145     // Expect the checked exception to propagate as-is
    146     try {
    147       sample.oneDeclared();
    148       fail();
    149     } catch (SomeCheckedException expected) {
    150     }
    151   }
    152 
    153   public void testPropagateIfPossible_OneDeclared_UndeclaredThrown()
    154       throws SomeCheckedException {
    155     Sample sample = new Sample() {
    156       @Override public void oneDeclared() throws SomeCheckedException {
    157         try {
    158           methodThatThrowsUndeclaredChecked();
    159         } catch (Throwable t) {
    160           Throwables.propagateIfPossible(t, SomeCheckedException.class);
    161           throw new SomeChainingException(t);
    162         }
    163       }
    164     };
    165 
    166     // Expect the undeclared exception to have been chained inside another
    167     try {
    168       sample.oneDeclared();
    169       fail();
    170     } catch (SomeChainingException expected) {
    171     }
    172   }
    173 
    174   public void testPropagateIfPossible_TwoDeclared_NoneThrown()
    175       throws SomeCheckedException, SomeOtherCheckedException {
    176     Sample sample = new Sample() {
    177       @Override public void twoDeclared() throws SomeCheckedException,
    178           SomeOtherCheckedException {
    179         try {
    180           methodThatDoesntThrowAnything();
    181         } catch (Throwable t) {
    182           Throwables.propagateIfPossible(t, SomeCheckedException.class,
    183               SomeOtherCheckedException.class);
    184           throw new SomeChainingException(t);
    185         }
    186       }
    187     };
    188 
    189     // Expect no exception to be thrown
    190     sample.twoDeclared();
    191   }
    192 
    193   public void testPropagateIfPossible_TwoDeclared_UncheckedThrown()
    194       throws SomeCheckedException, SomeOtherCheckedException {
    195     Sample sample = new Sample() {
    196       @Override public void twoDeclared() throws SomeCheckedException,
    197           SomeOtherCheckedException {
    198         try {
    199           methodThatThrowsUnchecked();
    200         } catch (Throwable t) {
    201           Throwables.propagateIfPossible(t, SomeCheckedException.class,
    202               SomeOtherCheckedException.class);
    203           throw new SomeChainingException(t);
    204         }
    205       }
    206     };
    207 
    208     // Expect the unchecked exception to propagate as-is
    209     try {
    210       sample.twoDeclared();
    211       fail();
    212     } catch (SomeUncheckedException expected) {
    213     }
    214   }
    215 
    216   public void testPropagateIfPossible_TwoDeclared_CheckedThrown()
    217       throws SomeOtherCheckedException {
    218     Sample sample = new Sample() {
    219       @Override public void twoDeclared() throws SomeCheckedException,
    220           SomeOtherCheckedException {
    221         try {
    222           methodThatThrowsChecked();
    223         } catch (Throwable t) {
    224           Throwables.propagateIfPossible(t, SomeCheckedException.class,
    225               SomeOtherCheckedException.class);
    226           throw new SomeChainingException(t);
    227         }
    228       }
    229     };
    230 
    231     // Expect the checked exception to propagate as-is
    232     try {
    233       sample.twoDeclared();
    234       fail();
    235     } catch (SomeCheckedException expected) {
    236     }
    237   }
    238 
    239   public void testPropagateIfPossible_TwoDeclared_OtherCheckedThrown()
    240       throws SomeCheckedException {
    241     Sample sample = new Sample() {
    242       @Override public void twoDeclared() throws SomeCheckedException,
    243           SomeOtherCheckedException {
    244         try {
    245           methodThatThrowsOtherChecked();
    246         } catch (Throwable t) {
    247           Throwables.propagateIfPossible(t, SomeCheckedException.class,
    248               SomeOtherCheckedException.class);
    249           throw new SomeChainingException(t);
    250         }
    251       }
    252     };
    253 
    254     // Expect the checked exception to propagate as-is
    255     try {
    256       sample.twoDeclared();
    257       fail();
    258     } catch (SomeOtherCheckedException expected) {
    259     }
    260   }
    261 
    262   public void testPropageIfPossible_null() throws SomeCheckedException {
    263     Throwables.propagateIfPossible(null);
    264     Throwables.propagateIfPossible(null, SomeCheckedException.class);
    265     Throwables.propagateIfPossible(null, SomeCheckedException.class,
    266         SomeUncheckedException.class);
    267   }
    268 
    269   public void testPropagate_NoneDeclared_NoneThrown() {
    270     Sample sample = new Sample() {
    271       @Override public void noneDeclared() {
    272         try {
    273           methodThatDoesntThrowAnything();
    274         } catch (Throwable t) {
    275           throw Throwables.propagate(t);
    276         }
    277       }
    278     };
    279 
    280     // Expect no exception to be thrown
    281     sample.noneDeclared();
    282   }
    283 
    284   public void testPropagate_NoneDeclared_UncheckedThrown() {
    285     Sample sample = new Sample() {
    286       @Override public void noneDeclared() {
    287         try {
    288           methodThatThrowsUnchecked();
    289         } catch (Throwable t) {
    290           throw Throwables.propagate(t);
    291         }
    292       }
    293     };
    294 
    295     // Expect the unchecked exception to propagate as-is
    296     try {
    297       sample.noneDeclared();
    298       fail();
    299     } catch (SomeUncheckedException expected) {
    300     }
    301   }
    302 
    303   public void testPropagate_NoneDeclared_ErrorThrown() {
    304     Sample sample = new Sample() {
    305       @Override public void noneDeclared() {
    306         try {
    307           methodThatThrowsError();
    308         } catch (Throwable t) {
    309           throw Throwables.propagate(t);
    310         }
    311       }
    312     };
    313 
    314     // Expect the error to propagate as-is
    315     try {
    316       sample.noneDeclared();
    317       fail();
    318     } catch (SomeError expected) {
    319     }
    320   }
    321 
    322   public void testPropagate_NoneDeclared_CheckedThrown() {
    323     Sample sample = new Sample() {
    324       @Override public void noneDeclared() {
    325         try {
    326           methodThatThrowsChecked();
    327         } catch (Throwable t) {
    328           throw Throwables.propagate(t);
    329         }
    330       }
    331     };
    332 
    333     // Expect the undeclared exception to have been chained inside another
    334     try {
    335       sample.noneDeclared();
    336       fail();
    337     } catch (RuntimeException expected) {
    338       assertTrue(expected.getCause() instanceof SomeCheckedException);
    339     }
    340   }
    341 
    342   public void testPropagateIfInstanceOf_NoneThrown()
    343       throws SomeCheckedException {
    344     Sample sample = new Sample() {
    345       @Override public void oneDeclared() throws SomeCheckedException {
    346         try {
    347           methodThatDoesntThrowAnything();
    348         } catch (Throwable t) {
    349           Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
    350           throw Throwables.propagate(t);
    351         }
    352       }
    353     };
    354 
    355     // Expect no exception to be thrown
    356     sample.oneDeclared();
    357   }
    358 
    359   public void testPropagateIfInstanceOf_DeclaredThrown() {
    360     Sample sample = new Sample() {
    361       @Override public void oneDeclared() throws SomeCheckedException {
    362         try {
    363           methodThatThrowsChecked();
    364         } catch (Throwable t) {
    365           Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
    366           throw Throwables.propagate(t);
    367         }
    368       }
    369     };
    370 
    371     // Expect declared exception to be thrown as-is
    372     try {
    373       sample.oneDeclared();
    374       fail();
    375     } catch (SomeCheckedException e) {
    376     }
    377   }
    378 
    379   public void testPropagateIfInstanceOf_UncheckedThrown()
    380       throws SomeCheckedException {
    381     Sample sample = new Sample() {
    382       @Override public void oneDeclared() throws SomeCheckedException {
    383         try {
    384           methodThatThrowsUnchecked();
    385         } catch (Throwable t) {
    386           Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
    387           throw Throwables.propagate(t);
    388         }
    389       }
    390     };
    391 
    392     // Expect unchecked exception to be thrown as-is
    393     try {
    394       sample.oneDeclared();
    395       fail();
    396     } catch (SomeUncheckedException e) {
    397     }
    398   }
    399 
    400   public void testPropagateIfInstanceOf_UndeclaredThrown()
    401       throws SomeCheckedException {
    402     Sample sample = new Sample() {
    403       @Override public void oneDeclared() throws SomeCheckedException {
    404         try {
    405           methodThatThrowsOtherChecked();
    406         } catch (Throwable t) {
    407           Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
    408           throw Throwables.propagate(t);
    409         }
    410       }
    411     };
    412 
    413     // Expect undeclared exception wrapped by RuntimeException to be thrown
    414     try {
    415       sample.oneDeclared();
    416       fail();
    417     } catch (RuntimeException e) {
    418       assertTrue(e.getCause() instanceof SomeOtherCheckedException);
    419     }
    420   }
    421 
    422   public void testPropageIfInstanceOf_null() throws SomeCheckedException {
    423     Throwables.propagateIfInstanceOf(null, SomeCheckedException.class);
    424   }
    425 
    426   public void testGetRootCause_NoCause() {
    427     SomeCheckedException exception = new SomeCheckedException();
    428     assertSame(exception, Throwables.getRootCause(exception));
    429   }
    430 
    431   public void testGetRootCause_SingleWrapped() {
    432     SomeCheckedException cause = new SomeCheckedException();
    433     SomeChainingException exception = new SomeChainingException(cause);
    434     assertSame(cause, Throwables.getRootCause(exception));
    435   }
    436 
    437   public void testGetRootCause_DoubleWrapped() {
    438     SomeCheckedException cause = new SomeCheckedException();
    439     SomeChainingException exception =
    440         new SomeChainingException(new SomeChainingException(cause));
    441     assertSame(cause, Throwables.getRootCause(exception));
    442   }
    443 
    444   private static class SomeError extends Error {}
    445   private static class SomeCheckedException extends Exception {}
    446   private static class SomeOtherCheckedException extends Exception {}
    447   private static class SomeUncheckedException extends RuntimeException {}
    448   private static class SomeUndeclaredCheckedException extends Exception {}
    449   private static class SomeChainingException extends RuntimeException {
    450     public SomeChainingException(Throwable cause) {
    451       super(cause);
    452     }
    453   }
    454 
    455   static class Sample {
    456     void noneDeclared() {}
    457     void oneDeclared() throws SomeCheckedException {}
    458     void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {}
    459   }
    460 
    461   static void methodThatDoesntThrowAnything() {}
    462   static void methodThatThrowsError() {
    463     throw new SomeError();
    464   }
    465   static void methodThatThrowsUnchecked() {
    466     throw new SomeUncheckedException();
    467   }
    468   static void methodThatThrowsChecked() throws SomeCheckedException {
    469     throw new SomeCheckedException();
    470   }
    471   static void methodThatThrowsOtherChecked() throws SomeOtherCheckedException {
    472     throw new SomeOtherCheckedException();
    473   }
    474   static void methodThatThrowsUndeclaredChecked()
    475       throws SomeUndeclaredCheckedException {
    476     throw new SomeUndeclaredCheckedException();
    477   }
    478 
    479   public void testGetStackTraceAsString() {
    480     class StackTraceException extends Exception {
    481       StackTraceException(String message) {
    482         super(message);
    483       }
    484     }
    485 
    486     StackTraceException e = new StackTraceException("my message");
    487 
    488     String firstLine = quote(e.getClass().getName() + ": " + e.getMessage());
    489     String secondLine = "\\s*at " + ThrowablesTest.class.getName() + "\\..*";
    490     String moreLines = "(?:.*\n?)*";
    491     String expected = firstLine + "\n" + secondLine + "\n" + moreLines;
    492     assertTrue(getStackTraceAsString(e).matches(expected));
    493   }
    494 
    495   public void testGetCausalChain() {
    496     FileNotFoundException fnfe = new FileNotFoundException();
    497     IllegalArgumentException iae = new IllegalArgumentException(fnfe);
    498     RuntimeException re = new RuntimeException(iae);
    499     IllegalStateException ex = new IllegalStateException(re);
    500 
    501     assertEquals(asList(ex, re, iae, fnfe), Throwables.getCausalChain(ex));
    502     assertSame(fnfe, Iterables.getOnlyElement(Throwables.getCausalChain(fnfe)));
    503     try {
    504       Throwables.getCausalChain(null);
    505       fail("Should have throw NPE");
    506     } catch (NullPointerException expected) {
    507     }
    508 
    509     List<Throwable> causes = Throwables.getCausalChain(ex);
    510     try {
    511       causes.add(new RuntimeException());
    512       fail("List should be unmodifiable");
    513     } catch (UnsupportedOperationException expected) {
    514     }
    515   }
    516 
    517   public void testNullPointers() {
    518     new NullPointerTester().testAllPublicStaticMethods(Throwables.class);
    519   }
    520 }
    521