/
githubmirror
/
guava
Обзор
Документация
Войти
/
githubmirror
/
guava
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
android/guava-tests/test/com/google/common/base/PreconditionsTest.java
505 строк
19 KB
cpovirk
Restore `testNulls` methods to classes that we don't want `PackageSanityTest` to automatically test with `NullPointerTester`.
13 июл 2026, 23:13
13 июл 2026, 23:13
ae76e3c
Код
Авторство
О чём код?
/* * Copyright (C) 2006 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.base; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkElementIndex; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndex; import static com.google.common.base.Preconditions.checkPositionIndexes; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Strings.lenientFormat; import static com.google.common.collect.Lists.cartesianProduct; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.J2ktIncompatible; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.testing.ArbitraryInstances; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; /** * Unit test for {@link Preconditions}. * * @author Kevin Bourrillion * @author Jared Levy */ @NullMarked @SuppressWarnings("LenientFormatStringValidation") // Intentional for testing @GwtCompatible public class PreconditionsTest extends TestCase { public void testCheckArgument_simple_success() { checkArgument(true); } public void testCheckArgument_simple_failure() { assertThrows(IllegalArgumentException.class, () -> checkArgument(false)); } public void testCheckArgument_simpleMessage_success() { checkArgument(true, IGNORE_ME); } public void testCheckArgument_simpleMessage_failure() { IllegalArgumentException expected = assertThrows(IllegalArgumentException.class, () -> checkArgument(false, new Message())); verifySimpleMessage(expected); } public void testCheckArgument_nullMessage_failure() { IllegalArgumentException expected = assertThrows(IllegalArgumentException.class, () -> checkArgument(false, null)); assertThat(expected).hasMessageThat().isEqualTo("null"); } public void testCheckArgument_nullMessageWithArgs_failure() { IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> checkArgument(false, null, "b", "d")); assertThat(e).hasMessageThat().isEqualTo("null [b, d]"); } public void testCheckArgument_nullArgs_failure() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, () -> checkArgument(false, "A %s C %s E", null, null)); assertThat(e).hasMessageThat().isEqualTo("A null C null E"); } public void testCheckArgument_notEnoughArgs_failure() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, () -> checkArgument(false, "A %s C %s E", "b")); assertThat(e).hasMessageThat().isEqualTo("A b C %s E"); } public void testCheckArgument_tooManyArgs_failure() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, () -> checkArgument(false, "A %s C %s E", "b", "d", "f")); assertThat(e).hasMessageThat().isEqualTo("A b C d E [f]"); } public void testCheckArgument_singleNullArg_failure() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, () -> checkArgument(false, "A %s C", (Object) null)); assertThat(e).hasMessageThat().isEqualTo("A null C"); } @J2ktIncompatible // TODO(b/319404022): Allow passing null array as varargs public void testCheckArgument_singleNullArray_failure() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, () -> checkArgument(false, "A %s C", (Object[]) null)); assertThat(e).hasMessageThat().isEqualTo("A (Object[])null C"); } public void testCheckArgument_complexMessage_success() { checkArgument(true, "%s", IGNORE_ME); } public void testCheckArgument_complexMessage_failure() { IllegalArgumentException expected = assertThrows(IllegalArgumentException.class, () -> checkArgument(false, FORMAT, 5)); verifyComplexMessage(expected); } public void testCheckState_simple_success() { checkState(true); } public void testCheckState_simple_failure() { assertThrows(IllegalStateException.class, () -> checkState(false)); } public void testCheckState_simpleMessage_success() { checkState(true, IGNORE_ME); } public void testCheckState_simpleMessage_failure() { IllegalStateException expected = assertThrows(IllegalStateException.class, () -> checkState(false, new Message())); verifySimpleMessage(expected); } public void testCheckState_nullMessage_failure() { IllegalStateException expected = assertThrows(IllegalStateException.class, () -> checkState(false, null)); assertThat(expected).hasMessageThat().isEqualTo("null"); } public void testCheckState_complexMessage_success() { checkState(true, "%s", IGNORE_ME); } public void testCheckState_complexMessage_failure() { IllegalStateException expected = assertThrows(IllegalStateException.class, () -> checkState(false, FORMAT, 5)); verifyComplexMessage(expected); } private static final String NON_NULL_STRING = "foo"; public void testCheckNotNull_simple_success() { String result = checkNotNull(NON_NULL_STRING); assertThat(result).isSameInstanceAs(NON_NULL_STRING); } public void testCheckNotNull_simple_failure() { assertThrows(NullPointerException.class, () -> checkNotNull(null)); } public void testCheckNotNull_simpleMessage_success() { String result = checkNotNull(NON_NULL_STRING, IGNORE_ME); assertThat(result).isSameInstanceAs(NON_NULL_STRING); } public void testCheckNotNull_simpleMessage_failure() { NullPointerException expected = assertThrows(NullPointerException.class, () -> checkNotNull(null, new Message())); verifySimpleMessage(expected); } public void testCheckNotNull_complexMessage_success() { String result = checkNotNull(NON_NULL_STRING, "%s", IGNORE_ME); assertThat(result).isSameInstanceAs(NON_NULL_STRING); } public void testCheckNotNull_complexMessage_failure() { NullPointerException expected = assertThrows(NullPointerException.class, () -> checkNotNull(null, FORMAT, 5)); verifyComplexMessage(expected); } public void testCheckElementIndex_ok() { assertEquals(0, checkElementIndex(0, 1)); assertEquals(0, checkElementIndex(0, 2)); assertEquals(1, checkElementIndex(1, 2)); } public void testCheckElementIndex_badSize() { assertThrows(IllegalArgumentException.class, () -> checkElementIndex(1, -1)); } public void testCheckElementIndex_negative() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkElementIndex(-1, 1)); assertThat(expected).hasMessageThat().isEqualTo("index (-1) must not be negative"); } public void testCheckElementIndex_tooHigh() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkElementIndex(1, 1)); assertThat(expected).hasMessageThat().isEqualTo("index (1) must be less than size (1)"); } public void testCheckElementIndex_withDesc_negative() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkElementIndex(-1, 1, "foo")); assertThat(expected).hasMessageThat().isEqualTo("foo (-1) must not be negative"); } public void testCheckElementIndex_withDesc_tooHigh() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkElementIndex(1, 1, "foo")); assertThat(expected).hasMessageThat().isEqualTo("foo (1) must be less than size (1)"); } public void testCheckPositionIndex_ok() { assertEquals(0, checkPositionIndex(0, 0)); assertEquals(0, checkPositionIndex(0, 1)); assertEquals(1, checkPositionIndex(1, 1)); } public void testCheckPositionIndex_badSize() { assertThrows(IllegalArgumentException.class, () -> checkPositionIndex(1, -1)); } public void testCheckPositionIndex_negative() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndex(-1, 1)); assertThat(expected).hasMessageThat().isEqualTo("index (-1) must not be negative"); } public void testCheckPositionIndex_tooHigh() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndex(2, 1)); assertThat(expected).hasMessageThat().isEqualTo("index (2) must not be greater than size (1)"); } public void testCheckPositionIndex_withDesc_negative() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndex(-1, 1, "foo")); assertThat(expected).hasMessageThat().isEqualTo("foo (-1) must not be negative"); } public void testCheckPositionIndex_withDesc_tooHigh() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndex(2, 1, "foo")); assertThat(expected).hasMessageThat().isEqualTo("foo (2) must not be greater than size (1)"); } public void testCheckPositionIndexes_ok() { checkPositionIndexes(0, 0, 0); checkPositionIndexes(0, 0, 1); checkPositionIndexes(0, 1, 1); checkPositionIndexes(1, 1, 1); } public void testCheckPositionIndexes_badSize() { assertThrows(IllegalArgumentException.class, () -> checkPositionIndexes(1, 1, -1)); } public void testCheckPositionIndex_startNegative() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndexes(-1, 1, 1)); assertThat(expected).hasMessageThat().isEqualTo("start index (-1) must not be negative"); } public void testCheckPositionIndexes_endTooHigh() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndexes(0, 2, 1)); assertThat(expected) .hasMessageThat() .isEqualTo("end index (2) must not be greater than size (1)"); } public void testCheckPositionIndexes_reversed() { IndexOutOfBoundsException expected = assertThrows(IndexOutOfBoundsException.class, () -> checkPositionIndexes(1, 0, 1)); assertThat(expected) .hasMessageThat() .isEqualTo("end index (0) must not be less than start index (1)"); } @GwtIncompatible // Reflection @J2ktIncompatible public void testAllOverloads_checkArgument() throws Exception { for (ImmutableList<Class<?>> sig : allSignatures(boolean.class)) { Method checkArgumentMethod = Preconditions.class.getMethod("checkArgument", sig.toArray(new Class<?>[] {})); checkArgumentMethod.invoke(null /* static method */, getParametersForSignature(true, sig)); Object[] failingParams = getParametersForSignature(false, sig); InvocationTargetException ite = assertThrows( InvocationTargetException.class, () -> checkArgumentMethod.invoke(null /* static method */, failingParams)); assertFailureCause(ite.getCause(), IllegalArgumentException.class, failingParams); } } @GwtIncompatible // Reflection @J2ktIncompatible public void testAllOverloads_checkState() throws Exception { for (ImmutableList<Class<?>> sig : allSignatures(boolean.class)) { Method checkArgumentMethod = Preconditions.class.getMethod("checkState", sig.toArray(new Class<?>[] {})); checkArgumentMethod.invoke(null /* static method */, getParametersForSignature(true, sig)); Object[] failingParams = getParametersForSignature(false, sig); InvocationTargetException ite = assertThrows( InvocationTargetException.class, () -> checkArgumentMethod.invoke(null /* static method */, failingParams)); assertFailureCause(ite.getCause(), IllegalStateException.class, failingParams); } } @GwtIncompatible // Reflection @J2ktIncompatible public void testAllOverloads_checkNotNull() throws Exception { for (ImmutableList<Class<?>> sig : allSignatures(Object.class)) { Method checkArgumentMethod = Preconditions.class.getMethod("checkNotNull", sig.toArray(new Class<?>[] {})); checkArgumentMethod.invoke( null /* static method */, getParametersForSignature(new Object(), sig)); Object[] failingParams = getParametersForSignature(null, sig); InvocationTargetException ite = assertThrows( InvocationTargetException.class, () -> checkArgumentMethod.invoke(null /* static method */, failingParams)); assertFailureCause(ite.getCause(), NullPointerException.class, failingParams); } } /** * Asserts that the given throwable has the given class and then asserts on the message as using * the full set of method parameters. */ private void assertFailureCause( Throwable throwable, Class<? extends Throwable> clazz, Object[] params) { assertThat(throwable).isInstanceOf(clazz); if (params.length == 1) { assertThat(throwable).hasMessageThat().isNull(); } else if (params.length == 2) { assertThat(throwable).hasMessageThat().isEmpty(); } else { assertThat(throwable) .hasMessageThat() .isEqualTo(lenientFormat("", Arrays.copyOfRange(params, 2, params.length))); } } /** * Returns an array containing parameters for invoking a checkArgument, checkNotNull or checkState * method reflectively * * @param firstParam The first parameter * @param sig The method signature */ @GwtIncompatible // ArbitraryInstances @J2ktIncompatible private Object[] getParametersForSignature( @Nullable Object firstParam, ImmutableList<Class<?>> sig) { Object[] params = new Object[sig.size()]; params[0] = firstParam; if (params.length > 1) { params[1] = ""; if (params.length > 2) { // fill in the rest of the array with arbitrary instances for (int i = 2; i < params.length; i++) { params[i] = ArbitraryInstances.get(sig.get(i)); } } } return params; } private static final ImmutableList<Class<?>> POSSIBLE_PARAM_TYPES = ImmutableList.of(char.class, int.class, long.class, Object.class); /** * Returns a list of parameters for invoking an overload of checkState, checkArgument or * checkNotNull * * @param predicateType The first parameter to the method (boolean or Object) */ private static ImmutableList<ImmutableList<Class<?>>> allSignatures(Class<?> predicateType) { ImmutableSet.Builder<ImmutableList<Class<?>>> allOverloads = ImmutableSet.builder(); // The first two are for the overloads that don't take formatting args, e.g. // checkArgument(boolean) and checkArgument(boolean, Object) allOverloads.add(ImmutableList.of(predicateType)); allOverloads.add(ImmutableList.of(predicateType, Object.class)); List<List<Class<?>>> typesLists = new ArrayList<>(); for (int i = 0; i < 2; i++) { typesLists.add(POSSIBLE_PARAM_TYPES); for (List<Class<?>> curr : cartesianProduct(typesLists)) { allOverloads.add( ImmutableList.<Class<?>>builder() .add(predicateType) .add(String.class) // the format string .addAll(curr) .build()); } } return allOverloads.build().asList(); } // 'test' to demonstrate some potentially ambiguous overloads. This 'test' is kind of strange, // but essentially each line will be a call to a Preconditions method that, but for a documented // change would be a compiler error. // See https://docs.oracle.com/javase/specs/jls/se26/html/jls-15.html#jls-15.12.2 for the spec on // how javac selects overloads @SuppressWarnings("null") public void overloadSelection() { Boolean boxedBoolean = null; boolean aBoolean = true; Long boxedLong = null; int anInt = 1; // With a boxed predicate, no overloads can be selected in phase 1 // ambiguous without the call to .booleanValue to unbox the Boolean checkState(boxedBoolean.booleanValue(), "", 1); // ambiguous without the cast to Object because the boxed predicate prevents any overload from // being selected in phase 1 checkState(boxedBoolean, "", (Object) boxedLong); // ternaries introduce their own problems. because of the ternary (which requires a boxing // operation) no overload can be selected in phase 1. and in phase 2 it is ambiguous since it // matches with the second parameter being boxed and without it being boxed. The cast to Object // avoids this. checkState(aBoolean, "", aBoolean ? "" : anInt, (Object) anInt); // ambiguous without the .booleanValue() call since the boxing forces us into phase 2 resolution short s = 2; checkState(boxedBoolean.booleanValue(), "", s); } @J2ktIncompatible @GwtIncompatible // NullPointerTester public void testNullPointers() { /* * Don't bother testing: Preconditions defines a bunch of methods that accept a template (or * even entire message) that simultaneously: * * - _shouldn't_ be null, so we don't annotate it with @Nullable * * - _can_ be null without causing a runtime failure (because we don't want the interesting * details of precondition failure to be hidden by an exception we throw about an unexpectedly * null _failure message_) * * That combination upsets NullPointerTester, which wants any call that passes null for a * non-@Nullable parameter to trigger a NullPointerException. * * (We still define this empty method to keep PackageSanityTests from generating its own * automated nullness tests, which would fail.) */ } private static final Object IGNORE_ME = new Object() { @Override public String toString() { throw new AssertionFailedError(); } }; private static class Message { boolean invoked; @Override public String toString() { assertFalse(invoked); invoked = true; return "A message"; } } private static final String FORMAT = "I ate %s pies."; private static void verifySimpleMessage(Exception e) { assertThat(e).hasMessageThat().isEqualTo("A message"); } private static void verifyComplexMessage(Exception e) { assertThat(e).hasMessageThat().isEqualTo("I ate 5 pies."); } }