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