001/*
002 * Copyright (C) 2012 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.testing;
018
019import static com.google.common.base.Preconditions.checkArgument;
020import static com.google.common.base.Preconditions.checkNotNull;
021import static com.google.common.base.Throwables.throwIfUnchecked;
022import static com.google.common.testing.NullPointerTester.isNullable;
023
024import com.google.common.annotations.GwtIncompatible;
025import com.google.common.annotations.J2ktIncompatible;
026import com.google.common.annotations.VisibleForTesting;
027import com.google.common.base.Joiner;
028import com.google.common.base.Objects;
029import com.google.common.collect.ArrayListMultimap;
030import com.google.common.collect.ImmutableList;
031import com.google.common.collect.ListMultimap;
032import com.google.common.collect.Lists;
033import com.google.common.collect.MutableClassToInstanceMap;
034import com.google.common.collect.Ordering;
035import com.google.common.collect.Sets;
036import com.google.common.reflect.Invokable;
037import com.google.common.reflect.Parameter;
038import com.google.common.reflect.Reflection;
039import com.google.common.reflect.TypeToken;
040import com.google.common.testing.NullPointerTester.Visibility;
041import com.google.common.testing.RelationshipTester.Item;
042import com.google.common.testing.RelationshipTester.ItemReporter;
043import com.google.errorprone.annotations.CanIgnoreReturnValue;
044import java.io.Serializable;
045import java.lang.reflect.Constructor;
046import java.lang.reflect.InvocationTargetException;
047import java.lang.reflect.Method;
048import java.lang.reflect.Modifier;
049import java.util.Collection;
050import java.util.List;
051import java.util.Map.Entry;
052import java.util.Set;
053import junit.framework.Assert;
054import junit.framework.AssertionFailedError;
055import org.jspecify.annotations.NullUnmarked;
056import org.jspecify.annotations.Nullable;
057
058/**
059 * Tester that runs automated sanity tests for any given class. A typical use case is to test static
060 * factory classes like:
061 *
062 * <pre>
063 * interface Book {...}
064 * public class Books {
065 *   public static Book hardcover(String title) {...}
066 *   public static Book paperback(String title) {...}
067 * }
068 * </pre>
069 *
070 * <p>And all the created {@code Book} instances can be tested with:
071 *
072 * <pre>
073 * new ClassSanityTester()
074 *     .forAllPublicStaticMethods(Books.class)
075 *     .thatReturn(Book.class)
076 *     .testEquals(); // or testNulls(), testSerializable() etc.
077 * </pre>
078 *
079 * @author Ben Yu
080 * @since 14.0
081 */
082@GwtIncompatible
083@J2ktIncompatible
084@NullUnmarked
085@SuppressWarnings("nullness")
086public final class ClassSanityTester {
087
088  private static final Ordering<Invokable<?, ?>> BY_METHOD_NAME =
089      new Ordering<Invokable<?, ?>>() {
090        @Override
091        public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
092          return left.getName().compareTo(right.getName());
093        }
094      };
095
096  private static final Ordering<Invokable<?, ?>> BY_PARAMETERS =
097      new Ordering<Invokable<?, ?>>() {
098        @Override
099        public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
100          return Ordering.usingToString().compare(left.getParameters(), right.getParameters());
101        }
102      };
103
104  private static final Ordering<Invokable<?, ?>> BY_NUMBER_OF_PARAMETERS =
105      new Ordering<Invokable<?, ?>>() {
106        @Override
107        public int compare(Invokable<?, ?> left, Invokable<?, ?> right) {
108          return Integer.compare(left.getParameters().size(), right.getParameters().size());
109        }
110      };
111
112  private final MutableClassToInstanceMap<Object> defaultValues =
113      MutableClassToInstanceMap.create();
114  private final ListMultimap<Class<?>, Object> distinctValues = ArrayListMultimap.create();
115  private final NullPointerTester nullPointerTester = new NullPointerTester();
116
117  public ClassSanityTester() {
118    // TODO(benyu): bake these into ArbitraryInstances.
119    setDefault(byte.class, (byte) 1);
120    setDefault(Byte.class, (byte) 1);
121    setDefault(short.class, (short) 1);
122    setDefault(Short.class, (short) 1);
123    setDefault(int.class, 1);
124    setDefault(Integer.class, 1);
125    setDefault(long.class, 1L);
126    setDefault(Long.class, 1L);
127    setDefault(float.class, 1F);
128    setDefault(Float.class, 1F);
129    setDefault(double.class, 1D);
130    setDefault(Double.class, 1D);
131    setDefault(Class.class, Class.class);
132  }
133
134  /**
135   * Sets the default value for {@code type}. The default value isn't used in testing {@link
136   * Object#equals} because more than one sample instances are needed for testing inequality. To set
137   * distinct values for equality testing, use {@link #setDistinctValues} instead.
138   */
139  @CanIgnoreReturnValue
140  public <T> ClassSanityTester setDefault(Class<T> type, T value) {
141    nullPointerTester.setDefault(type, value);
142    defaultValues.putInstance(type, value);
143    return this;
144  }
145
146  /**
147   * Sets distinct values for {@code type}, so that when a class {@code Foo} is tested for {@link
148   * Object#equals} and {@link Object#hashCode}, and its construction requires a parameter of {@code
149   * type}, the distinct values of {@code type} can be passed as parameters to create {@code Foo}
150   * instances that are unequal.
151   *
152   * <p>Calling {@code setDistinctValues(type, v1, v2)} also sets the default value for {@code type}
153   * that's used for {@link #testNulls}.
154   *
155   * <p>Only necessary for types where {@link ClassSanityTester} doesn't already know how to create
156   * distinct values.
157   *
158   * @return this tester instance
159   * @since 17.0
160   */
161  @CanIgnoreReturnValue
162  public <T> ClassSanityTester setDistinctValues(Class<T> type, T value1, T value2) {
163    checkNotNull(type);
164    checkNotNull(value1);
165    checkNotNull(value2);
166    checkArgument(!Objects.equal(value1, value2), "Duplicate value provided.");
167    distinctValues.replaceValues(type, ImmutableList.of(value1, value2));
168    setDefault(type, value1);
169    return this;
170  }
171
172  /**
173   * Tests that {@code cls} properly checks null on all constructor and method parameters that
174   * aren't annotated nullable (according to the rules of {@link NullPointerTester}). In details:
175   *
176   * <ul>
177   *   <li>All non-private static methods are checked such that passing null for any parameter
178   *       that's not annotated nullable should throw {@link NullPointerException}.
179   *   <li>If there is any non-private constructor or non-private static factory method declared by
180   *       {@code cls}, all non-private instance methods will be checked too using the instance
181   *       created by invoking the constructor or static factory method.
182   *   <li>If there is any non-private constructor or non-private static factory method declared by
183   *       {@code cls}:
184   *       <ul>
185   *         <li>Test will fail if default value for a parameter cannot be determined.
186   *         <li>Test will fail if the factory method returns null so testing instance methods is
187   *             impossible.
188   *         <li>Test will fail if the constructor or factory method throws exception.
189   *       </ul>
190   *   <li>If there is no non-private constructor or non-private static factory method declared by
191   *       {@code cls}, instance methods are skipped for nulls test.
192   *   <li>Nulls test is not performed on method return values unless the method is a non-private
193   *       static factory method whose return type is {@code cls} or {@code cls}'s subtype.
194   * </ul>
195   */
196  public void testNulls(Class<?> cls) {
197    try {
198      doTestNulls(cls, Visibility.PACKAGE);
199    } catch (Exception e) {
200      throwIfUnchecked(e);
201      throw new RuntimeException(e);
202    }
203  }
204
205  void doTestNulls(Class<?> cls, Visibility visibility)
206      throws ParameterNotInstantiableException,
207          IllegalAccessException,
208          InvocationTargetException,
209          FactoryMethodReturnsNullException {
210    if (!Modifier.isAbstract(cls.getModifiers())) {
211      nullPointerTester.testConstructors(cls, visibility);
212    }
213    nullPointerTester.testStaticMethods(cls, visibility);
214    if (hasInstanceMethodToTestNulls(cls, visibility)) {
215      Object instance = instantiate(cls);
216      if (instance != null) {
217        nullPointerTester.testInstanceMethods(instance, visibility);
218      }
219    }
220  }
221
222  private boolean hasInstanceMethodToTestNulls(Class<?> c, Visibility visibility) {
223    for (Method method : nullPointerTester.getInstanceMethodsToTest(c, visibility)) {
224      for (Parameter param : Invokable.from(method).getParameters()) {
225        if (!NullPointerTester.isPrimitiveOrNullable(param)) {
226          return true;
227        }
228      }
229    }
230    return false;
231  }
232
233  /**
234   * Tests the {@link Object#equals} and {@link Object#hashCode} of {@code cls}. In details:
235   *
236   * <ul>
237   *   <li>The non-private constructor or non-private static factory method with the most parameters
238   *       is used to construct the sample instances. In case of tie, the candidate constructors or
239   *       factories are tried one after another until one can be used to construct sample
240   *       instances.
241   *   <li>For the constructor or static factory method used to construct instances, it's checked
242   *       that when equal parameters are passed, the result instance should also be equal; and vice
243   *       versa.
244   *   <li>If a non-private constructor or non-private static factory method exists:
245   *       <ul>
246   *         <li>Test will fail if default value for a parameter cannot be determined.
247   *         <li>Test will fail if the factory method returns null so testing instance methods is
248   *             impossible.
249   *         <li>Test will fail if the constructor or factory method throws exception.
250   *       </ul>
251   *   <li>If there is no non-private constructor or non-private static factory method declared by
252   *       {@code cls}, no test is performed.
253   *   <li>Equality test is not performed on method return values unless the method is a non-private
254   *       static factory method whose return type is {@code cls} or {@code cls}'s subtype.
255   *   <li>Inequality check is not performed against state mutation methods such as {@link
256   *       List#add}, or functional update methods such as {@link
257   *       com.google.common.base.Joiner#skipNulls}.
258   * </ul>
259   *
260   * <p>Note that constructors taking a builder object cannot be tested effectively because
261   * semantics of builder can be arbitrarily complex. Still, a factory class can be created in the
262   * test to facilitate equality testing. For example:
263   *
264   * <pre>
265   * public class FooTest {
266   *
267   *   private static class FooFactoryForTest {
268   *     public static Foo create(String a, String b, int c, boolean d) {
269   *       return Foo.builder()
270   *           .setA(a)
271   *           .setB(b)
272   *           .setC(c)
273   *           .setD(d)
274   *           .build();
275   *     }
276   *   }
277   *
278   *   public void testEquals() {
279   *     new ClassSanityTester()
280   *       .forAllPublicStaticMethods(FooFactoryForTest.class)
281   *       .thatReturn(Foo.class)
282   *       .testEquals();
283   *   }
284   * }
285   * </pre>
286   *
287   * <p>It will test that Foo objects created by the {@code create(a, b, c, d)} factory method with
288   * equal parameters are equal and vice versa, thus indirectly tests the builder equality.
289   */
290  public void testEquals(Class<?> cls) {
291    try {
292      doTestEquals(cls);
293    } catch (Exception e) {
294      throwIfUnchecked(e);
295      throw new RuntimeException(e);
296    }
297  }
298
299  void doTestEquals(Class<?> cls)
300      throws ParameterNotInstantiableException,
301          ParameterHasNoDistinctValueException,
302          IllegalAccessException,
303          InvocationTargetException,
304          FactoryMethodReturnsNullException {
305    if (cls.isEnum()) {
306      return;
307    }
308    List<? extends Invokable<?, ?>> factories = Lists.reverse(getFactories(TypeToken.of(cls)));
309    if (factories.isEmpty()) {
310      return;
311    }
312    int numberOfParameters = factories.get(0).getParameters().size();
313    List<ParameterNotInstantiableException> paramErrors = Lists.newArrayList();
314    List<ParameterHasNoDistinctValueException> distinctValueErrors = Lists.newArrayList();
315    List<InvocationTargetException> instantiationExceptions = Lists.newArrayList();
316    List<FactoryMethodReturnsNullException> nullErrors = Lists.newArrayList();
317    // Try factories with the greatest number of parameters.
318    for (Invokable<?, ?> factory : factories) {
319      if (factory.getParameters().size() == numberOfParameters) {
320        try {
321          testEqualsUsing(factory);
322          return;
323        } catch (ParameterNotInstantiableException e) {
324          paramErrors.add(e);
325        } catch (ParameterHasNoDistinctValueException e) {
326          distinctValueErrors.add(e);
327        } catch (InvocationTargetException e) {
328          instantiationExceptions.add(e);
329        } catch (FactoryMethodReturnsNullException e) {
330          nullErrors.add(e);
331        }
332      }
333    }
334    throwFirst(paramErrors);
335    throwFirst(distinctValueErrors);
336    throwFirst(instantiationExceptions);
337    throwFirst(nullErrors);
338  }
339
340  /**
341   * Instantiates {@code cls} by invoking one of its non-private constructors or non-private static
342   * factory methods with the parameters automatically provided using dummy values.
343   *
344   * @return The instantiated instance, or {@code null} if the class has no non-private constructor
345   *     or factory method to be constructed.
346   */
347  <T> @Nullable T instantiate(Class<T> cls)
348      throws ParameterNotInstantiableException,
349          IllegalAccessException,
350          InvocationTargetException,
351          FactoryMethodReturnsNullException {
352    if (cls.isEnum()) {
353      T[] constants = cls.getEnumConstants();
354      if (constants != null && 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   * Instantiates using {@code factory}. If {@code factory} is annotated nullable and returns null,
389   * null will be returned.
390   *
391   * @throws ParameterNotInstantiableException if the static methods cannot be invoked because the
392   *     default value of a parameter cannot be determined.
393   * @throws IllegalAccessException if the class isn't public or is nested inside a non-public
394   *     class, preventing its methods from being accessible.
395   * @throws InvocationTargetException if a static method threw exception.
396   */
397  private <T> @Nullable T instantiate(Invokable<?, ? extends T> factory)
398      throws ParameterNotInstantiableException, InvocationTargetException, IllegalAccessException {
399    return invoke(factory, getDummyArguments(factory));
400  }
401
402  /**
403   * Returns an object responsible for performing sanity tests against the return values of all
404   * public static methods declared by {@code cls}, excluding superclasses.
405   */
406  public FactoryMethodReturnValueTester forAllPublicStaticMethods(Class<?> cls) {
407    ImmutableList.Builder<Invokable<?, ?>> builder = ImmutableList.builder();
408    for (Method method : cls.getDeclaredMethods()) {
409      Invokable<?, ?> invokable = Invokable.from(method);
410      invokable.setAccessible(true);
411      if (invokable.isPublic() && invokable.isStatic() && !invokable.isSynthetic()) {
412        builder.add(invokable);
413      }
414    }
415    return new FactoryMethodReturnValueTester(cls, builder.build(), "public static methods");
416  }
417
418  /** Runs sanity tests against return values of static factory methods declared by a class. */
419  public final class FactoryMethodReturnValueTester {
420    private final Set<String> packagesToTest = Sets.newHashSet();
421    private final Class<?> declaringClass;
422    private final ImmutableList<Invokable<?, ?>> factories;
423    private final String factoryMethodsDescription;
424    private Class<?> returnTypeToTest = Object.class;
425
426    private FactoryMethodReturnValueTester(
427        Class<?> declaringClass,
428        ImmutableList<Invokable<?, ?>> factories,
429        String factoryMethodsDescription) {
430      this.declaringClass = declaringClass;
431      this.factories = factories;
432      this.factoryMethodsDescription = factoryMethodsDescription;
433      packagesToTest.add(Reflection.getPackageName(declaringClass));
434    }
435
436    /**
437     * Specifies that only the methods that are declared to return {@code returnType} or its subtype
438     * are tested.
439     *
440     * @return this tester object
441     */
442    @CanIgnoreReturnValue
443    public FactoryMethodReturnValueTester thatReturn(Class<?> returnType) {
444      this.returnTypeToTest = returnType;
445      return this;
446    }
447
448    /**
449     * Tests null checks against the instance methods of the return values, if any.
450     *
451     * <p>Test fails if default value cannot be determined for a constructor or factory method
452     * parameter, or if the constructor or factory method throws exception.
453     *
454     * @return this tester
455     */
456    @CanIgnoreReturnValue
457    public FactoryMethodReturnValueTester testNulls() throws Exception {
458      for (Invokable<?, ?> factory : getFactoriesToTest()) {
459        Object instance = instantiate(factory);
460        if (instance != null
461            && packagesToTest.contains(Reflection.getPackageName(instance.getClass()))) {
462          try {
463            nullPointerTester.testAllPublicInstanceMethods(instance);
464          } catch (AssertionError e) {
465            throw new AssertionError("Null check failed on return value of " + factory, e);
466          }
467        }
468      }
469      return this;
470    }
471
472    /**
473     * Tests {@link Object#equals} and {@link Object#hashCode} against the return values of the
474     * static methods, by asserting that when equal parameters are passed to the same static method,
475     * the return value should also be equal; and vice versa.
476     *
477     * <p>Test fails if default value cannot be determined for a constructor or factory method
478     * parameter, or if the constructor or factory method throws exception.
479     *
480     * @return this tester
481     */
482    @CanIgnoreReturnValue
483    public FactoryMethodReturnValueTester testEquals() throws Exception {
484      for (Invokable<?, ?> factory : getFactoriesToTest()) {
485        try {
486          testEqualsUsing(factory);
487        } catch (FactoryMethodReturnsNullException e) {
488          // If the factory returns null, we just skip it.
489        }
490      }
491      return this;
492    }
493
494    /**
495     * Runs serialization test on the return values of the static methods.
496     *
497     * <p>Test fails if default value cannot be determined for a constructor or factory method
498     * parameter, or if the constructor or factory method throws exception.
499     *
500     * @return this tester
501     */
502    @CanIgnoreReturnValue
503    @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
504    public FactoryMethodReturnValueTester testSerializable() throws Exception {
505      for (Invokable<?, ?> factory : getFactoriesToTest()) {
506        Object instance = instantiate(factory);
507        if (instance != null) {
508          try {
509            SerializableTester.reserialize(instance);
510          } catch (Exception e) { // sneaky checked exception
511            throw new AssertionError(
512                "Serialization failed on return value of " + factory, e.getCause());
513          }
514        }
515      }
516      return this;
517    }
518
519    /**
520     * Runs equals and serialization test on the return values.
521     *
522     * <p>Test fails if default value cannot be determined for a constructor or factory method
523     * parameter, or if the constructor or factory method throws exception.
524     *
525     * @return this tester
526     */
527    @CanIgnoreReturnValue
528    @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
529    public FactoryMethodReturnValueTester testEqualsAndSerializable() throws Exception {
530      for (Invokable<?, ?> factory : getFactoriesToTest()) {
531        try {
532          testEqualsUsing(factory);
533        } catch (FactoryMethodReturnsNullException e) {
534          // If the factory returns null, we just skip it.
535        }
536        Object instance = instantiate(factory);
537        if (instance != null) {
538          try {
539            SerializableTester.reserializeAndAssert(instance);
540          } catch (Exception e) { // sneaky checked exception
541            throw new AssertionError(
542                "Serialization failed on return value of " + factory, e.getCause());
543          } catch (AssertionFailedError e) {
544            throw new AssertionError(
545                "Return value of " + factory + " reserialized to an unequal value", e);
546          }
547        }
548      }
549      return this;
550    }
551
552    private ImmutableList<Invokable<?, ?>> getFactoriesToTest() {
553      ImmutableList.Builder<Invokable<?, ?>> builder = ImmutableList.builder();
554      for (Invokable<?, ?> factory : factories) {
555        if (returnTypeToTest.isAssignableFrom(factory.getReturnType().getRawType())) {
556          builder.add(factory);
557        }
558      }
559      ImmutableList<Invokable<?, ?>> factoriesToTest = builder.build();
560      Assert.assertFalse(
561          "No "
562              + factoryMethodsDescription
563              + " that return "
564              + returnTypeToTest.getName()
565              + " or subtype are found in "
566              + declaringClass
567              + ".",
568          factoriesToTest.isEmpty());
569      return factoriesToTest;
570    }
571  }
572
573  private void testEqualsUsing(Invokable<?, ?> factory)
574      throws ParameterNotInstantiableException,
575          ParameterHasNoDistinctValueException,
576          IllegalAccessException,
577          InvocationTargetException,
578          FactoryMethodReturnsNullException {
579    List<Parameter> params = factory.getParameters();
580    List<FreshValueGenerator> argGenerators = Lists.newArrayListWithCapacity(params.size());
581    List<@Nullable Object> args = Lists.newArrayListWithCapacity(params.size());
582    for (Parameter param : params) {
583      FreshValueGenerator generator = newFreshValueGenerator();
584      argGenerators.add(generator);
585      args.add(generateDummyArg(param, generator));
586    }
587    Object instance = createInstance(factory, args);
588    List<Object> equalArgs = generateEqualFactoryArguments(factory, params, args);
589    // Each group is a List of items, each item has a list of factory args.
590    List<List<List<Object>>> argGroups = Lists.newArrayList();
591    argGroups.add(ImmutableList.of(args, equalArgs));
592    EqualsTester tester =
593        new EqualsTester(
594            new ItemReporter() {
595              @Override
596              String reportItem(Item<?> item) {
597                List<Object> factoryArgs = argGroups.get(item.groupNumber).get(item.itemNumber);
598                return factory.getName()
599                    + "("
600                    + Joiner.on(", ").useForNull("null").join(factoryArgs)
601                    + ")";
602              }
603            });
604    tester.addEqualityGroup(instance, createInstance(factory, equalArgs));
605    for (int i = 0; i < params.size(); i++) {
606      List<Object> newArgs = Lists.newArrayList(args);
607      Object newArg = argGenerators.get(i).generateFresh(params.get(i).getType());
608
609      if (newArg == null || Objects.equal(args.get(i), newArg)) {
610        if (params.get(i).getType().getRawType().isEnum()) {
611          continue; // Nothing better we can do if it's single-value enum
612        }
613        throw new ParameterHasNoDistinctValueException(params.get(i));
614      }
615      newArgs.set(i, newArg);
616      tester.addEqualityGroup(createInstance(factory, newArgs));
617      argGroups.add(ImmutableList.of(newArgs));
618    }
619    tester.testEquals();
620  }
621
622  /**
623   * Returns dummy factory arguments that are equal to {@code args} but may be different instances,
624   * to be used to construct a second instance of the same equality group.
625   */
626  private List<Object> generateEqualFactoryArguments(
627      Invokable<?, ?> factory, List<Parameter> params, List<Object> args)
628      throws ParameterNotInstantiableException,
629          FactoryMethodReturnsNullException,
630          InvocationTargetException,
631          IllegalAccessException {
632    List<Object> equalArgs = Lists.newArrayList(args);
633    for (int i = 0; i < args.size(); i++) {
634      Parameter param = params.get(i);
635      Object arg = args.get(i);
636      // Use new fresh value generator because 'args' were populated with new fresh generator each.
637      // Two newFreshValueGenerator() instances should normally generate equal value sequence.
638      Object shouldBeEqualArg = generateDummyArg(param, newFreshValueGenerator());
639      if (arg != shouldBeEqualArg
640          && Objects.equal(arg, shouldBeEqualArg)
641          && hashCodeInsensitiveToArgReference(factory, args, i, shouldBeEqualArg)
642          && hashCodeInsensitiveToArgReference(
643              factory, args, i, generateDummyArg(param, newFreshValueGenerator()))) {
644        // If the implementation uses identityHashCode(), referential equality is
645        // probably intended. So no point in using an equal-but-different factory argument.
646        // We check twice to avoid confusion caused by accidental hash collision.
647        equalArgs.set(i, shouldBeEqualArg);
648      }
649    }
650    return equalArgs;
651  }
652
653  private static boolean hashCodeInsensitiveToArgReference(
654      Invokable<?, ?> factory, List<Object> args, int i, Object alternateArg)
655      throws FactoryMethodReturnsNullException, InvocationTargetException, IllegalAccessException {
656    List<Object> tentativeArgs = Lists.newArrayList(args);
657    tentativeArgs.set(i, alternateArg);
658    return createInstance(factory, tentativeArgs).hashCode()
659        == createInstance(factory, args).hashCode();
660  }
661
662  // distinctValues is a type-safe class-values mapping, but we don't have a type-safe data
663  // structure to hold the mappings.
664  @SuppressWarnings({"unchecked", "rawtypes"})
665  private FreshValueGenerator newFreshValueGenerator() {
666    FreshValueGenerator generator =
667        new FreshValueGenerator() {
668          @Override
669          @Nullable Object interfaceMethodCalled(Class<?> interfaceType, Method method) {
670            return getDummyValue(TypeToken.of(interfaceType).method(method).getReturnType());
671          }
672        };
673    for (Entry<Class<?>, Collection<Object>> entry : distinctValues.asMap().entrySet()) {
674      generator.addSampleInstances((Class) entry.getKey(), entry.getValue());
675    }
676    return generator;
677  }
678
679  private static @Nullable Object generateDummyArg(Parameter param, FreshValueGenerator generator)
680      throws ParameterNotInstantiableException {
681    if (isNullable(param)) {
682      return null;
683    }
684    Object arg = generator.generateFresh(param.getType());
685    if (arg == null) {
686      throw new ParameterNotInstantiableException(param);
687    }
688    return arg;
689  }
690
691  private static <X extends Throwable> void throwFirst(List<X> exceptions) throws X {
692    if (!exceptions.isEmpty()) {
693      throw exceptions.get(0);
694    }
695  }
696
697  /** Factories with the least number of parameters are listed first. */
698  private static <T> ImmutableList<Invokable<?, ? extends T>> getFactories(TypeToken<T> type) {
699    List<Invokable<?, ? extends T>> factories = Lists.newArrayList();
700    for (Method method : type.getRawType().getDeclaredMethods()) {
701      Invokable<?, ?> invokable = type.method(method);
702      if (!invokable.isPrivate()
703          && !invokable.isSynthetic()
704          && invokable.isStatic()
705          && type.isSupertypeOf(invokable.getReturnType())) {
706        @SuppressWarnings("unchecked") // guarded by isAssignableFrom()
707        Invokable<?, ? extends T> factory = (Invokable<?, ? extends T>) invokable;
708        factories.add(factory);
709      }
710    }
711    if (!Modifier.isAbstract(type.getRawType().getModifiers())) {
712      for (Constructor<?> constructor : type.getRawType().getDeclaredConstructors()) {
713        Invokable<T, T> invokable = type.constructor(constructor);
714        if (!invokable.isPrivate() && !invokable.isSynthetic()) {
715          factories.add(invokable);
716        }
717      }
718    }
719    for (Invokable<?, ?> factory : factories) {
720      factory.setAccessible(true);
721    }
722    // Sorts methods/constructors with the least number of parameters first since it's likely easier
723    // to fill dummy parameter values for them. Ties are broken by name then by the string form of
724    // the parameter list.
725    return BY_NUMBER_OF_PARAMETERS
726        .compound(BY_METHOD_NAME)
727        .compound(BY_PARAMETERS)
728        .immutableSortedCopy(factories);
729  }
730
731  private List<Object> getDummyArguments(Invokable<?, ?> invokable)
732      throws ParameterNotInstantiableException {
733    List<Object> args = Lists.newArrayList();
734    for (Parameter param : invokable.getParameters()) {
735      if (isNullable(param)) {
736        args.add(null);
737        continue;
738      }
739      Object defaultValue = getDummyValue(param.getType());
740      if (defaultValue == null) {
741        throw new ParameterNotInstantiableException(param);
742      }
743      args.add(defaultValue);
744    }
745    return args;
746  }
747
748  private <T> @Nullable T getDummyValue(TypeToken<T> type) {
749    Class<? super T> rawType = type.getRawType();
750    @SuppressWarnings("unchecked") // Assume all default values are generics safe.
751    T defaultValue = (T) defaultValues.getInstance(rawType);
752    if (defaultValue != null) {
753      return defaultValue;
754    }
755    @SuppressWarnings("unchecked") // ArbitraryInstances always returns generics-safe dummies.
756    T value = (T) ArbitraryInstances.get(rawType);
757    if (value != null) {
758      return value;
759    }
760    if (rawType.isInterface()) {
761      return new SerializableDummyProxy(this).newProxy(type);
762    }
763    return null;
764  }
765
766  private static <T> T createInstance(Invokable<?, ? extends T> factory, List<?> args)
767      throws FactoryMethodReturnsNullException, InvocationTargetException, IllegalAccessException {
768    T instance = invoke(factory, args);
769    if (instance == null) {
770      throw new FactoryMethodReturnsNullException(factory);
771    }
772    return instance;
773  }
774
775  private static <T> @Nullable T invoke(Invokable<?, ? extends T> factory, List<?> args)
776      throws InvocationTargetException, IllegalAccessException {
777    T returnValue = factory.invoke(null, args.toArray());
778    if (returnValue == null) {
779      Assert.assertTrue(
780          factory + " returns null but it's not annotated with @Nullable", isNullable(factory));
781    }
782    return returnValue;
783  }
784
785  /**
786   * Thrown if the test tries to invoke a constructor or static factory method but failed because
787   * the dummy value of a constructor or method parameter is unknown.
788   */
789  @VisibleForTesting
790  static class ParameterNotInstantiableException extends Exception {
791    public ParameterNotInstantiableException(Parameter parameter) {
792      super(
793          "Cannot determine value for parameter "
794              + parameter
795              + " of "
796              + parameter.getDeclaringInvokable());
797    }
798  }
799
800  /**
801   * Thrown if the test fails to generate two distinct non-null values of a constructor or factory
802   * parameter in order to test {@link Object#equals} and {@link Object#hashCode} of the declaring
803   * class.
804   */
805  @VisibleForTesting
806  static class ParameterHasNoDistinctValueException extends Exception {
807    ParameterHasNoDistinctValueException(Parameter parameter) {
808      super(
809          "Cannot generate distinct value for parameter "
810              + parameter
811              + " of "
812              + parameter.getDeclaringInvokable());
813    }
814  }
815
816  /**
817   * Thrown if the test tries to invoke a static factory method to test instance methods but the
818   * factory returned null.
819   */
820  @VisibleForTesting
821  static class FactoryMethodReturnsNullException extends Exception {
822    public FactoryMethodReturnsNullException(Invokable<?, ?> factory) {
823      super(factory + " returns null and cannot be used to test instance methods.");
824    }
825  }
826
827  private static final class SerializableDummyProxy extends DummyProxy implements Serializable {
828
829    private final transient ClassSanityTester tester;
830
831    SerializableDummyProxy(ClassSanityTester tester) {
832      this.tester = tester;
833    }
834
835    @Override
836    <R> R dummyReturnValue(TypeToken<R> returnType) {
837      return tester.getDummyValue(returnType);
838    }
839
840    @Override
841    public boolean equals(@Nullable Object obj) {
842      return obj instanceof SerializableDummyProxy;
843    }
844
845    @Override
846    public int hashCode() {
847      return 0;
848    }
849  }
850}