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