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 { testPropagateIfPossible_NoneDeclared_NoneThrown()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 testPropagateIfPossible_NoneDeclared_UncheckedThrown()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 testPropagateIfPossible_NoneDeclared_UndeclaredThrown()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 testPropagateIfPossible_OneDeclared_NoneThrown()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 testPropagateIfPossible_OneDeclared_UncheckedThrown()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 testPropagateIfPossible_OneDeclared_CheckedThrown()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 testPropagateIfPossible_OneDeclared_UndeclaredThrown()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 testPropagateIfPossible_TwoDeclared_NoneThrown()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 testPropagateIfPossible_TwoDeclared_UncheckedThrown()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 testPropagateIfPossible_TwoDeclared_CheckedThrown()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 testPropagateIfPossible_TwoDeclared_OtherCheckedThrown()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 testPropageIfPossible_null()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 testPropagate_NoneDeclared_NoneThrown()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 testPropagate_NoneDeclared_UncheckedThrown()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 testPropagate_NoneDeclared_ErrorThrown()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 testPropagate_NoneDeclared_CheckedThrown()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 testPropagateIfInstanceOf_NoneThrown()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 testPropagateIfInstanceOf_DeclaredThrown()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 testPropagateIfInstanceOf_UncheckedThrown()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 testPropagateIfInstanceOf_UndeclaredThrown()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 testPropageIfInstanceOf_null()423 public void testPropageIfInstanceOf_null() throws SomeCheckedException { 424 Throwables.propagateIfInstanceOf(null, SomeCheckedException.class); 425 } 426 testGetRootCause_NoCause()427 public void testGetRootCause_NoCause() { 428 SomeCheckedException exception = new SomeCheckedException(); 429 assertSame(exception, Throwables.getRootCause(exception)); 430 } 431 testGetRootCause_SingleWrapped()432 public void testGetRootCause_SingleWrapped() { 433 SomeCheckedException cause = new SomeCheckedException(); 434 SomeChainingException exception = new SomeChainingException(cause); 435 assertSame(cause, Throwables.getRootCause(exception)); 436 } 437 testGetRootCause_DoubleWrapped()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 { SomeChainingException(Throwable cause)452 public SomeChainingException(Throwable cause) { 453 super(cause); 454 } 455 } 456 457 static class Sample { noneDeclared()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") oneDeclared()466 void oneDeclared() throws SomeCheckedException {} 467 @SuppressWarnings("unused") twoDeclared()468 void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {} 469 } 470 methodThatDoesntThrowAnything()471 static void methodThatDoesntThrowAnything() {} methodThatThrowsError()472 static void methodThatThrowsError() { 473 throw new SomeError(); 474 } methodThatThrowsUnchecked()475 static void methodThatThrowsUnchecked() { 476 throw new SomeUncheckedException(); 477 } methodThatThrowsChecked()478 static void methodThatThrowsChecked() throws SomeCheckedException { 479 throw new SomeCheckedException(); 480 } methodThatThrowsOtherChecked()481 static void methodThatThrowsOtherChecked() throws SomeOtherCheckedException { 482 throw new SomeOtherCheckedException(); 483 } methodThatThrowsUndeclaredChecked()484 static void methodThatThrowsUndeclaredChecked() 485 throws SomeUndeclaredCheckedException { 486 throw new SomeUndeclaredCheckedException(); 487 } 488 testGetStackTraceAsString()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 testGetCausalChain()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 testNullPointers()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