org.unitils.objectvalidation.rules.EqualsComplientRule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unitils-objectvalidation Show documentation
Show all versions of unitils-objectvalidation Show documentation
Unitils module to validate objects.
package org.unitils.objectvalidation.rules;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.unitils.core.UnitilsException;
import org.unitils.objectvalidation.ObjectCloner;
import org.unitils.objectvalidation.ObjectCreator;
import org.unitils.objectvalidation.Rule;
/**
* Verifies the seven equality rules defined by Sun :
* 1. Equals must be reflexive
* 2. Equals must be symmetric
* 3. Equals must be transitive
* 4. Equals must be consistent
* 5. Fails in the case of a null value
* 6. Inequality with a totally different object of the same type created randomly
* 7. Inequality with a totally different object
*
* @author Jeroen Horemans
* @author Matthieu Mestrez
* @since Oct 16, 2013
*/
public class EqualsComplientRule implements Rule {
private static final int NUMBER_OF_EQUALS_CHECK_FOR_CONSISTENCY = 500;
private ObjectCreator randomFactory;
private ObjectCloner objectCloner;
private Class> clazz;
public EqualsComplientRule(ObjectCreator randomFactory, ObjectCloner objectCloner) {
this.randomFactory = randomFactory;
this.objectCloner = objectCloner;
}
@Override
public void validate(Class> bean) {
clazz = bean;
Object firstInstance = randomFactory.createRandomObject(bean);
Object secondInstance = objectCloner.deepClone(firstInstance);
Object thirdInstance = objectCloner.deepClone(firstInstance);
checkRules(firstInstance, secondInstance, thirdInstance);
}
private void checkRules(Object firstInstance, Object secondInstance, Object thirdInstance) {
if (firstInstance == null || secondInstance == null) {
throw new UnitilsException("One of the instances is null.");
}
testReflexive(firstInstance);
testSymmetric(firstInstance, secondInstance);
testTransitive(firstInstance, secondInstance, thirdInstance);
testConsistent(firstInstance, secondInstance);
testNonValue(firstInstance);
testInequality(firstInstance);
testInequalityWithARandomObject(firstInstance);
}
/** It is reflexive : an object must always be equal to himself */
private void testReflexive(Object x) {
assertTrue("Equals is not reflexive.", x.equals(x));
}
/** It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. */
private void testSymmetric(Object x, Object y) {
assertTrue("Equals is not symmetric.", x.equals(y));
assertTrue("Equals is not symmetric.", y.equals(x));
}
/**
* It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then
* x.equals(z) should return true.
*/
private void testTransitive(Object x, Object y, Object z) {
assertTrue("Equals is not transitive.", x.equals(y));
assertTrue("Equals is not transitive.", y.equals(z));
assertTrue("Equals is not transitive.", z.equals(x));
}
/**
* It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or
* consistently return false, provided no information used in equals comparisons on the objects is modified.
*/
private void testConsistent(Object x, Object y) {
for (int i = 0; i < NUMBER_OF_EQUALS_CHECK_FOR_CONSISTENCY; i++) {
assertTrue("Equals is not consistent.", x.equals(y));
}
}
/**
* For any non-null reference value x, x.equals(null) should return false.
*/
private void testNonValue(Object x) {
Object nullObject = null;
assertFalse("Equals should not be equals to null for a non null object.", x.equals(nullObject));
}
/**
* check two objects are not equal.
*/
private void testInequality(Object x) {
Object y = createDifferentObject(x);
assertFalse("Object " + x + " should not be equal with random object " + y, x.equals(y));
}
/**
* check two objects are not equal.
*/
private void testInequalityWithARandomObject(Object x) {
Object y = new Object();
assertFalse("Object " + x + " should not be equal to " + y, x.equals(y));
}
private Object createDifferentObject(Object previousValue) {
Object randomField = randomFactory.createRandomObject(clazz);
int maxSearchForRandom = 1000;
while (previousValue == randomField || previousValue.equals(randomField)) {
randomField = randomFactory.createRandomObject(previousValue.getClass());
maxSearchForRandom--;
if (maxSearchForRandom == 0) {
fail("The validator was unable to create a different value for the field " + previousValue.getClass() + " of the class " + clazz.getName() + " than " + randomField.toString());
}
}
return randomField;
}
}