Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2012 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.testing;
     18 
     19 import static com.google.common.base.Preconditions.checkArgument;
     20 import static com.google.common.base.Preconditions.checkNotNull;
     21 
     22 import com.google.common.annotations.Beta;
     23 import com.google.common.annotations.VisibleForTesting;
     24 import com.google.common.base.Joiner;
     25 import com.google.common.base.Objects;
     26 import com.google.common.base.Throwables;
     27 import com.google.common.collect.ArrayListMultimap;
     28 import com.google.common.collect.ImmutableList;
     29 import com.google.common.collect.ListMultimap;
     30 import com.google.common.collect.Lists;
     31 import com.google.common.collect.MutableClassToInstanceMap;
     32 import com.google.common.collect.Ordering;
     33 import com.google.common.collect.Sets;
     34 import com.google.common.primitives.Ints;
     35 import com.google.common.reflect.Invokable;
     36 import com.google.common.reflect.Parameter;
     37 import com.google.common.reflect.Reflection;
     38 import com.google.common.reflect.TypeToken;
     39 import com.google.common.testing.NullPointerTester.Visibility;
     40 import com.google.common.testing.RelationshipTester.Item;
     41 import com.google.common.testing.RelationshipTester.ItemReporter;
     42 
     43 import junit.framework.Assert;
     44 import junit.framework.AssertionFailedError;
     45 
     46 import java.io.Serializable;
     47 import java.lang.reflect.Constructor;
     48 import java.lang.reflect.InvocationTargetException;
     49 import java.lang.reflect.Method;
     50 import java.lang.reflect.Modifier;
     51 import java.util.Collection;
     52 import java.util.HashSet;
     53 import java.util.List;
     54 import java.util.Map;
     55 import java.util.Set;
     56 
     57 import javax.annotation.Nullable;
     58 
     59 /**
     60  * Tester that runs automated sanity tests for any given class. A typical use case is to test static
     61  * factory classes like: <pre>
     62  * interface Book {...}
     63  * public class Books {
     64  *   public static Book hardcover(String title) {...}
     65  *   public static Book paperback(String title) {...}
     66  * }
     67  * </pre>
     68  * <p>And all the created {@code Book} instances can be tested with: <pre>
     69  * new ClassSanityTester()
     70  *     .forAllPublicStaticMethods(Books.class)
     71  *     .thatReturn(Book.class)
     72  *     .testEquals(); // or testNulls(), testSerializable() etc.
     73  * </pre>
     74  *
     75  * @author Ben Yu
     76  * @since 14.0
     77  */
     78 @Beta
     79 public final class ClassSanityTester {
     80 
     81   private static final Ordering<Invokable<?, ?>> BY_METHOD_NAME =
     82       new Ordering<Invokable<?, ?>>() {
     83         @Override public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
     84           return left.getName().compareTo(right.getName());
     85         }
     86       };
     87 
     88   private static final Ordering<Invokable<?, ?>> BY_PARAMETERS =
     89       new Ordering<Invokable<?, ?>>() {
     90         @Override public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
     91           return Ordering.usingToString().compare(left.getParameters(), right.getParameters());
     92         }
     93       };
     94 
     95   private static final Ordering<Invokable<?, ?>> BY_NUMBER_OF_PARAMETERS =
     96       new Ordering<Invokable<?, ?>>() {
     97         @Override public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
     98           return Ints.compare(left.getParameters().size(), right.getParameters().size());
     99         }
    100       };
    101 
    102   private final MutableClassToInstanceMap<Object> defaultValues =
    103       MutableClassToInstanceMap.create();
    104   private final ListMultimap<Class<?>, Object> distinctValues = ArrayListMultimap.create();
    105   private final NullPointerTester nullPointerTester = new NullPointerTester();
    106 
    107   public ClassSanityTester() {
    108     // TODO(benyu): bake these into ArbitraryInstances.
    109     setDefault(byte.class, (byte) 1);
    110     setDefault(Byte.class, (byte) 1);
    111     setDefault(short.class, (short) 1);
    112     setDefault(Short.class, (short) 1);
    113     setDefault(int.class, 1);
    114     setDefault(Integer.class, 1);
    115     setDefault(long.class, 1L);
    116     setDefault(Long.class, 1L);
    117     setDefault(float.class, 1F);
    118     setDefault(Float.class, 1F);
    119     setDefault(double.class, 1D);
    120     setDefault(Double.class, 1D);
    121     setDefault(Class.class, Class.class);
    122   }
    123 
    124   /**
    125    * Sets the default value for {@code type}. The default value isn't used in testing {@link
    126    * Object#equals} because more than one sample instances are needed for testing inequality.
    127    * To set sample instances for equality testing, use {@link #setSampleInstances} instead.
    128    */
    129   public <T> ClassSanityTester setDefault(Class<T> type, T value) {
    130     nullPointerTester.setDefault(type, value);
    131     defaultValues.putInstance(type, value);
    132     return this;
    133   }
    134 
    135   /**
    136    * Sets sample instances for {@code type}, so that when a class {@code Foo} is tested for {@link
    137    * Object#equals} and {@link Object#hashCode}, and its construction requires a parameter of {@code
    138    * type}, the sample instances can be passed to create {@code Foo} instances that are unequal.
    139    *
    140    * <p>Used for types where {@link ClassSanityTester} doesn't already know how to instantiate
    141    * distinct values. It's usually necessary to add two unequal instances for each type, with the
    142    * exception that if the sample instance is to be passed to a {@link Nullable} parameter, one
    143    * non-null sample is sufficient. Setting an empty list will clear sample instances for {@code
    144    * type}.
    145 
    146    *
    147 
    148    * @deprecated Use {@link #setDistinctValues} instead.
    149    */
    150   @Deprecated
    151   public <T> ClassSanityTester setSampleInstances(Class<T> type, Iterable<? extends T> instances) {
    152     ImmutableList<? extends T> samples = ImmutableList.copyOf(instances);
    153     Set<Object> uniqueValues = new HashSet<Object>();
    154     for (T instance : instances) {
    155       checkArgument(uniqueValues.add(instance), "Duplicate value: %s", instance);
    156     }
    157     distinctValues.putAll(checkNotNull(type), samples);
    158     if (!samples.isEmpty()) {
    159       setDefault(type, samples.get(0));
    160     }
    161     return this;
    162   }
    163 
    164   /**
    165    * Sets distinct values for {@code type}, so that when a class {@code Foo} is tested for {@link
    166    * Object#equals} and {@link Object#hashCode}, and its construction requires a parameter of {@code
    167    * type}, the distinct values of {@code type} can be passed as parameters to create {@code Foo}
    168    * instances that are unequal.
    169    *
    170    * <p>Calling {@code setDistinctValues(type, v1, v2)} also sets the default value for {@code type}
    171    * that's used for {@link #testNulls}.
    172    *
    173    * <p>Only necessary for types where {@link ClassSanityTester} doesn't already know how to create
    174    * distinct values.
    175    *
    176    * @return this tester instance
    177    * @since 17.0
    178    */
    179   public <T> ClassSanityTester setDistinctValues(Class<T> type, T value1, T value2) {
    180     checkNotNull(type);
    181     checkNotNull(value1);
    182     checkNotNull(value2);
    183     checkArgument(!Objects.equal(value1, value2), "Duplicate value provided.");
    184     distinctValues.replaceValues(type, ImmutableList.of(value1, value2));
    185     setDefault(type, value1);
    186     return this;
    187   }
    188 
    189   /**
    190    * Tests that {@code cls} properly checks null on all constructor and method parameters that
    191    * aren't annotated with {@link Nullable}. In details:
    192    * <ul>
    193    * <li>All non-private static methods are checked such that passing null for any parameter that's
    194    *     not annotated with {@link javax.annotation.Nullable} should throw {@link
    195    *     NullPointerException}.
    196    * <li>If there is any non-private constructor or non-private static factory method declared by
    197    *     {@code cls}, all non-private instance methods will be checked too using the instance
    198    *     created by invoking the constructor or static factory method.
    199    * <li>If there is any non-private constructor or non-private static factory method declared by
    200    *     {@code cls}:
    201    *     <ul>
    202    *     <li>Test will fail if default value for a parameter cannot be determined.
    203    *     <li>Test will fail if the factory method returns null so testing instance methods is
    204    *         impossible.
    205    *     <li>Test will fail if the constructor or factory method throws exception.
    206    *     </ul>
    207    * <li>If there is no non-private constructor or non-private static factory method declared by
    208    *     {@code cls}, instance methods are skipped for nulls test.
    209    * <li>Nulls test is not performed on method return values unless the method is a non-private
    210    *     static factory method whose return type is {@code cls} or {@code cls}'s subtype.
    211    * </ul>
    212    */
    213   public void testNulls(Class<?> cls) {
    214     try {
    215       doTestNulls(cls, Visibility.PACKAGE);
    216     } catch (Exception e) {
    217       throw Throwables.propagate(e);
    218     }
    219   }
    220 
    221   void doTestNulls(Class<?> cls, Visibility visibility)
    222       throws ParameterNotInstantiableException, IllegalAccessException,
    223              InvocationTargetException, FactoryMethodReturnsNullException {
    224     if (!Modifier.isAbstract(cls.getModifiers())) {
    225       nullPointerTester.testConstructors(cls, visibility);
    226     }
    227     nullPointerTester.testStaticMethods(cls, visibility);
    228     if (hasInstanceMethodToTestNulls(cls, visibility)) {
    229       Object instance = instantiate(cls);
    230       if (instance != null) {
    231         nullPointerTester.testInstanceMethods(instance, visibility);
    232       }
    233     }
    234   }
    235 
    236   private boolean hasInstanceMethodToTestNulls(Class<?> c, Visibility visibility) {
    237     for (Method method : nullPointerTester.getInstanceMethodsToTest(c, visibility)) {
    238       for (Parameter param : Invokable.from(method).getParameters()) {
    239         if (!NullPointerTester.isPrimitiveOrNullable(param)) {
    240           return true;
    241         }
    242       }
    243     }
    244     return false;
    245   }
    246 
    247   /**
    248    * Tests the {@link Object#equals} and {@link Object#hashCode} of {@code cls}. In details:
    249    * <ul>
    250    * <li>The non-private constructor or non-private static factory method with the most parameters
    251    *     is used to construct the sample instances. In case of tie, the candidate constructors or
    252    *     factories are tried one after another until one can be used to construct sample instances.
    253    * <li>For the constructor or static factory method used to construct instances, it's checked that
    254    *     when equal parameters are passed, the result instance should also be equal; and vice versa.
    255    * <li>If a non-private constructor or non-private static factory method exists: <ul>
    256    *     <li>Test will fail if default value for a parameter cannot be determined.
    257    *     <li>Test will fail if the factory method returns null so testing instance methods is
    258    *         impossible.
    259    *     <li>Test will fail if the constructor or factory method throws exception.
    260    *     </ul>
    261    * <li>If there is no non-private constructor or non-private static factory method declared by
    262    *     {@code cls}, no test is performed.
    263    * <li>Equality test is not performed on method return values unless the method is a non-private
    264    *     static factory method whose return type is {@code cls} or {@code cls}'s subtype.
    265    * <li>Inequality check is not performed against state mutation methods such as {@link List#add},
    266    *     or functional update methods such as {@link com.google.common.base.Joiner#skipNulls}.
    267    * </ul>
    268    *
    269    * <p>Note that constructors taking a builder object cannot be tested effectively because
    270    * semantics of builder can be arbitrarily complex. Still, a factory class can be created in the
    271    * test to facilitate equality testing. For example: <pre>
    272    * public class FooTest {
    273    *
    274    *   private static class FooFactoryForTest {
    275    *     public static Foo create(String a, String b, int c, boolean d) {
    276    *       return Foo.builder()
    277    *           .setA(a)
    278    *           .setB(b)
    279    *           .setC(c)
    280    *           .setD(d)
    281    *           .build();
    282    *     }
    283    *   }
    284    *
    285    *   public void testEquals() {
    286    *     new ClassSanityTester()
    287    *       .forAllPublicStaticMethods(FooFactoryForTest.class)
    288    *       .thatReturn(Foo.class)
    289    *       .testEquals();
    290    *   }
    291    * }
    292    * </pre>
    293    * <p>It will test that Foo objects created by the {@code create(a, b, c, d)} factory method with
    294    * equal parameters are equal and vice versa, thus indirectly tests the builder equality.
    295    */
    296   public void testEquals(Class<?> cls) {
    297     try {
    298       doTestEquals(cls);
    299     } catch (Exception e) {
    300       throw Throwables.propagate(e);
    301     }
    302   }
    303 
    304   void doTestEquals(Class<?> cls)
    305       throws ParameterNotInstantiableException, ParameterHasNoDistinctValueException,
    306              IllegalAccessException, InvocationTargetException, FactoryMethodReturnsNullException {
    307     if (cls.isEnum()) {
    308       return;
    309     }
    310     List<? extends Invokable<?, ?>> factories = Lists.reverse(getFactories(TypeToken.of(cls)));
    311     if (factories.isEmpty()) {
    312       return;
    313     }
    314     int numberOfParameters = factories.get(0).getParameters().size();
    315     List<ParameterNotInstantiableException> paramErrors = Lists.newArrayList();
    316     List<ParameterHasNoDistinctValueException> distinctValueErrors = Lists.newArrayList();
    317     List<InvocationTargetException> instantiationExceptions = Lists.newArrayList();
    318     List<FactoryMethodReturnsNullException> nullErrors = Lists.newArrayList();
    319     // Try factories with the greatest number of parameters.
    320     for (Invokable<?, ?> factory : factories) {
    321       if (factory.getParameters().size() == numberOfParameters) {
    322         try {
    323           testEqualsUsing(factory);
    324           return;
    325         } catch (ParameterNotInstantiableException e) {
    326           paramErrors.add(e);
    327         } catch (ParameterHasNoDistinctValueException e) {
    328           distinctValueErrors.add(e);
    329         } catch (InvocationTargetException e) {
    330           instantiationExceptions.add(e);
    331         } catch (FactoryMethodReturnsNullException e) {
    332           nullErrors.add(e);
    333         }
    334       }
    335     }
    336     throwFirst(paramErrors);
    337     throwFirst(distinctValueErrors);
    338     throwFirst(instantiationExceptions);
    339     throwFirst(nullErrors);
    340   }
    341 
    342   /**
    343    * Instantiates {@code cls} by invoking one of its non-private constructors or non-private static
    344    * factory methods with the parameters automatically provided using dummy values.
    345    *
    346    * @return The instantiated instance, or {@code null} if the class has no non-private constructor
    347    *         or factory method to be constructed.
    348    */
    349   @Nullable <T> T instantiate(Class<T> cls)
    350       throws ParameterNotInstantiableException, IllegalAccessException,
    351              InvocationTargetException, FactoryMethodReturnsNullException {
    352     if (cls.isEnum()) {
    353       T[] constants = cls.getEnumConstants();
    354       if (constants.length > 0) {
    355         return constants[0];
    356       } else {
    357         return null;
    358       }
    359     }
    360     TypeToken<T> type = TypeToken.of(cls);
    361     List<ParameterNotInstantiableException> paramErrors = Lists.newArrayList();
    362     List<InvocationTargetException> instantiationExceptions = Lists.newArrayList();
    363     List<FactoryMethodReturnsNullException> nullErrors = Lists.newArrayList();
    364     for (Invokable<?, ? extends T> factory : getFactories(type)) {
    365       T instance;
    366       try {
    367         instance = instantiate(factory);
    368       } catch (ParameterNotInstantiableException e) {
    369         paramErrors.add(e);
    370         continue;
    371       } catch (InvocationTargetException e) {
    372         instantiationExceptions.add(e);
    373         continue;
    374       }
    375       if (instance == null) {
    376         nullErrors.add(new FactoryMethodReturnsNullException(factory));
    377       } else {
    378         return instance;
    379       }
    380     }
    381     throwFirst(paramErrors);
    382     throwFirst(instantiationExceptions);
    383     throwFirst(nullErrors);
    384     return null;
    385   }
    386 
    387   /**
    388    * Returns an object responsible for performing sanity tests against the return values
    389    * of all public static methods declared by {@code cls}, excluding superclasses.
    390    */
    391   public FactoryMethodReturnValueTester forAllPublicStaticMethods(Class<?> cls) {
    392     ImmutableList.Builder<Invokable<?, ?>> builder = ImmutableList.builder();
    393     for (Method method : cls.getDeclaredMethods()) {
    394       Invokable<?, ?> invokable = Invokable.from(method);
    395       invokable.setAccessible(true);
    396       if (invokable.isPublic() && invokable.isStatic() && !invokable.isSynthetic()) {
    397         builder.add(invokable);
    398       }
    399     }
    400     return new FactoryMethodReturnValueTester(cls, builder.build(), "public static methods");
    401   }
    402 
    403   /** Runs sanity tests against return values of static factory methods declared by a class. */
    404   public final class FactoryMethodReturnValueTester {
    405     private final Set<String> packagesToTest = Sets.newHashSet();
    406     private final Class<?> declaringClass;
    407     private final ImmutableList<Invokable<?, ?>> factories;
    408     private final String factoryMethodsDescription;
    409     private Class<?> returnTypeToTest = Object.class;
    410 
    411     private FactoryMethodReturnValueTester(
    412         Class<?> declaringClass,
    413         ImmutableList<Invokable<?, ?>> factories,
    414         String factoryMethodsDescription) {
    415       this.declaringClass = declaringClass;
    416       this.factories = factories;
    417       this.factoryMethodsDescription = factoryMethodsDescription;
    418       packagesToTest.add(Reflection.getPackageName(declaringClass));
    419     }
    420 
    421     /**
    422      * Specifies that only the methods that are declared to return {@code returnType} or its subtype
    423      * are tested.
    424      *
    425      * @return this tester object
    426      */
    427     public FactoryMethodReturnValueTester thatReturn(Class<?> returnType) {
    428       this.returnTypeToTest = returnType;
    429       return this;
    430     }
    431 
    432     /**
    433      * Tests null checks against the instance methods of the return values, if any.
    434      *
    435      * <p>Test fails if default value cannot be determined for a constructor or factory method
    436      * parameter, or if the constructor or factory method throws exception.
    437      *
    438      * @return this tester
    439      */
    440     public FactoryMethodReturnValueTester testNulls() throws Exception {
    441       for (Invokable<?, ?> factory : getFactoriesToTest()) {
    442         Object instance = instantiate(factory);
    443         if (instance != null
    444             && packagesToTest.contains(Reflection.getPackageName(instance.getClass()))) {
    445           try {
    446             nullPointerTester.testAllPublicInstanceMethods(instance);
    447           } catch (AssertionError e) {
    448             AssertionError error = new AssertionFailedError(
    449                 "Null check failed on return value of " + factory);
    450             error.initCause(e);
    451             throw error;
    452           }
    453         }
    454       }
    455       return this;
    456     }
    457 
    458     /**
    459      * Tests {@link Object#equals} and {@link Object#hashCode} against the return values of the
    460      * static methods, by asserting that when equal parameters are passed to the same static method,
    461      * the return value should also be equal; and vice versa.
    462      *
    463      * <p>Test fails if default value cannot be determined for a constructor or factory method
    464      * parameter, or if the constructor or factory method throws exception.
    465      *
    466      * @return this tester
    467      */
    468     public FactoryMethodReturnValueTester testEquals() throws Exception {
    469       for (Invokable<?, ?> factory : getFactoriesToTest()) {
    470         try {
    471           testEqualsUsing(factory);
    472         } catch (FactoryMethodReturnsNullException e) {
    473           // If the factory returns null, we just skip it.
    474         }
    475       }
    476       return this;
    477     }
    478 
    479     /**
    480      * Runs serialization test on the return values of the static methods.
    481      *
    482      * <p>Test fails if default value cannot be determined for a constructor or factory method
    483      * parameter, or if the constructor or factory method throws exception.
    484      *
    485      * @return this tester
    486      */
    487     public FactoryMethodReturnValueTester testSerializable() throws Exception {
    488       for (Invokable<?, ?> factory : getFactoriesToTest()) {
    489         Object instance = instantiate(factory);
    490         if (instance != null) {
    491           try {
    492             SerializableTester.reserialize(instance);
    493           } catch (RuntimeException e) {
    494             AssertionError error = new AssertionFailedError(
    495                 "Serialization failed on return value of " + factory);
    496             error.initCause(e.getCause());
    497             throw error;
    498           }
    499         }
    500       }
    501       return this;
    502     }
    503 
    504     /**
    505      * Runs equals and serialization test on the return values.
    506      *
    507      * <p>Test fails if default value cannot be determined for a constructor or factory method
    508      * parameter, or if the constructor or factory method throws exception.
    509      *
    510      * @return this tester
    511      */
    512     public FactoryMethodReturnValueTester testEqualsAndSerializable() throws Exception {
    513       for (Invokable<?, ?> factory : getFactoriesToTest()) {
    514         try {
    515           testEqualsUsing(factory);
    516         } catch (FactoryMethodReturnsNullException e) {
    517           // If the factory returns null, we just skip it.
    518         }
    519         Object instance = instantiate(factory);
    520         if (instance != null) {
    521           try {
    522             SerializableTester.reserializeAndAssert(instance);
    523           } catch (RuntimeException e) {
    524             AssertionError error = new AssertionFailedError(
    525                 "Serialization failed on return value of " + factory);
    526             error.initCause(e.getCause());
    527             throw error;
    528           } catch (AssertionFailedError e) {
    529             AssertionError error = new AssertionFailedError(
    530                 "Return value of " + factory + " reserialized to an unequal value");
    531             error.initCause(e);
    532             throw error;
    533           }
    534         }
    535       }
    536       return this;
    537     }
    538 
    539     private ImmutableList<Invokable<?, ?>> getFactoriesToTest() {
    540       ImmutableList.Builder<Invokable<?, ?>> builder = ImmutableList.builder();
    541       for (Invokable<?, ?> factory : factories) {
    542         if (returnTypeToTest.isAssignableFrom(factory.getReturnType().getRawType())) {
    543           builder.add(factory);
    544         }
    545       }
    546       ImmutableList<Invokable<?, ?>> factoriesToTest = builder.build();
    547       Assert.assertFalse("No " + factoryMethodsDescription + " that return "
    548               + returnTypeToTest.getName() + " or subtype are found in "
    549               + declaringClass + ".",
    550           factoriesToTest.isEmpty());
    551       return factoriesToTest;
    552     }
    553   }
    554 
    555   /**
    556    * Instantiates using {@code factory}. If {@code factory} is annotated with {@link Nullable} and
    557    * returns null, null will be returned.
    558    *
    559    * @throws ParameterNotInstantiableException if the static methods cannot be invoked because
    560    *         the default value of a parameter cannot be determined.
    561    * @throws IllegalAccessException if the class isn't public or is nested inside a non-public
    562    *         class, preventing its methods from being accessible.
    563    * @throws InvocationTargetException if a static method threw exception.
    564    */
    565   @Nullable private <T> T instantiate(Invokable<?, ? extends T> factory)
    566       throws ParameterNotInstantiableException, InvocationTargetException,
    567       IllegalAccessException {
    568     return invoke(factory, getDummyArguments(factory));
    569   }
    570 
    571   private void testEqualsUsing(final Invokable<?, ?> factory)
    572 
    573       throws ParameterNotInstantiableException, ParameterHasNoDistinctValueException,
    574              IllegalAccessException, InvocationTargetException, FactoryMethodReturnsNullException {
    575     List<Parameter> params = factory.getParameters();
    576     List<FreshValueGenerator> argGenerators = Lists.newArrayListWithCapacity(params.size());
    577     List<Object> args = Lists.newArrayListWithCapacity(params.size());
    578     for (Parameter param : params) {
    579       FreshValueGenerator generator = newFreshValueGenerator();
    580       argGenerators.add(generator);
    581       args.add(generateDummyArg(param, generator));
    582     }
    583     Object instance = createInstance(factory, args);
    584     List<Object> equalArgs = generateEqualFactoryArguments(factory, params, args);
    585     // Each group is a List of items, each item has a list of factory args.
    586     final List<List<List<Object>>> argGroups = Lists.newArrayList();
    587     argGroups.add(ImmutableList.of(args, equalArgs));
    588     EqualsTester tester = new EqualsTester(new ItemReporter() {
    589       @Override String reportItem(Item<?> item) {
    590         List<Object> factoryArgs = argGroups.get(item.groupNumber).get(item.itemNumber);
    591         return factory.getName() + "(" + Joiner.on(", ").useForNull("null").join(factoryArgs) + ")";
    592       }
    593     });
    594     tester.addEqualityGroup(instance, createInstance(factory, equalArgs));
    595     for (int i = 0; i < params.size(); i++) {
    596       List<Object> newArgs = Lists.newArrayList(args);
    597       Object newArg = argGenerators.get(i).generate(params.get(i).getType());
    598 
    599       if (newArg == null || Objects.equal(args.get(i), newArg)) {
    600         if (params.get(i).getType().getRawType().isEnum()) {
    601           continue; // Nothing better we can do if it's single-value enum
    602         }
    603         throw new ParameterHasNoDistinctValueException(params.get(i));
    604       }
    605       newArgs.set(i, newArg);
    606       tester.addEqualityGroup(createInstance(factory, newArgs));
    607       argGroups.add(ImmutableList.of(newArgs));
    608     }
    609     tester.testEquals();
    610   }
    611 
    612   /**
    613    * Returns dummy factory arguments that are equal to {@code args} but may be different instances,
    614    * to be used to construct a second instance of the same equality group.
    615    */
    616   private List<Object> generateEqualFactoryArguments(
    617       Invokable<?, ?> factory, List<Parameter> params, List<Object> args)
    618       throws ParameterNotInstantiableException, FactoryMethodReturnsNullException,
    619       InvocationTargetException, IllegalAccessException {
    620     List<Object> equalArgs = Lists.newArrayList(args);
    621     for (int i = 0; i < args.size(); i++) {
    622       Parameter param = params.get(i);
    623       Object arg = args.get(i);
    624       // Use new fresh value generator because 'args' were populated with new fresh generator each.
    625       // Two newFreshValueGenerator() instances should normally generate equal value sequence.
    626       Object shouldBeEqualArg = generateDummyArg(param, newFreshValueGenerator());
    627       if (arg != shouldBeEqualArg
    628           && Objects.equal(arg, shouldBeEqualArg)
    629           && hashCodeInsensitiveToArgReference(factory, args, i, shouldBeEqualArg)
    630           && hashCodeInsensitiveToArgReference(
    631               factory, args, i, generateDummyArg(param, newFreshValueGenerator()))) {
    632         // If the implementation uses identityHashCode(), referential equality is
    633         // probably intended. So no point in using an equal-but-different factory argument.
    634         // We check twice to avoid confusion caused by accidental hash collision.
    635         equalArgs.set(i, shouldBeEqualArg);
    636       }
    637     }
    638     return equalArgs;
    639   }
    640 
    641   private static boolean hashCodeInsensitiveToArgReference(
    642       Invokable<?, ?> factory, List<Object> args, int i, Object alternateArg)
    643       throws FactoryMethodReturnsNullException, InvocationTargetException, IllegalAccessException {
    644     List<Object> tentativeArgs = Lists.newArrayList(args);
    645     tentativeArgs.set(i, alternateArg);
    646     return createInstance(factory, tentativeArgs).hashCode()
    647         == createInstance(factory, args).hashCode();
    648   }
    649 
    650   // distinctValues is a type-safe class-values mapping, but we don't have a type-safe data
    651   // structure to hold the mappings.
    652   @SuppressWarnings({"unchecked", "rawtypes"})
    653   private FreshValueGenerator newFreshValueGenerator() {
    654     FreshValueGenerator generator = new FreshValueGenerator() {
    655       @Override Object interfaceMethodCalled(Class<?> interfaceType, Method method) {
    656         return getDummyValue(TypeToken.of(interfaceType).method(method).getReturnType());
    657       }
    658     };
    659     for (Map.Entry<Class<?>, Collection<Object>> entry : distinctValues.asMap().entrySet()) {
    660       generator.addSampleInstances((Class) entry.getKey(), entry.getValue());
    661     }
    662     return generator;
    663   }
    664 
    665   private static @Nullable Object generateDummyArg(Parameter param, FreshValueGenerator generator)
    666       throws ParameterNotInstantiableException {
    667     if (param.isAnnotationPresent(Nullable.class)) {
    668       return null;
    669     }
    670     Object arg = generator.generate(param.getType());
    671     if (arg == null) {
    672       throw new ParameterNotInstantiableException(param);
    673     }
    674     return arg;
    675   }
    676 
    677   private static <X extends Throwable> void throwFirst(List<X> exceptions) throws X {
    678     if (!exceptions.isEmpty()) {
    679       throw exceptions.get(0);
    680     }
    681   }
    682 
    683   /** Factories with the least number of parameters are listed first. */
    684   private static <T> ImmutableList<Invokable<?, ? extends T>> getFactories(TypeToken<T> type) {
    685     List<Invokable<?, ? extends T>> factories = Lists.newArrayList();
    686     for (Method method : type.getRawType().getDeclaredMethods()) {
    687       Invokable<?, ?> invokable = type.method(method);
    688       if (!invokable.isPrivate()
    689           && !invokable.isSynthetic()
    690           && invokable.isStatic()
    691           && type.isAssignableFrom(invokable.getReturnType())) {
    692         @SuppressWarnings("unchecked") // guarded by isAssignableFrom()
    693         Invokable<?, ? extends T> factory = (Invokable<?, ? extends T>) invokable;
    694         factories.add(factory);
    695       }
    696     }
    697     if (!Modifier.isAbstract(type.getRawType().getModifiers())) {
    698       for (Constructor<?> constructor : type.getRawType().getDeclaredConstructors()) {
    699         Invokable<T, T> invokable = type.constructor(constructor);
    700         if (!invokable.isPrivate() && !invokable.isSynthetic()) {
    701           factories.add(invokable);
    702         }
    703       }
    704     }
    705     for (Invokable<?, ?> factory : factories) {
    706       factory.setAccessible(true);
    707     }
    708     // Sorts methods/constructors with least number of parameters first since it's likely easier to
    709     // fill dummy parameter values for them. Ties are broken by name then by the string form of the
    710     // parameter list.
    711     return BY_NUMBER_OF_PARAMETERS.compound(BY_METHOD_NAME).compound(BY_PARAMETERS)
    712         .immutableSortedCopy(factories);
    713   }
    714 
    715   private List<Object> getDummyArguments(Invokable<?, ?> invokable)
    716       throws ParameterNotInstantiableException {
    717     List<Object> args = Lists.newArrayList();
    718     for (Parameter param : invokable.getParameters()) {
    719       if (param.isAnnotationPresent(Nullable.class)) {
    720         args.add(null);
    721         continue;
    722       }
    723       Object defaultValue = getDummyValue(param.getType());
    724       if (defaultValue == null) {
    725         throw new ParameterNotInstantiableException(param);
    726       }
    727       args.add(defaultValue);
    728     }
    729     return args;
    730   }
    731 
    732   private <T> T getDummyValue(TypeToken<T> type) {
    733     Class<? super T> rawType = type.getRawType();
    734     @SuppressWarnings("unchecked") // Assume all default values are generics safe.
    735     T defaultValue = (T) defaultValues.getInstance(rawType);
    736     if (defaultValue != null) {
    737       return defaultValue;
    738     }
    739     @SuppressWarnings("unchecked") // ArbitraryInstances always returns generics-safe dummies.
    740     T value = (T) ArbitraryInstances.get(rawType);
    741     if (value != null) {
    742       return value;
    743     }
    744     if (rawType.isInterface()) {
    745       return new SerializableDummyProxy(this).newProxy(type);
    746     }
    747     return null;
    748   }
    749 
    750   private static <T> T createInstance(Invokable<?, ? extends T> factory, List<?> args)
    751       throws FactoryMethodReturnsNullException, InvocationTargetException, IllegalAccessException {
    752     T instance = invoke(factory, args);
    753     if (instance == null) {
    754       throw new FactoryMethodReturnsNullException(factory);
    755     }
    756     return instance;
    757   }
    758 
    759   @Nullable private static <T> T invoke(Invokable<?, ? extends T> factory, List<?> args)
    760       throws InvocationTargetException, IllegalAccessException {
    761     T returnValue = factory.invoke(null, args.toArray());
    762     if (returnValue == null) {
    763       Assert.assertTrue(factory + " returns null but it's not annotated with @Nullable",
    764           factory.isAnnotationPresent(Nullable.class));
    765     }
    766     return returnValue;
    767   }
    768 
    769   /**
    770    * Thrown if the test tries to invoke a constructor or static factory method but failed because
    771    * the dummy value of a constructor or method parameter is unknown.
    772    */
    773   @VisibleForTesting static class ParameterNotInstantiableException extends Exception {
    774     public ParameterNotInstantiableException(Parameter parameter) {
    775       super("Cannot determine value for parameter " + parameter
    776           + " of " + parameter.getDeclaringInvokable());
    777     }
    778   }
    779 
    780   /**
    781    * Thrown if the test fails to generate two distinct non-null values of a constructor or factory
    782    * parameter in order to test {@link Object#equals} and {@link Object#hashCode} of the declaring
    783    * class.
    784    */
    785   @VisibleForTesting static class ParameterHasNoDistinctValueException extends Exception {
    786     ParameterHasNoDistinctValueException(Parameter parameter) {
    787         super("Cannot generate distinct value for parameter " + parameter
    788             + " of " + parameter.getDeclaringInvokable());
    789     }
    790   }
    791 
    792   /**
    793    * Thrown if the test tries to invoke a static factory method to test instance methods but the
    794    * factory returned null.
    795    */
    796   @VisibleForTesting static class FactoryMethodReturnsNullException extends Exception {
    797     public FactoryMethodReturnsNullException(Invokable<?, ?> factory) {
    798       super(factory + " returns null and cannot be used to test instance methods.");
    799     }
    800   }
    801 
    802   private static final class SerializableDummyProxy extends DummyProxy
    803       implements Serializable {
    804 
    805     private transient final ClassSanityTester tester;
    806 
    807     SerializableDummyProxy(ClassSanityTester tester) {
    808       this.tester = tester;
    809     }
    810 
    811     @Override <R> R dummyReturnValue(TypeToken<R> returnType) {
    812       return tester.getDummyValue(returnType);
    813     }
    814 
    815     @Override public boolean equals(Object obj) {
    816       return obj instanceof SerializableDummyProxy;
    817     }
    818 
    819     @Override public int hashCode() {
    820       return 0;
    821     }
    822   }
    823 }
    824 
    825