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