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