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

org.meanbean.test.EqualsMethodContractVerifier Maven / Gradle / Ivy

Go to download

Mean Bean is an open source Java test library that tests equals and hashCode contract compliance, as well as JavaBean/POJO getter and setter methods.

There is a newer version: 2.0.3
Show newest version
package org.meanbean.test;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.meanbean.lang.EquivalentFactory;
import org.meanbean.util.AssertionUtils;
import org.meanbean.util.SimpleValidationHelper;
import org.meanbean.util.ValidationHelper;

/**
 * 

* Class that affords functionality to test the equals logic implemented by objects.
*

* *

* Use the tests provided by this class (namely, verifyEqualsMethod()) to test a class that overrides * equals(). verifyEqualsMethod() invokes all other tests. However, you can invoke each test * individually instead.
*

* *

* As an example, to test the equals logic implemented by a class called MyClass do the following: *

* *
 * EqualsMethodContractVerifier verifier = new EqualsMethodContractVerifier();
 * verifier.verifyEqualsMethod(new EquivalentFactory() {
 *    @Override
 *    public MyClass create() {
 *       MyClass() result = new MyClass();
 *       // initialize result...
 *       result.setName("TEST_NAME");
 *       return result;
 *    }
 * });
 * 
* *

* The EquivalentFactory creates new logically equivalent instances of MyClass. MyClass has overridden * equals() and hashCode(). *

* * @author Graham Williamson */ class EqualsMethodContractVerifier { /** Logging mechanism. */ private final Log log = LogFactory.getLog(EqualsMethodContractVerifier.class); /** Input validation helper. */ private final ValidationHelper validationHelper = new SimpleValidationHelper(log); /** Null value */ private static final Object NULL = null; /** *

* Verify that the equals logic implemented by the type the specified factory creates is correct by testing: *

* *
    *
  • the reflexive item of the equals contract - x.equals(x) should hold
  • * *
  • the symmetric item of the equals contract - if x.equals(y), then * y.equals(x) should also hold
  • * *
  • the transitive item of the equals contract - if x.equals(y) and * y.equals(z), then x.equals(z) should hold
  • * *
  • the consistent item of the equals contract - if x.equals(y), then * x.equals(y) should hold (remain consistent) across multiple invocations, so long as neither object * changes
  • * *
  • the null item of the equals contract - a non-null object should not be deemed equal to * another null object
  • * *
  • that an entirely different type of object is not deemed equal to an object created by the specified factory.
  • *
* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates non-null logically equivalent objects that will be used to test * whether the equals logic implemented by the type is correct. The factory must create logically * equivalent but different actual instances of the type upon each invocation of create() in * order for the test to be meaningful and correct. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null, if it creates a * null object or if it creates objects that are not logically equivalent. * @throws AssertionError * If the test fails. */ public void verifyEqualsMethod(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsMethod: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals", factory); verifyEqualsReflexive(factory); verifyEqualsSymmetric(factory); verifyEqualsTransitive(factory); verifyEqualsConsistent(factory); verifyEqualsNull(factory); verifyEqualsDifferentType(factory); log.debug("verifyEqualsMethod: Exiting - Equals is correct."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is consistent with the * reflexive item of the equals contract.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates non-null logically equivalent objects that will be used to test * whether the equals logic implemented by the type is consistent with the reflexive item of the equals * contract. The factory must create logically equivalent but different actual instances of the type upon * each invocation of create() in order for the test to be meaningful. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null or if it creates * a null object. * @throws AssertionError * If the test fails. */ public void verifyEqualsReflexive(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsReflexive: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals reflexive item", factory); Object x = factory.create(); log.debug("verifyEqualsReflexive: Created object x=[" + x + "] for test."); validationHelper.ensureExists("factory-created object", "test equals reflexive item", x); if (!x.equals(x)) { log.debug("verifyEqualsReflexive: Equals is not reflexive."); AssertionUtils.fail("equals is not reflexive."); } log.debug("verifyEqualsReflexive: Exiting - Equals is reflexive."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is consistent with the * symmetric item of the equals contract.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates non-null logically equivalent objects that will be used to test * whether the equals logic implemented by the type is consistent with the symmetric item of the equals * contract. The factory must create logically equivalent but different actual instances of the type upon * each invocation of create() in order for the test to be meaningful. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null, if it creates a * null object or if it creates objects that are not logically equivalent. * @throws AssertionError * If the test fails. */ public void verifyEqualsSymmetric(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsSymmetric: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals symmetric item", factory); Object x = factory.create(); Object y = factory.create(); log.debug("verifyEqualsSymmetric: Created objects x=[" + x + "] and y=[" + y + "] for test."); validationHelper.ensureExists("factory-created object", "test equals symmetric item", x); validationHelper.ensureExists("factory-created object", "test equals symmetric item", y); if (!x.equals(y)) { String message = "Cannot test equals symmetric item if factory does not create logically equivalent " + "objects. Does factory not create logically equivalent objects, or do objects not override " + "equals?"; log.debug("verifyEqualsSymmetric: " + message + " Throw IllegalArgumentException."); throw new IllegalArgumentException(message); } if (x.equals(y) && !y.equals(x)) { log.debug("verifyEqualsSymmetric: Equals is not symmetric."); AssertionUtils.fail("equals is not symmetric."); } log.debug("verifyEqualsSymmetric: Exiting - Equals is symmetric."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is consistent with the * transitive item of the equals contract.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates non-null logically equivalent objects that will be used to test * whether the equals logic implemented by the type is consistent with the transitive item of the equals * contract. The factory must create logically equivalent but different actual instances of the type upon * each invocation of create() in order for the test to be meaningful. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null or if it creates * a null object or if it creates objects that are not logically equivalent. * @throws AssertionError * If the test fails. */ public void verifyEqualsTransitive(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsTransitive: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals transitive item", factory); Object x = factory.create(); Object y = factory.create(); Object z = factory.create(); log.debug("verifyEqualsTransitive: Created objects x=[" + x + "], y=[" + y + "] and z=[" + z + "] for test."); validationHelper.ensureExists("factory-created object", "test equals transitive item", x); validationHelper.ensureExists("factory-created object", "test equals transitive item", y); validationHelper.ensureExists("factory-created object", "test equals transitive item", z); if (!(x.equals(y) && y.equals(z))) { String message = "Cannot test equals transitive item if factory does not create logically equivalent objects."; log.debug("verifyEqualsTransitive: " + message + " Throw IllegalArgumentException."); throw new IllegalArgumentException(message); } if (x.equals(y) && y.equals(z) && (!x.equals(z))) { log.debug("verifyEqualsTransitive: Equals is not transitive."); AssertionUtils.fail("equals is not transitive."); } log.debug("verifyEqualsTransitive: Exiting - Equals is transitive."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is consistent with the * consistent item of the equals contract.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates non-null logically equivalent objects that will be used to test * whether the equals logic implemented by the type is consistent with the consistent item of the equals * contract. The factory must create logically equivalent but different actual instances of the type upon * each invocation of create() in order for the test to be meaningful. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null or if it creates * a null object. * @throws AssertionError * If the test fails. */ public void verifyEqualsConsistent(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsConsistent: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals consistent item", factory); Object x = factory.create(); Object y = factory.create(); log.debug("verifyEqualsConsistent: Created objects x=[" + x + "] and y=[" + y + "] for test."); validationHelper.ensureExists("factory-created object", "test equals consistent item", x); validationHelper.ensureExists("factory-created object", "test equals consistent item", y); for (int idx = 0; idx < 100; idx++) { if (!x.equals(y)) { log.debug("verifyEqualsConsistent: Equals is not consistent on invocation [" + idx + "]."); AssertionUtils.fail("equals is not consistent on invocation [" + idx + "]."); } } log.debug("verifyEqualsConsistent: Exiting - Equals is consistent."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is consistent with the * null item of the equals contract. That is, that the non-null object created by the specified * factory should never be equal to a null object.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates a non-null object that will be used to test whether the equals logic * implemented by the type is consistent with the null item of the equals contract. The factory must * create a non-null instance of the type upon each invocation of create() in order for the * test to function. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null or if it creates * a null object. * @throws AssertionError * If the test fails. */ public void verifyEqualsNull(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsNull: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals null item", factory); Object x = factory.create(); log.debug("verifyEqualsNull: Created object x=[" + x + "] for test."); validationHelper.ensureExists("factory-created object", "test equals null item", x); if (x.equals(NULL)) { log.debug("verifyEqualsNull: Equals is incorrect with respect to null comparison."); AssertionUtils.fail("equals is incorrect with respect to null comparison."); } log.debug("verifyEqualsNull: Exiting - Equals is correct with respect to null comparison."); } /** *

* Verify that the equals logic implemented by the type the specified factory creates is correct when comparing an * instance of that type with an instance of an entirely different type. Two entirely different objects should never * be equal to one another.
*

* *

* If the test fails, an AssertionError is thrown. *

* * @param factory * An EquivalentFactory that creates a non-null object that will be used to test whether the equals logic * implemented by the type is correct when comparing itself with an instance of an entirely different * type. The factory must create a non-null instance of the type upon each invocation of * create() in order for the test to function. * * @throws IllegalArgumentException * If the specified factory is deemed illegal. For example, if it is null or if it creates * a null object. * @throws AssertionError * If the test fails. */ public void verifyEqualsDifferentType(EquivalentFactory factory) throws IllegalArgumentException, AssertionError { log.debug("verifyEqualsDifferentType: Entering with factory=[" + factory + "]."); validationHelper.ensureExists("factory", "test equals for different types", factory); Object x = factory.create(); Object differentObect = new Object(); log.debug("verifyEqualsDifferentType: Created object x=[" + x + "] and differentObject=[" + differentObect + "] for test."); validationHelper.ensureExists("factory-created object", "test equals for different types", x); if (x.equals(differentObect)) { log.debug("verifyEqualsDifferentType: Equals is incorrect as it found objects of different type to be equal."); AssertionUtils.fail("equals should not find objects of different type to be equal."); } log.debug("verifyEqualsDifferentType: Exiting - Equals is correct when comparing an object of different type."); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy