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