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