@Beta @GwtIncompatible public final class ClassSanityTester extends java.lang.Object
interface Book {...} public class Books { public static Book hardcover(String title) {...} public static Book paperback(String title) {...} }
And all the created Book
instances can be tested with:
new ClassSanityTester() .forAllPublicStaticMethods(Books.class) .thatReturn(Book.class) .testEquals(); // or testNulls(), testSerializable() etc.
Modifier and Type | Class and Description |
---|---|
(package private) static class |
ClassSanityTester.FactoryMethodReturnsNullException
Thrown if the test tries to invoke a static factory method to test instance methods but the
factory returned null.
|
class |
ClassSanityTester.FactoryMethodReturnValueTester
Runs sanity tests against return values of static factory methods declared by a class.
|
(package private) static class |
ClassSanityTester.ParameterHasNoDistinctValueException
Thrown if the test fails to generate two distinct non-null values of a constructor or factory
parameter in order to test
Object.equals(java.lang.Object) and Object.hashCode() of the declaring
class. |
(package private) static class |
ClassSanityTester.ParameterNotInstantiableException
Thrown if the test tries to invoke a constructor or static factory method but failed because
the dummy value of a constructor or method parameter is unknown.
|
private static class |
ClassSanityTester.SerializableDummyProxy |
Modifier and Type | Field and Description |
---|---|
private static Ordering<Invokable<?,?>> |
BY_METHOD_NAME |
private static Ordering<Invokable<?,?>> |
BY_NUMBER_OF_PARAMETERS |
private static Ordering<Invokable<?,?>> |
BY_PARAMETERS |
private MutableClassToInstanceMap<java.lang.Object> |
defaultValues |
private ListMultimap<java.lang.Class<?>,java.lang.Object> |
distinctValues |
private NullPointerTester |
nullPointerTester |
Constructor and Description |
---|
ClassSanityTester() |
Modifier and Type | Method and Description |
---|---|
private static <T> T |
createInstance(Invokable<?,? extends T> factory,
java.util.List<?> args) |
(package private) void |
doTestEquals(java.lang.Class<?> cls) |
(package private) void |
doTestNulls(java.lang.Class<?> cls,
NullPointerTester.Visibility visibility) |
ClassSanityTester.FactoryMethodReturnValueTester |
forAllPublicStaticMethods(java.lang.Class<?> cls)
Returns an object responsible for performing sanity tests against the return values
of all public static methods declared by
cls , excluding superclasses. |
private static java.lang.Object |
generateDummyArg(Parameter param,
FreshValueGenerator generator) |
private java.util.List<java.lang.Object> |
generateEqualFactoryArguments(Invokable<?,?> factory,
java.util.List<Parameter> params,
java.util.List<java.lang.Object> args)
Returns dummy factory arguments that are equal to
args but may be different instances,
to be used to construct a second instance of the same equality group. |
private java.util.List<java.lang.Object> |
getDummyArguments(Invokable<?,?> invokable) |
private <T> T |
getDummyValue(TypeToken<T> type) |
private static <T> ImmutableList<Invokable<?,? extends T>> |
getFactories(TypeToken<T> type)
Factories with the least number of parameters are listed first.
|
private static boolean |
hashCodeInsensitiveToArgReference(Invokable<?,?> factory,
java.util.List<java.lang.Object> args,
int i,
java.lang.Object alternateArg) |
private boolean |
hasInstanceMethodToTestNulls(java.lang.Class<?> c,
NullPointerTester.Visibility visibility) |
(package private) <T> T |
instantiate(java.lang.Class<T> cls)
Instantiates
cls by invoking one of its non-private constructors or non-private static
factory methods with the parameters automatically provided using dummy values. |
private <T> T |
instantiate(Invokable<?,? extends T> factory)
Instantiates using
factory . |
private static <T> T |
invoke(Invokable<?,? extends T> factory,
java.util.List<?> args) |
private FreshValueGenerator |
newFreshValueGenerator() |
<T> ClassSanityTester |
setDefault(java.lang.Class<T> type,
T value)
Sets the default value for
type . |
<T> ClassSanityTester |
setDistinctValues(java.lang.Class<T> type,
T value1,
T value2)
Sets distinct values for
type , so that when a class Foo is tested for Object.equals(java.lang.Object) and Object.hashCode() , and its construction requires a parameter of type , the distinct values of type can be passed as parameters to create Foo
instances that are unequal. |
void |
testEquals(java.lang.Class<?> cls)
Tests the
Object.equals(java.lang.Object) and Object.hashCode() of cls . |
private void |
testEqualsUsing(Invokable<?,?> factory) |
void |
testNulls(java.lang.Class<?> cls)
Tests that
cls properly checks null on all constructor and method parameters that
aren't annotated with Nullable . |
private static <X extends java.lang.Throwable> |
throwFirst(java.util.List<X> exceptions) |
private final MutableClassToInstanceMap<java.lang.Object> defaultValues
private final ListMultimap<java.lang.Class<?>,java.lang.Object> distinctValues
private final NullPointerTester nullPointerTester
public <T> ClassSanityTester setDefault(java.lang.Class<T> type, T value)
type
. The default value isn't used in testing Object.equals(java.lang.Object)
because more than one sample instances are needed for testing inequality.
To set distinct values for equality testing, use setDistinctValues(java.lang.Class<T>, T, T)
instead.public <T> ClassSanityTester setDistinctValues(java.lang.Class<T> type, T value1, T value2)
type
, so that when a class Foo
is tested for Object.equals(java.lang.Object)
and Object.hashCode()
, and its construction requires a parameter of type
, the distinct values of type
can be passed as parameters to create Foo
instances that are unequal.
Calling setDistinctValues(type, v1, v2)
also sets the default value for type
that's used for testNulls(java.lang.Class<?>)
.
Only necessary for types where ClassSanityTester
doesn't already know how to create
distinct values.
public void testNulls(java.lang.Class<?> cls)
cls
properly checks null on all constructor and method parameters that
aren't annotated with Nullable
. In details:
Nullable
should throw NullPointerException
.
cls
, all non-private instance methods will be checked too using the instance
created by invoking the constructor or static factory method.
cls
:
cls
, instance methods are skipped for nulls test.
cls
or cls
's subtype.
void doTestNulls(java.lang.Class<?> cls, NullPointerTester.Visibility visibility) throws ClassSanityTester.ParameterNotInstantiableException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException, ClassSanityTester.FactoryMethodReturnsNullException
ClassSanityTester.ParameterNotInstantiableException
java.lang.IllegalAccessException
java.lang.reflect.InvocationTargetException
ClassSanityTester.FactoryMethodReturnsNullException
private boolean hasInstanceMethodToTestNulls(java.lang.Class<?> c, NullPointerTester.Visibility visibility)
public void testEquals(java.lang.Class<?> cls)
Object.equals(java.lang.Object)
and Object.hashCode()
of cls
. In details:
cls
, no test is performed.
cls
or cls
's subtype.
List.add(E)
,
or functional update methods such as Joiner.skipNulls()
.
Note that constructors taking a builder object cannot be tested effectively because semantics of builder can be arbitrarily complex. Still, a factory class can be created in the test to facilitate equality testing. For example:
public class FooTest { private static class FooFactoryForTest { public static Foo create(String a, String b, int c, boolean d) { return Foo.builder() .setA(a) .setB(b) .setC(c) .setD(d) .build(); } } public void testEquals() { new ClassSanityTester() .forAllPublicStaticMethods(FooFactoryForTest.class) .thatReturn(Foo.class) .testEquals(); } }
It will test that Foo objects created by the create(a, b, c, d)
factory method with
equal parameters are equal and vice versa, thus indirectly tests the builder equality.
void doTestEquals(java.lang.Class<?> cls) throws ClassSanityTester.ParameterNotInstantiableException, ClassSanityTester.ParameterHasNoDistinctValueException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException, ClassSanityTester.FactoryMethodReturnsNullException
ClassSanityTester.ParameterNotInstantiableException
ClassSanityTester.ParameterHasNoDistinctValueException
java.lang.IllegalAccessException
java.lang.reflect.InvocationTargetException
ClassSanityTester.FactoryMethodReturnsNullException
@Nullable <T> T instantiate(java.lang.Class<T> cls) throws ClassSanityTester.ParameterNotInstantiableException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException, ClassSanityTester.FactoryMethodReturnsNullException
cls
by invoking one of its non-private constructors or non-private static
factory methods with the parameters automatically provided using dummy values.null
if the class has no non-private constructor
or factory method to be constructed.ClassSanityTester.ParameterNotInstantiableException
java.lang.IllegalAccessException
java.lang.reflect.InvocationTargetException
ClassSanityTester.FactoryMethodReturnsNullException
public ClassSanityTester.FactoryMethodReturnValueTester forAllPublicStaticMethods(java.lang.Class<?> cls)
cls
, excluding superclasses.@Nullable private <T> T instantiate(Invokable<?,? extends T> factory) throws ClassSanityTester.ParameterNotInstantiableException, java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException
factory
. If factory
is annotated with Nullable
and
returns null, null will be returned.ClassSanityTester.ParameterNotInstantiableException
- if the static methods cannot be invoked because
the default value of a parameter cannot be determined.java.lang.IllegalAccessException
- if the class isn't public or is nested inside a non-public
class, preventing its methods from being accessible.java.lang.reflect.InvocationTargetException
- if a static method threw exception.private void testEqualsUsing(Invokable<?,?> factory) throws ClassSanityTester.ParameterNotInstantiableException, ClassSanityTester.ParameterHasNoDistinctValueException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException, ClassSanityTester.FactoryMethodReturnsNullException
ClassSanityTester.ParameterNotInstantiableException
ClassSanityTester.ParameterHasNoDistinctValueException
java.lang.IllegalAccessException
java.lang.reflect.InvocationTargetException
ClassSanityTester.FactoryMethodReturnsNullException
private java.util.List<java.lang.Object> generateEqualFactoryArguments(Invokable<?,?> factory, java.util.List<Parameter> params, java.util.List<java.lang.Object> args) throws ClassSanityTester.ParameterNotInstantiableException, ClassSanityTester.FactoryMethodReturnsNullException, java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException
args
but may be different instances,
to be used to construct a second instance of the same equality group.ClassSanityTester.ParameterNotInstantiableException
ClassSanityTester.FactoryMethodReturnsNullException
java.lang.reflect.InvocationTargetException
java.lang.IllegalAccessException
private static boolean hashCodeInsensitiveToArgReference(Invokable<?,?> factory, java.util.List<java.lang.Object> args, int i, java.lang.Object alternateArg) throws ClassSanityTester.FactoryMethodReturnsNullException, java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException
ClassSanityTester.FactoryMethodReturnsNullException
java.lang.reflect.InvocationTargetException
java.lang.IllegalAccessException
private FreshValueGenerator newFreshValueGenerator()
@Nullable private static java.lang.Object generateDummyArg(Parameter param, FreshValueGenerator generator) throws ClassSanityTester.ParameterNotInstantiableException
private static <X extends java.lang.Throwable> void throwFirst(java.util.List<X> exceptions) throws X extends java.lang.Throwable
X extends java.lang.Throwable
private static <T> ImmutableList<Invokable<?,? extends T>> getFactories(TypeToken<T> type)
private java.util.List<java.lang.Object> getDummyArguments(Invokable<?,?> invokable) throws ClassSanityTester.ParameterNotInstantiableException
private <T> T getDummyValue(TypeToken<T> type)
private static <T> T createInstance(Invokable<?,? extends T> factory, java.util.List<?> args) throws ClassSanityTester.FactoryMethodReturnsNullException, java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException
ClassSanityTester.FactoryMethodReturnsNullException
java.lang.reflect.InvocationTargetException
java.lang.IllegalAccessException
@Nullable private static <T> T invoke(Invokable<?,? extends T> factory, java.util.List<?> args) throws java.lang.reflect.InvocationTargetException, java.lang.IllegalAccessException
java.lang.reflect.InvocationTargetException
java.lang.IllegalAccessException