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