1 /* 2 * Copyright (C) 2006 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.truth.Truth.assertThat; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.collect.ImmutableList; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Lists; 26 import com.google.common.testing.ArbitraryInstances; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.Method; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.List; 32 import junit.framework.AssertionFailedError; 33 import junit.framework.TestCase; 34 35 /** 36 * Unit test for {@link Preconditions}. 37 * 38 * @author Kevin Bourrillion 39 * @author Jared Levy 40 */ 41 @GwtCompatible(emulated = true) 42 public class PreconditionsTest extends TestCase { testCheckArgument_simple_success()43 public void testCheckArgument_simple_success() { 44 Preconditions.checkArgument(true); 45 } 46 testCheckArgument_simple_failure()47 public void testCheckArgument_simple_failure() { 48 try { 49 Preconditions.checkArgument(false); 50 fail("no exception thrown"); 51 } catch (IllegalArgumentException expected) { 52 } 53 } 54 testCheckArgument_simpleMessage_success()55 public void testCheckArgument_simpleMessage_success() { 56 Preconditions.checkArgument(true, IGNORE_ME); 57 } 58 testCheckArgument_simpleMessage_failure()59 public void testCheckArgument_simpleMessage_failure() { 60 try { 61 Preconditions.checkArgument(false, new Message()); 62 fail("no exception thrown"); 63 } catch (IllegalArgumentException expected) { 64 verifySimpleMessage(expected); 65 } 66 } 67 testCheckArgument_nullMessage_failure()68 public void testCheckArgument_nullMessage_failure() { 69 try { 70 Preconditions.checkArgument(false, null); 71 fail("no exception thrown"); 72 } catch (IllegalArgumentException expected) { 73 assertThat(expected).hasMessageThat().isEqualTo("null"); 74 } 75 } 76 testCheckArgument_nullMessageWithArgs_failure()77 public void testCheckArgument_nullMessageWithArgs_failure() { 78 try { 79 Preconditions.checkArgument(false, null, "b", "d"); 80 fail("no exception thrown"); 81 } catch (IllegalArgumentException e) { 82 assertThat(e).hasMessageThat().isEqualTo("null [b, d]"); 83 } 84 } 85 testCheckArgument_nullArgs_failure()86 public void testCheckArgument_nullArgs_failure() { 87 try { 88 Preconditions.checkArgument(false, "A %s C %s E", null, null); 89 fail("no exception thrown"); 90 } catch (IllegalArgumentException e) { 91 assertThat(e).hasMessageThat().isEqualTo("A null C null E"); 92 } 93 } 94 testCheckArgument_notEnoughArgs_failure()95 public void testCheckArgument_notEnoughArgs_failure() { 96 try { 97 Preconditions.checkArgument(false, "A %s C %s E", "b"); 98 fail("no exception thrown"); 99 } catch (IllegalArgumentException e) { 100 assertThat(e).hasMessageThat().isEqualTo("A b C %s E"); 101 } 102 } 103 testCheckArgument_tooManyArgs_failure()104 public void testCheckArgument_tooManyArgs_failure() { 105 try { 106 Preconditions.checkArgument(false, "A %s C %s E", "b", "d", "f"); 107 fail("no exception thrown"); 108 } catch (IllegalArgumentException e) { 109 assertThat(e).hasMessageThat().isEqualTo("A b C d E [f]"); 110 } 111 } 112 testCheckArgument_singleNullArg_failure()113 public void testCheckArgument_singleNullArg_failure() { 114 try { 115 Preconditions.checkArgument(false, "A %s C", (Object) null); 116 fail("no exception thrown"); 117 } catch (IllegalArgumentException e) { 118 assertThat(e).hasMessageThat().isEqualTo("A null C"); 119 } 120 } 121 testCheckArgument_singleNullArray_failure()122 public void testCheckArgument_singleNullArray_failure() { 123 try { 124 Preconditions.checkArgument(false, "A %s C", (Object[]) null); 125 fail("no exception thrown"); 126 } catch (IllegalArgumentException e) { 127 assertThat(e).hasMessageThat().isEqualTo("A (Object[])null C"); 128 } 129 } 130 testCheckArgument_complexMessage_success()131 public void testCheckArgument_complexMessage_success() { 132 Preconditions.checkArgument(true, "%s", IGNORE_ME); 133 } 134 testCheckArgument_complexMessage_failure()135 public void testCheckArgument_complexMessage_failure() { 136 try { 137 Preconditions.checkArgument(false, FORMAT, 5); 138 fail("no exception thrown"); 139 } catch (IllegalArgumentException expected) { 140 verifyComplexMessage(expected); 141 } 142 } 143 testCheckState_simple_success()144 public void testCheckState_simple_success() { 145 Preconditions.checkState(true); 146 } 147 testCheckState_simple_failure()148 public void testCheckState_simple_failure() { 149 try { 150 Preconditions.checkState(false); 151 fail("no exception thrown"); 152 } catch (IllegalStateException expected) { 153 } 154 } 155 testCheckState_simpleMessage_success()156 public void testCheckState_simpleMessage_success() { 157 Preconditions.checkState(true, IGNORE_ME); 158 } 159 testCheckState_simpleMessage_failure()160 public void testCheckState_simpleMessage_failure() { 161 try { 162 Preconditions.checkState(false, new Message()); 163 fail("no exception thrown"); 164 } catch (IllegalStateException expected) { 165 verifySimpleMessage(expected); 166 } 167 } 168 testCheckState_nullMessage_failure()169 public void testCheckState_nullMessage_failure() { 170 try { 171 Preconditions.checkState(false, null); 172 fail("no exception thrown"); 173 } catch (IllegalStateException expected) { 174 assertThat(expected).hasMessageThat().isEqualTo("null"); 175 } 176 } 177 testCheckState_complexMessage_success()178 public void testCheckState_complexMessage_success() { 179 Preconditions.checkState(true, "%s", IGNORE_ME); 180 } 181 testCheckState_complexMessage_failure()182 public void testCheckState_complexMessage_failure() { 183 try { 184 Preconditions.checkState(false, FORMAT, 5); 185 fail("no exception thrown"); 186 } catch (IllegalStateException expected) { 187 verifyComplexMessage(expected); 188 } 189 } 190 191 private static final String NON_NULL_STRING = "foo"; 192 testCheckNotNull_simple_success()193 public void testCheckNotNull_simple_success() { 194 String result = Preconditions.checkNotNull(NON_NULL_STRING); 195 assertSame(NON_NULL_STRING, result); 196 } 197 testCheckNotNull_simple_failure()198 public void testCheckNotNull_simple_failure() { 199 try { 200 Preconditions.checkNotNull(null); 201 fail("no exception thrown"); 202 } catch (NullPointerException expected) { 203 } 204 } 205 testCheckNotNull_simpleMessage_success()206 public void testCheckNotNull_simpleMessage_success() { 207 String result = Preconditions.checkNotNull(NON_NULL_STRING, IGNORE_ME); 208 assertSame(NON_NULL_STRING, result); 209 } 210 testCheckNotNull_simpleMessage_failure()211 public void testCheckNotNull_simpleMessage_failure() { 212 try { 213 Preconditions.checkNotNull(null, new Message()); 214 fail("no exception thrown"); 215 } catch (NullPointerException expected) { 216 verifySimpleMessage(expected); 217 } 218 } 219 testCheckNotNull_complexMessage_success()220 public void testCheckNotNull_complexMessage_success() { 221 String result = Preconditions.checkNotNull(NON_NULL_STRING, "%s", IGNORE_ME); 222 assertSame(NON_NULL_STRING, result); 223 } 224 testCheckNotNull_complexMessage_failure()225 public void testCheckNotNull_complexMessage_failure() { 226 try { 227 Preconditions.checkNotNull(null, FORMAT, 5); 228 fail("no exception thrown"); 229 } catch (NullPointerException expected) { 230 verifyComplexMessage(expected); 231 } 232 } 233 testCheckElementIndex_ok()234 public void testCheckElementIndex_ok() { 235 assertEquals(0, Preconditions.checkElementIndex(0, 1)); 236 assertEquals(0, Preconditions.checkElementIndex(0, 2)); 237 assertEquals(1, Preconditions.checkElementIndex(1, 2)); 238 } 239 testCheckElementIndex_badSize()240 public void testCheckElementIndex_badSize() { 241 try { 242 Preconditions.checkElementIndex(1, -1); 243 fail(); 244 } catch (IllegalArgumentException expected) { 245 // don't care what the message text is, as this is an invalid usage of 246 // the Preconditions class, unlike all the other exceptions it throws 247 } 248 } 249 testCheckElementIndex_negative()250 public void testCheckElementIndex_negative() { 251 try { 252 Preconditions.checkElementIndex(-1, 1); 253 fail(); 254 } catch (IndexOutOfBoundsException expected) { 255 assertThat(expected).hasMessageThat().isEqualTo("index (-1) must not be negative"); 256 } 257 } 258 testCheckElementIndex_tooHigh()259 public void testCheckElementIndex_tooHigh() { 260 try { 261 Preconditions.checkElementIndex(1, 1); 262 fail(); 263 } catch (IndexOutOfBoundsException expected) { 264 assertThat(expected).hasMessageThat().isEqualTo("index (1) must be less than size (1)"); 265 } 266 } 267 testCheckElementIndex_withDesc_negative()268 public void testCheckElementIndex_withDesc_negative() { 269 try { 270 Preconditions.checkElementIndex(-1, 1, "foo"); 271 fail(); 272 } catch (IndexOutOfBoundsException expected) { 273 assertThat(expected).hasMessageThat().isEqualTo("foo (-1) must not be negative"); 274 } 275 } 276 testCheckElementIndex_withDesc_tooHigh()277 public void testCheckElementIndex_withDesc_tooHigh() { 278 try { 279 Preconditions.checkElementIndex(1, 1, "foo"); 280 fail(); 281 } catch (IndexOutOfBoundsException expected) { 282 assertThat(expected).hasMessageThat().isEqualTo("foo (1) must be less than size (1)"); 283 } 284 } 285 testCheckPositionIndex_ok()286 public void testCheckPositionIndex_ok() { 287 assertEquals(0, Preconditions.checkPositionIndex(0, 0)); 288 assertEquals(0, Preconditions.checkPositionIndex(0, 1)); 289 assertEquals(1, Preconditions.checkPositionIndex(1, 1)); 290 } 291 testCheckPositionIndex_badSize()292 public void testCheckPositionIndex_badSize() { 293 try { 294 Preconditions.checkPositionIndex(1, -1); 295 fail(); 296 } catch (IllegalArgumentException expected) { 297 // don't care what the message text is, as this is an invalid usage of 298 // the Preconditions class, unlike all the other exceptions it throws 299 } 300 } 301 testCheckPositionIndex_negative()302 public void testCheckPositionIndex_negative() { 303 try { 304 Preconditions.checkPositionIndex(-1, 1); 305 fail(); 306 } catch (IndexOutOfBoundsException expected) { 307 assertThat(expected).hasMessageThat().isEqualTo("index (-1) must not be negative"); 308 } 309 } 310 testCheckPositionIndex_tooHigh()311 public void testCheckPositionIndex_tooHigh() { 312 try { 313 Preconditions.checkPositionIndex(2, 1); 314 fail(); 315 } catch (IndexOutOfBoundsException expected) { 316 assertThat(expected) 317 .hasMessageThat() 318 .isEqualTo("index (2) must not be greater than size (1)"); 319 } 320 } 321 testCheckPositionIndex_withDesc_negative()322 public void testCheckPositionIndex_withDesc_negative() { 323 try { 324 Preconditions.checkPositionIndex(-1, 1, "foo"); 325 fail(); 326 } catch (IndexOutOfBoundsException expected) { 327 assertThat(expected).hasMessageThat().isEqualTo("foo (-1) must not be negative"); 328 } 329 } 330 testCheckPositionIndex_withDesc_tooHigh()331 public void testCheckPositionIndex_withDesc_tooHigh() { 332 try { 333 Preconditions.checkPositionIndex(2, 1, "foo"); 334 fail(); 335 } catch (IndexOutOfBoundsException expected) { 336 assertThat(expected).hasMessageThat().isEqualTo("foo (2) must not be greater than size (1)"); 337 } 338 } 339 testCheckPositionIndexes_ok()340 public void testCheckPositionIndexes_ok() { 341 Preconditions.checkPositionIndexes(0, 0, 0); 342 Preconditions.checkPositionIndexes(0, 0, 1); 343 Preconditions.checkPositionIndexes(0, 1, 1); 344 Preconditions.checkPositionIndexes(1, 1, 1); 345 } 346 testCheckPositionIndexes_badSize()347 public void testCheckPositionIndexes_badSize() { 348 try { 349 Preconditions.checkPositionIndexes(1, 1, -1); 350 fail(); 351 } catch (IllegalArgumentException expected) { 352 } 353 } 354 testCheckPositionIndex_startNegative()355 public void testCheckPositionIndex_startNegative() { 356 try { 357 Preconditions.checkPositionIndexes(-1, 1, 1); 358 fail(); 359 } catch (IndexOutOfBoundsException expected) { 360 assertThat(expected).hasMessageThat().isEqualTo("start index (-1) must not be negative"); 361 } 362 } 363 testCheckPositionIndexes_endTooHigh()364 public void testCheckPositionIndexes_endTooHigh() { 365 try { 366 Preconditions.checkPositionIndexes(0, 2, 1); 367 fail(); 368 } catch (IndexOutOfBoundsException expected) { 369 assertThat(expected) 370 .hasMessageThat() 371 .isEqualTo("end index (2) must not be greater than size (1)"); 372 } 373 } 374 testCheckPositionIndexes_reversed()375 public void testCheckPositionIndexes_reversed() { 376 try { 377 Preconditions.checkPositionIndexes(1, 0, 1); 378 fail(); 379 } catch (IndexOutOfBoundsException expected) { 380 assertThat(expected) 381 .hasMessageThat() 382 .isEqualTo("end index (0) must not be less than start index (1)"); 383 } 384 } 385 386 @GwtIncompatible("Reflection") testAllOverloads_checkArgument()387 public void testAllOverloads_checkArgument() throws Exception { 388 for (ImmutableList<Class<?>> sig : allSignatures(boolean.class)) { 389 Method checkArgumentMethod = 390 Preconditions.class.getMethod("checkArgument", sig.toArray(new Class<?>[] {})); 391 checkArgumentMethod.invoke(null /* static method */, getParametersForSignature(true, sig)); 392 393 Object[] failingParams = getParametersForSignature(false, sig); 394 try { 395 checkArgumentMethod.invoke(null /* static method */, failingParams); 396 fail(); 397 } catch (InvocationTargetException ite) { 398 assertFailureCause(ite.getCause(), IllegalArgumentException.class, failingParams); 399 } 400 } 401 } 402 403 @GwtIncompatible("Reflection") testAllOverloads_checkState()404 public void testAllOverloads_checkState() throws Exception { 405 for (ImmutableList<Class<?>> sig : allSignatures(boolean.class)) { 406 Method checkArgumentMethod = 407 Preconditions.class.getMethod("checkState", sig.toArray(new Class<?>[] {})); 408 checkArgumentMethod.invoke(null /* static method */, getParametersForSignature(true, sig)); 409 410 Object[] failingParams = getParametersForSignature(false, sig); 411 try { 412 checkArgumentMethod.invoke(null /* static method */, failingParams); 413 fail(); 414 } catch (InvocationTargetException ite) { 415 assertFailureCause(ite.getCause(), IllegalStateException.class, failingParams); 416 } 417 } 418 } 419 420 @GwtIncompatible("Reflection") testAllOverloads_checkNotNull()421 public void testAllOverloads_checkNotNull() throws Exception { 422 for (ImmutableList<Class<?>> sig : allSignatures(Object.class)) { 423 Method checkArgumentMethod = 424 Preconditions.class.getMethod("checkNotNull", sig.toArray(new Class<?>[] {})); 425 checkArgumentMethod.invoke( 426 null /* static method */, getParametersForSignature(new Object(), sig)); 427 428 Object[] failingParams = getParametersForSignature(null, sig); 429 try { 430 checkArgumentMethod.invoke(null /* static method */, failingParams); 431 fail(); 432 } catch (InvocationTargetException ite) { 433 assertFailureCause(ite.getCause(), NullPointerException.class, failingParams); 434 } 435 } 436 } 437 438 /** 439 * Asserts that the given throwable has the given class and then asserts on the message as using 440 * the full set of method parameters. 441 */ assertFailureCause( Throwable throwable, Class<? extends Throwable> clazz, Object[] params)442 private void assertFailureCause( 443 Throwable throwable, Class<? extends Throwable> clazz, Object[] params) { 444 assertThat(throwable).isInstanceOf(clazz); 445 if (params.length == 1) { 446 assertThat(throwable).hasMessageThat().isNull(); 447 } else if (params.length == 2) { 448 assertThat(throwable).hasMessageThat().isEmpty(); 449 } else { 450 assertThat(throwable) 451 .hasMessageThat() 452 .isEqualTo(Strings.lenientFormat("", Arrays.copyOfRange(params, 2, params.length))); 453 } 454 } 455 456 /** 457 * Returns an array containing parameters for invoking a checkArgument, checkNotNull or checkState 458 * method reflectively 459 * 460 * @param firstParam The first parameter 461 * @param sig The method signature 462 */ 463 @GwtIncompatible("ArbitraryInstances") getParametersForSignature(Object firstParam, ImmutableList<Class<?>> sig)464 private Object[] getParametersForSignature(Object firstParam, ImmutableList<Class<?>> sig) { 465 Object[] params = new Object[sig.size()]; 466 params[0] = firstParam; 467 if (params.length > 1) { 468 params[1] = ""; 469 if (params.length > 2) { 470 // fill in the rest of the array with arbitrary instances 471 for (int i = 2; i < params.length; i++) { 472 params[i] = ArbitraryInstances.get(sig.get(i)); 473 } 474 } 475 } 476 return params; 477 } 478 479 private static final ImmutableList<Class<?>> possibleParamTypes = 480 ImmutableList.of(char.class, int.class, long.class, Object.class); 481 482 /** 483 * Returns a list of parameters for invoking an overload of checkState, checkArgument or 484 * checkNotNull 485 * 486 * @param predicateType The first parameter to the method (boolean or Object) 487 */ allSignatures(Class<?> predicateType)488 private static ImmutableList<ImmutableList<Class<?>>> allSignatures(Class<?> predicateType) { 489 ImmutableSet.Builder<ImmutableList<Class<?>>> allOverloads = ImmutableSet.builder(); 490 // The first two are for the overloads that don't take formatting args, e.g. 491 // checkArgument(boolean) and checkArgument(boolean, Object) 492 allOverloads.add(ImmutableList.<Class<?>>of(predicateType)); 493 allOverloads.add(ImmutableList.<Class<?>>of(predicateType, Object.class)); 494 495 List<List<Class<?>>> typesLists = new ArrayList<>(); 496 for (int i = 0; i < 2; i++) { 497 typesLists.add(possibleParamTypes); 498 for (List<Class<?>> curr : Lists.cartesianProduct(typesLists)) { 499 allOverloads.add( 500 ImmutableList.<Class<?>>builder() 501 .add(predicateType) 502 .add(String.class) // the format string 503 .addAll(curr) 504 .build()); 505 } 506 } 507 return allOverloads.build().asList(); 508 } 509 510 // 'test' to demonstrate some potentially ambiguous overloads. This 'test' is kind of strange, 511 // but essentially each line will be a call to a Preconditions method that, but for a documented 512 // change would be a compiler error. 513 // See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2 for the spec on 514 // how javac selects overloads 515 @SuppressWarnings("null") overloadSelection()516 public void overloadSelection() { 517 Boolean boxedBoolean = null; 518 boolean aBoolean = true; 519 Long boxedLong = null; 520 int anInt = 1; 521 // With a boxed predicate, no overloads can be selected in phase 1 522 // ambiguous without the call to .booleanValue to unbox the Boolean 523 Preconditions.checkState(boxedBoolean.booleanValue(), "", 1); 524 // ambiguous without the cast to Object because the boxed predicate prevents any overload from 525 // being selected in phase 1 526 Preconditions.checkState(boxedBoolean, "", (Object) boxedLong); 527 528 // ternaries introduce their own problems. because of the ternary (which requires a boxing 529 // operation) no overload can be selected in phase 1. and in phase 2 it is ambiguous since it 530 // matches with the second parameter being boxed and without it being boxed. The cast to Object 531 // avoids this. 532 Preconditions.checkState(aBoolean, "", aBoolean ? "" : anInt, (Object) anInt); 533 534 // ambiguous without the .booleanValue() call since the boxing forces us into phase 2 resolution 535 short s = 2; 536 Preconditions.checkState(boxedBoolean.booleanValue(), "", s); 537 } 538 539 @GwtIncompatible // NullPointerTester testNullPointers()540 public void testNullPointers() { 541 /* 542 * Don't bother testing: Preconditions defines a bunch of methods that accept a template (or 543 * even entire message) that simultaneously: 544 * 545 * - _shouldn't_ be null, so we don't annotate it with @Nullable 546 * 547 * - _can_ be null without causing a runtime failure (because we don't want the interesting 548 * details of precondition failure to be hidden by an exception we throw about an unexpectedly 549 * null _failure message_) 550 * 551 * That combination upsets NullPointerTester, which wants any call that passes null for a 552 * non-@Nullable parameter to trigger a NullPointerException. 553 * 554 * (We still define this empty method to keep PackageSanityTests from generating its own 555 * automated nullness tests, which would fail.) 556 */ 557 } 558 559 private static final Object IGNORE_ME = 560 new Object() { 561 @Override 562 public String toString() { 563 throw new AssertionFailedError(); 564 } 565 }; 566 567 private static class Message { 568 boolean invoked; 569 570 @Override toString()571 public String toString() { 572 assertFalse(invoked); 573 invoked = true; 574 return "A message"; 575 } 576 } 577 578 private static final String FORMAT = "I ate %s pies."; 579 verifySimpleMessage(Exception e)580 private static void verifySimpleMessage(Exception e) { 581 assertThat(e).hasMessageThat().isEqualTo("A message"); 582 } 583 verifyComplexMessage(Exception e)584 private static void verifyComplexMessage(Exception e) { 585 assertThat(e).hasMessageThat().isEqualTo("I ate 5 pies."); 586 } 587 } 588