All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unitils.objectvalidation.rules.EqualsComplientRule Maven / Gradle / Ivy

There is a newer version: 1.1.9
Show newest version
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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy