/* * Copyright 2008, Unitils.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.unitils.reflectionassert; import junit.framework.TestCase; import static org.unitils.reflectionassert.ReflectionComparatorFactory.createRefectionComparator; import static org.unitils.reflectionassert.ReflectionComparatorMode.IGNORE_DEFAULTS; import org.unitils.reflectionassert.difference.Difference; import static org.unitils.reflectionassert.util.InnerDifferenceFinder.getInnerDifference; import static java.lang.Boolean.FALSE; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; /** * Test class for {@link ReflectionComparator}. * * @author Tim Ducheyne * @author Filip Neven */ public class ReflectionComparatorTest extends TestCase { /* Test object */ private Objects objectsA; /* Same as A but different instance */ private Objects objectsB; /* Same as A and B but different string value for stringValue2 */ private Objects objectsDifferentValue; /* Test object containing a null value */ private Objects objectsNullValue; /* Test object with inner object */ private Objects objectsInnerA; /* Same as innerA but different instance */ private Objects objectsInnerB; /* Same as innerA and innerB but different int value for inner intValue2 */ private Objects objectsInnerDifferentValue; /* Test object containing a circular dependency to itself */ private Objects objectsCircularDependencyA; /* Same as circularDependencyA but different instance */ private Objects objectsCircularDependencyB; /* Class under test */ private ReflectionComparator reflectionComparator, ignoreDefaultReflectionComparator; /** * Initializes the test fixture. */ protected void setUp() throws Exception { super.setUp(); objectsA = new Objects("test 1", "test 2", null); objectsB = new Objects("test 1", "test 2", null); objectsDifferentValue = new Objects("test 1", "XXXXXX", null); objectsNullValue = new Objects("test 1", null, null); objectsInnerA = new Objects(null, null, objectsA); objectsInnerB = new Objects(null, null, objectsB); objectsInnerDifferentValue = new Objects(null, null, objectsDifferentValue); objectsCircularDependencyA = new Objects(null, null, new Objects(null, null, new Objects(null, null, null))); objectsCircularDependencyB = new Objects(null, null, new Objects(null, null, new Objects(null, null, null))); // create a circular dependency objectsCircularDependencyA.getInner().getInner().setInner(objectsCircularDependencyA); objectsCircularDependencyB.getInner().getInner().setInner(objectsCircularDependencyB); reflectionComparator = createRefectionComparator(); ignoreDefaultReflectionComparator = createRefectionComparator(IGNORE_DEFAULTS); } /** * Test for two equal objects. */ public void testGetAllDifferences_equals() { Difference result = reflectionComparator.getDifference(objectsA, objectsB); assertNull(result); } /** * Test for two equal objects as an inner field of an object. */ public void testGetAllDifferences_equalsInner() { Difference result = reflectionComparator.getDifference(objectsInnerA, objectsInnerB); assertNull(result); } /** * Test case for 2 equal objects that contain a circular reference. This may not cause an infinite loop. */ public void testGetAllDifferences_equalsCircularDependency() { Difference result = reflectionComparator.getDifference(objectsCircularDependencyA, objectsCircularDependencyB); assertNull(result); } /** * Test for two objects that contain different values. */ public void testGetAllDifferences_notEqualsDifferentValues() { Difference result = reflectionComparator.getDifference(objectsA, objectsDifferentValue); Difference difference = getInnerDifference("string2", result); assertEquals("test 2", difference.getLeftValue()); assertEquals("XXXXXX", difference.getRightValue()); } /** * Test case for 2 objects with a right value null. */ public void testGetAllDifferences_notEqualsRightNull() { Difference result = reflectionComparator.getDifference(objectsA, objectsNullValue); Difference difference = getInnerDifference("string2", result); assertEquals("test 2", difference.getLeftValue()); assertEquals(null, difference.getRightValue()); } /** * Test case for 2 objects with a left value null. */ public void testGetAllDifferences_notEqualsLeftNull() { Difference result = reflectionComparator.getDifference(objectsNullValue, objectsA); Difference difference = getInnerDifference("string2", result); assertEquals(null, difference.getLeftValue()); assertEquals("test 2", difference.getRightValue()); } /** * Test for objects with inner objects that contain different values. */ public void testGetAllDifferences_notEqualsInnerDifferentValues() { Difference result = reflectionComparator.getDifference(objectsInnerA, objectsInnerDifferentValue); Difference difference = getInnerDifference("string2", getInnerDifference("inner", result)); assertEquals("test 2", difference.getLeftValue()); assertEquals("XXXXXX", difference.getRightValue()); } /** * Test case for a null left-argument. */ public void testGetAllDifferences_leftNull() { Difference result = reflectionComparator.getDifference(null, objectsA); assertEquals(null, result.getLeftValue()); assertSame(objectsA, result.getRightValue()); } /** * Test case for a null right-argument. */ public void testGetAllDifferences_rightNull() { Difference result = reflectionComparator.getDifference(objectsA, null); assertSame(objectsA, result.getLeftValue()); assertEquals(null, result.getRightValue()); } /** * Test case for both null arguments. */ public void testGetAllDifferences_null() { Difference result = reflectionComparator.getDifference(null, null); assertNull(result); } /** * Test for two equal objects. */ public void testIsEqual() { boolean result = reflectionComparator.isEqual(objectsA, objectsB); assertTrue(result); } /** * Test for ignored default left value and to check that the right value is not being evaluated (causing a lazy * loading). */ public void testGetAllDifferences_equalsIgnoredDefaultNoLazyLoading() { // create a proxy, that will fail if is accessed Collection<?> collection = (Collection<?>) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Collection.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("equals".equals(method.getName())) { return FALSE; } if ("hashCode".equals(method.getName())) { return -1; } fail("Should not be invoked"); return null; } }); Difference result = ignoreDefaultReflectionComparator.getDifference(new CollectionWrapper(null), new CollectionWrapper(collection)); assertNull(result); } /** * Test for two objects that contain different values. */ public void testGetAllDifference_notEqualsMultipleDifferentValues() { objectsDifferentValue.string1 = "YYYYYY"; Difference result = reflectionComparator.getDifference(objectsA, objectsDifferentValue); Difference difference1 = getInnerDifference("string1", result); assertEquals("test 1", difference1.getLeftValue()); assertEquals("YYYYYY", difference1.getRightValue()); Difference difference2 = getInnerDifference("string2", result); assertEquals("test 2", difference2.getLeftValue()); assertEquals("XXXXXX", difference2.getRightValue()); } /** * Test class with failing equals. */ private class Objects { /* A fist object value */ private String string1; /* A second object value */ private String string2; /* An inner object */ private Objects inner; /** * Creates and initializes the objects instance. * * @param stringValue1 the first object value * @param stringValue2 the second object value * @param inner the inner collection */ public Objects(String stringValue1, String stringValue2, Objects inner) { this.string1 = stringValue1; this.string2 = stringValue2; this.inner = inner; } /** * Gets the first object value * * @return the value */ public String getString1() { return string1; } /** * Gets the second object value * * @return the value */ public String getString2() { return string2; } /** * Gets the inner object * * @return the object */ public Objects getInner() { return inner; } /** * Sets the inner object * * @param inner the object */ public void setInner(Objects inner) { this.inner = inner; } /** * Always returns false * * @param o the object to compare to */ @Override public boolean equals(Object o) { return false; } } /** * Test class with a Collection as field. This is declared as interface so that a proxy can be installed in the * field. */ private class CollectionWrapper { /* Collection instance */ protected Collection<?> innerCollection; /** * Creates a wrapper for the given collection. * * @param innerCollection The collection */ public CollectionWrapper(Collection<?> innerCollection) { this.innerCollection = innerCollection; } } }