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