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.ReflectionFreeAssertThrows.assertThrows; 20 import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION; 21 import static com.google.common.base.Throwables.getCausalChain; 22 import static com.google.common.base.Throwables.getCauseAs; 23 import static com.google.common.base.Throwables.getRootCause; 24 import static com.google.common.base.Throwables.getStackTraceAsString; 25 import static com.google.common.base.Throwables.lazyStackTrace; 26 import static com.google.common.base.Throwables.lazyStackTraceIsLazy; 27 import static com.google.common.base.Throwables.propagate; 28 import static com.google.common.base.Throwables.propagateIfInstanceOf; 29 import static com.google.common.base.Throwables.propagateIfPossible; 30 import static com.google.common.base.Throwables.throwIfInstanceOf; 31 import static com.google.common.base.Throwables.throwIfUnchecked; 32 import static com.google.common.truth.Truth.assertThat; 33 import static java.util.regex.Pattern.quote; 34 35 import com.google.common.annotations.GwtCompatible; 36 import com.google.common.annotations.GwtIncompatible; 37 import com.google.common.annotations.J2ktIncompatible; 38 import com.google.common.base.TestExceptions.SomeChainingException; 39 import com.google.common.base.TestExceptions.SomeCheckedException; 40 import com.google.common.base.TestExceptions.SomeError; 41 import com.google.common.base.TestExceptions.SomeOtherCheckedException; 42 import com.google.common.base.TestExceptions.SomeUncheckedException; 43 import com.google.common.base.TestExceptions.YetAnotherCheckedException; 44 import com.google.common.collect.Iterables; 45 import com.google.common.primitives.Ints; 46 import com.google.common.testing.NullPointerTester; 47 import java.util.List; 48 import junit.framework.TestCase; 49 50 /** 51 * Unit test for {@link Throwables}. 52 * 53 * @author Kevin Bourrillion 54 */ 55 @GwtCompatible(emulated = true) 56 @SuppressWarnings("deprecation") // tests of numerous deprecated methods 57 public class ThrowablesTest extends TestCase { testThrowIfUnchecked_unchecked()58 public void testThrowIfUnchecked_unchecked() { 59 assertThrows( 60 SomeUncheckedException.class, () -> throwIfUnchecked(new SomeUncheckedException())); 61 } 62 testThrowIfUnchecked_error()63 public void testThrowIfUnchecked_error() { 64 assertThrows(SomeError.class, () -> throwIfUnchecked(new SomeError())); 65 } 66 67 @SuppressWarnings("ThrowIfUncheckedKnownChecked") testThrowIfUnchecked_checked()68 public void testThrowIfUnchecked_checked() { 69 throwIfUnchecked(new SomeCheckedException()); 70 } 71 72 @J2ktIncompatible 73 @GwtIncompatible // propagateIfPossible testPropagateIfPossible_noneDeclared_unchecked()74 public void testPropagateIfPossible_noneDeclared_unchecked() { 75 assertThrows( 76 SomeUncheckedException.class, () -> propagateIfPossible(new SomeUncheckedException())); 77 } 78 79 @J2ktIncompatible 80 @GwtIncompatible // propagateIfPossible 81 @SuppressWarnings("ThrowIfUncheckedKnownChecked") testPropagateIfPossible_noneDeclared_checked()82 public void testPropagateIfPossible_noneDeclared_checked() { 83 propagateIfPossible(new SomeCheckedException()); 84 } 85 86 @J2ktIncompatible 87 @GwtIncompatible // propagateIfPossible(Throwable, Class) testPropagateIfPossible_oneDeclared_unchecked()88 public void testPropagateIfPossible_oneDeclared_unchecked() { 89 assertThrows( 90 SomeUncheckedException.class, 91 () -> propagateIfPossible(new SomeUncheckedException(), SomeCheckedException.class)); 92 } 93 94 @J2ktIncompatible 95 @GwtIncompatible // propagateIfPossible(Throwable, Class) testPropagateIfPossible_oneDeclared_checkedSame()96 public void testPropagateIfPossible_oneDeclared_checkedSame() { 97 assertThrows( 98 SomeCheckedException.class, 99 () -> propagateIfPossible(new SomeCheckedException(), SomeCheckedException.class)); 100 } 101 102 @J2ktIncompatible 103 @GwtIncompatible // propagateIfPossible(Throwable, Class) testPropagateIfPossible_oneDeclared_checkedDifferent()104 public void testPropagateIfPossible_oneDeclared_checkedDifferent() throws SomeCheckedException { 105 propagateIfPossible(new SomeOtherCheckedException(), SomeCheckedException.class); 106 } 107 108 @J2ktIncompatible 109 @GwtIncompatible // propagateIfPossible(Throwable, Class, Class) testPropagateIfPossible_twoDeclared_unchecked()110 public void testPropagateIfPossible_twoDeclared_unchecked() { 111 assertThrows( 112 SomeUncheckedException.class, 113 () -> 114 propagateIfPossible( 115 new SomeUncheckedException(), 116 SomeCheckedException.class, 117 SomeOtherCheckedException.class)); 118 } 119 120 @J2ktIncompatible 121 @GwtIncompatible // propagateIfPossible(Throwable, Class, Class) testPropagateIfPossible_twoDeclared_firstSame()122 public void testPropagateIfPossible_twoDeclared_firstSame() { 123 assertThrows( 124 SomeCheckedException.class, 125 () -> 126 propagateIfPossible( 127 new SomeCheckedException(), 128 SomeCheckedException.class, 129 SomeOtherCheckedException.class)); 130 } 131 132 @J2ktIncompatible 133 @GwtIncompatible // propagateIfPossible(Throwable, Class, Class) testPropagateIfPossible_twoDeclared_secondSame()134 public void testPropagateIfPossible_twoDeclared_secondSame() { 135 assertThrows( 136 SomeOtherCheckedException.class, 137 () -> 138 propagateIfPossible( 139 new SomeOtherCheckedException(), 140 SomeCheckedException.class, 141 SomeOtherCheckedException.class)); 142 } 143 144 @J2ktIncompatible 145 @GwtIncompatible // propagateIfPossible(Throwable, Class, Class) testPropagateIfPossible_twoDeclared_neitherSame()146 public void testPropagateIfPossible_twoDeclared_neitherSame() 147 throws SomeCheckedException, SomeOtherCheckedException { 148 propagateIfPossible( 149 new YetAnotherCheckedException(), 150 SomeCheckedException.class, 151 SomeOtherCheckedException.class); 152 } 153 testThrowIfUnchecked_null()154 public void testThrowIfUnchecked_null() { 155 assertThrows(NullPointerException.class, () -> throwIfUnchecked(null)); 156 } 157 158 @J2ktIncompatible 159 @GwtIncompatible // propagateIfPossible testPropageIfPossible_null()160 public void testPropageIfPossible_null() { 161 propagateIfPossible(null); 162 } 163 164 @J2ktIncompatible 165 @GwtIncompatible // propagateIfPossible(Throwable, Class) testPropageIfPossible_oneDeclared_null()166 public void testPropageIfPossible_oneDeclared_null() throws SomeCheckedException { 167 propagateIfPossible(null, SomeCheckedException.class); 168 } 169 170 @J2ktIncompatible 171 @GwtIncompatible // propagateIfPossible(Throwable, Class, Class) testPropageIfPossible_twoDeclared_null()172 public void testPropageIfPossible_twoDeclared_null() 173 throws SomeCheckedException, SomeOtherCheckedException { 174 propagateIfPossible(null, SomeCheckedException.class, SomeOtherCheckedException.class); 175 } 176 177 @J2ktIncompatible 178 @GwtIncompatible // propagate testPropagate_noneDeclared_unchecked()179 public void testPropagate_noneDeclared_unchecked() { 180 assertThrows(SomeUncheckedException.class, () -> propagate(new SomeUncheckedException())); 181 } 182 183 @J2ktIncompatible 184 @GwtIncompatible // propagate testPropagate_noneDeclared_error()185 public void testPropagate_noneDeclared_error() { 186 assertThrows(SomeError.class, () -> propagate(new SomeError())); 187 } 188 189 @J2ktIncompatible 190 @GwtIncompatible // propagate testPropagate_noneDeclared_checked()191 public void testPropagate_noneDeclared_checked() { 192 RuntimeException expected = 193 assertThrows(RuntimeException.class, () -> propagate(new SomeCheckedException())); 194 assertThat(expected).hasCauseThat().isInstanceOf(SomeCheckedException.class); 195 } 196 197 @GwtIncompatible // throwIfInstanceOf testThrowIfInstanceOf_unchecked()198 public void testThrowIfInstanceOf_unchecked() throws SomeCheckedException { 199 throwIfInstanceOf(new SomeUncheckedException(), SomeCheckedException.class); 200 } 201 202 @GwtIncompatible // throwIfInstanceOf testThrowIfInstanceOf_checkedDifferent()203 public void testThrowIfInstanceOf_checkedDifferent() throws SomeCheckedException { 204 throwIfInstanceOf(new SomeOtherCheckedException(), SomeCheckedException.class); 205 } 206 207 @GwtIncompatible // throwIfInstanceOf testThrowIfInstanceOf_checkedSame()208 public void testThrowIfInstanceOf_checkedSame() { 209 assertThrows( 210 SomeCheckedException.class, 211 () -> throwIfInstanceOf(new SomeCheckedException(), SomeCheckedException.class)); 212 } 213 214 @GwtIncompatible // throwIfInstanceOf testThrowIfInstanceOf_checkedSubclass()215 public void testThrowIfInstanceOf_checkedSubclass() { 216 assertThrows( 217 SomeCheckedException.class, 218 () -> throwIfInstanceOf(new SomeCheckedException() {}, SomeCheckedException.class)); 219 } 220 221 @J2ktIncompatible 222 @GwtIncompatible // propagateIfInstanceOf testPropagateIfInstanceOf_checkedSame()223 public void testPropagateIfInstanceOf_checkedSame() { 224 assertThrows( 225 SomeCheckedException.class, 226 () -> propagateIfInstanceOf(new SomeCheckedException(), SomeCheckedException.class)); 227 } 228 229 @J2ktIncompatible 230 @GwtIncompatible // propagateIfInstanceOf testPropagateIfInstanceOf_unchecked()231 public void testPropagateIfInstanceOf_unchecked() throws SomeCheckedException { 232 propagateIfInstanceOf(new SomeUncheckedException(), SomeCheckedException.class); 233 } 234 235 @J2ktIncompatible 236 @GwtIncompatible // propagateIfInstanceOf testPropagateIfInstanceOf_checkedDifferent()237 public void testPropagateIfInstanceOf_checkedDifferent() throws SomeCheckedException { 238 propagateIfInstanceOf(new SomeOtherCheckedException(), SomeCheckedException.class); 239 } 240 241 @GwtIncompatible // throwIfInstanceOf testThrowIfInstanceOf_null()242 public void testThrowIfInstanceOf_null() { 243 assertThrows( 244 NullPointerException.class, () -> throwIfInstanceOf(null, SomeCheckedException.class)); 245 } 246 247 @J2ktIncompatible 248 @GwtIncompatible // propagateIfInstanceOf testPropageIfInstanceOf_null()249 public void testPropageIfInstanceOf_null() throws SomeCheckedException { 250 propagateIfInstanceOf(null, SomeCheckedException.class); 251 } 252 testGetRootCause_noCause()253 public void testGetRootCause_noCause() { 254 SomeCheckedException exception = new SomeCheckedException(); 255 assertSame(exception, getRootCause(exception)); 256 } 257 testGetRootCause_singleWrapped()258 public void testGetRootCause_singleWrapped() { 259 SomeCheckedException cause = new SomeCheckedException(); 260 SomeChainingException exception = new SomeChainingException(cause); 261 assertSame(cause, getRootCause(exception)); 262 } 263 testGetRootCause_doubleWrapped()264 public void testGetRootCause_doubleWrapped() { 265 SomeCheckedException cause = new SomeCheckedException(); 266 SomeChainingException exception = new SomeChainingException(new SomeChainingException(cause)); 267 assertSame(cause, getRootCause(exception)); 268 } 269 testGetRootCause_loop()270 public void testGetRootCause_loop() { 271 Exception cause = new Exception(); 272 Exception exception = new Exception(cause); 273 cause.initCause(exception); 274 IllegalArgumentException expected = 275 assertThrows(IllegalArgumentException.class, () -> getRootCause(cause)); 276 assertThat(expected).hasCauseThat().isSameInstanceAs(cause); 277 } 278 279 @J2ktIncompatible // Format does not match 280 @GwtIncompatible // getStackTraceAsString(Throwable) testGetStackTraceAsString()281 public void testGetStackTraceAsString() { 282 class StackTraceException extends Exception { 283 StackTraceException(String message) { 284 super(message); 285 } 286 } 287 288 StackTraceException e = new StackTraceException("my message"); 289 290 String firstLine = quote(e.getClass().getName() + ": " + e.getMessage()); 291 String secondLine = "\\s*at " + ThrowablesTest.class.getName() + "\\..*"; 292 String moreLines = "(?:.*" + System.lineSeparator() + "?)*"; 293 String expected = 294 firstLine + System.lineSeparator() + secondLine + System.lineSeparator() + moreLines; 295 assertThat(getStackTraceAsString(e)).matches(expected); 296 } 297 testGetCausalChain()298 public void testGetCausalChain() { 299 SomeUncheckedException sue = new SomeUncheckedException(); 300 IllegalArgumentException iae = new IllegalArgumentException(sue); 301 RuntimeException re = new RuntimeException(iae); 302 IllegalStateException ex = new IllegalStateException(re); 303 304 assertThat(getCausalChain(ex)).containsExactly(ex, re, iae, sue).inOrder(); 305 assertSame(sue, Iterables.getOnlyElement(getCausalChain(sue))); 306 307 List<Throwable> causes = getCausalChain(ex); 308 assertThrows(UnsupportedOperationException.class, () -> causes.add(new RuntimeException())); 309 } 310 testGetCasualChainNull()311 public void testGetCasualChainNull() { 312 assertThrows(NullPointerException.class, () -> getCausalChain(null)); 313 } 314 testGetCasualChainLoop()315 public void testGetCasualChainLoop() { 316 Exception cause = new Exception(); 317 Exception exception = new Exception(cause); 318 cause.initCause(exception); 319 IllegalArgumentException expected = 320 assertThrows(IllegalArgumentException.class, () -> getCausalChain(cause)); 321 assertThat(expected).hasCauseThat().isSameInstanceAs(cause); 322 } 323 324 @GwtIncompatible // getCauseAs(Throwable, Class) testGetCauseAs()325 public void testGetCauseAs() { 326 SomeCheckedException cause = new SomeCheckedException(); 327 SomeChainingException thrown = new SomeChainingException(cause); 328 329 assertThat(thrown).hasCauseThat().isSameInstanceAs(cause); 330 assertThat(getCauseAs(thrown, SomeCheckedException.class)).isSameInstanceAs(cause); 331 assertThat(getCauseAs(thrown, Exception.class)).isSameInstanceAs(cause); 332 333 ClassCastException expected = 334 assertThrows( 335 ClassCastException.class, () -> getCauseAs(thrown, IllegalStateException.class)); 336 assertThat(expected).hasCauseThat().isSameInstanceAs(thrown); 337 } 338 339 @AndroidIncompatible // No getJavaLangAccess in Android (at least not in the version we use). 340 @J2ktIncompatible 341 @GwtIncompatible // lazyStackTraceIsLazy() testLazyStackTraceWorksInProd()342 public void testLazyStackTraceWorksInProd() { 343 // TODO(b/64442212): Remove this guard once lazyStackTrace() works in Java 9+. 344 Integer javaVersion = Ints.tryParse(JAVA_SPECIFICATION_VERSION.value()); 345 if (javaVersion != null && javaVersion >= 9) { 346 return; 347 } 348 // Obviously this isn't guaranteed in every environment, but it works well enough for now: 349 assertTrue(lazyStackTraceIsLazy()); 350 } 351 352 @J2ktIncompatible 353 @GwtIncompatible // lazyStackTrace(Throwable) testLazyStackTrace()354 public void testLazyStackTrace() { 355 Exception e = new Exception(); 356 StackTraceElement[] originalStackTrace = e.getStackTrace(); 357 358 assertThat(lazyStackTrace(e)).containsExactly((Object[]) originalStackTrace).inOrder(); 359 360 assertThrows(UnsupportedOperationException.class, () -> lazyStackTrace(e).set(0, null)); 361 362 // Now we test a property that holds only for the lazy implementation. 363 364 if (!lazyStackTraceIsLazy()) { 365 return; 366 } 367 368 e.setStackTrace(new StackTraceElement[0]); 369 assertThat(lazyStackTrace(e)).containsExactly((Object[]) originalStackTrace).inOrder(); 370 } 371 372 @J2ktIncompatible 373 @GwtIncompatible // lazyStackTrace doTestLazyStackTraceFallback()374 private void doTestLazyStackTraceFallback() { 375 assertFalse(lazyStackTraceIsLazy()); 376 377 Exception e = new Exception(); 378 379 assertThat(lazyStackTrace(e)).containsExactly((Object[]) e.getStackTrace()).inOrder(); 380 381 try { 382 lazyStackTrace(e).set(0, null); 383 fail(); 384 } catch (UnsupportedOperationException expected) { 385 } 386 387 e.setStackTrace(new StackTraceElement[0]); 388 assertThat(lazyStackTrace(e)).isEmpty(); 389 } 390 391 @J2ktIncompatible 392 @GwtIncompatible // NullPointerTester testNullPointers()393 public void testNullPointers() { 394 new NullPointerTester().testAllPublicStaticMethods(Throwables.class); 395 } 396 } 397