package com.cedarsoftware.util; import com.cedarsoftware.util.io.JsonReader; import com.cedarsoftware.util.io.JsonWriter; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import static com.cedarsoftware.util.DeepEquals.deepEquals; import static com.cedarsoftware.util.GraphComparator.Delta.Command.ARRAY_RESIZE; import static com.cedarsoftware.util.GraphComparator.Delta.Command.ARRAY_SET_ELEMENT; import static com.cedarsoftware.util.GraphComparator.Delta.Command.LIST_RESIZE; import static com.cedarsoftware.util.GraphComparator.Delta.Command.LIST_SET_ELEMENT; import static com.cedarsoftware.util.GraphComparator.Delta.Command.MAP_PUT; import static com.cedarsoftware.util.GraphComparator.Delta.Command.MAP_REMOVE; import static com.cedarsoftware.util.GraphComparator.Delta.Command.OBJECT_ASSIGN_FIELD; import static com.cedarsoftware.util.GraphComparator.Delta.Command.OBJECT_FIELD_TYPE_CHANGED; import static com.cedarsoftware.util.GraphComparator.Delta.Command.OBJECT_ORPHAN; import static com.cedarsoftware.util.GraphComparator.Delta.Command.SET_ADD; import static com.cedarsoftware.util.GraphComparator.Delta.Command.SET_REMOVE; import static com.cedarsoftware.util.GraphComparator.Delta.Command.fromName; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Test for GraphComparator * * @author John DeRegnaucourt */ public class TestGraphComparator { private static final int SET_TYPE_HASH = 1; private static final int SET_TYPE_TREE = 2; private static final int SET_TYPE_LINKED = 3; public interface HasId { Object getId(); } private static class Person implements HasId { long id; String first; String last; Pet favoritePet; Pet[] pets; public Object getId() { return id; } } private class Document implements HasId { long id; Person party1; Person party2; Person party3; public Object getId() { return id; } } private static class Pet implements HasId { long id; String name; String type; int age; String[] nickNames; private Pet(long id, String name, String type, int age, String[] nickNames) { this.id = id; this.name = name == null ? null : new String(name); this.type = type == null ? null : new String(type); this.age = age; this.nickNames = nickNames; } public Object getId() { return id; } } private static class Employee implements HasId { long id; String first; String last; Collection<Address> addresses; Address mainAddress; public Object getId() { return id; } public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Employee employee = (Employee) o; if (id != employee.id) { return false; } if (first != null ? !first.equals(employee.first) : employee.first != null) { return false; } if (last != null ? !last.equals(employee.last) : employee.last != null) { return false; } if (mainAddress != null ? !mainAddress.equals(employee.mainAddress) : employee.mainAddress != null) { return false; } if (addresses == null || employee.addresses == null) { return addresses == employee.addresses; } if (addresses.size() != employee.addresses.size()) { return false; } for (Address left : addresses) { Iterator j = employee.addresses.iterator(); boolean found = false; while (j.hasNext()) { if (left.equals(j.next())) { found = true; break; } } if (!found) { return false; } } return true; } public int hashCode() { int result = (int) (id ^ (id >>> 32)); result = 31 * result + (first != null ? first.hashCode() : 0); result = 31 * result + (last != null ? last.hashCode() : 0); result = 31 * result + (addresses != null ? addresses.hashCode() : 0); result = 31 * result + (mainAddress != null ? mainAddress.hashCode() : 0); return result; } } private static class Address implements HasId { long id; String street; String state; String city; int zip; Collection junk; public Object getId() { return id; } public Collection getJunk() { return junk; } public void setJunk(Collection col) { junk = col; } public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Address address = (Address) o; if (id != address.id) { return false; } if (zip != address.zip) { return false; } if (city != null ? !city.equals(address.city) : address.city != null) { return false; } if (state != null ? !state.equals(address.state) : address.state != null) { return false; } if (street != null ? !street.equals(address.street) : address.street != null) { return false; } if (junk == null || address.junk == null) { return junk == address.junk; } return junk.equals(address.junk); } public int hashCode() { int result = (int) (id ^ (id >>> 32)); result = 31 * result + (street != null ? street.hashCode() : 0); result = 31 * result + (state != null ? state.hashCode() : 0); result = 31 * result + (city != null ? city.hashCode() : 0); result = 31 * result + zip; result = 31 * result + (junk != null ? junk.hashCode() : 0); return result; } } private static class Dictionary implements HasId { long id; String name; Map contents; public Object getId() { return id; } } private static class ObjectArray implements HasId { long id; Object[] array; public Object getId() { return id; } } private static class ListContainer implements HasId { long id; List list; public Object getId() { return id; } } private static class Dude implements HasId { private long id; private UnidentifiedObject dude; public Object getId() { return id; } } private static class UnidentifiedObject { private final String name; private final int age; private final List<Pet> pets = new ArrayList<>(); private UnidentifiedObject(String name, int age) { this.name = name; this.age = age; } public void addPet(Pet p) { pets.add(p); } } @Test public void testAlpha() { // TODO: Need to find faster way to get last IP address (problem for unique id generator, not GraphComparator) UniqueIdGenerator.getUniqueId(); } @Test public void testSimpleObjectDifference() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; Person p2 = persons[1]; p2.first = "Jack"; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("first".equals(delta.getFieldName())); assertNull(delta.getOptionalKey()); assertTrue("John".equals(delta.getSourceValue())); assertTrue("Jack".equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testNullingField() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; Pet savePet = persons[0].favoritePet; persons[1].favoritePet = null; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("favoritePet".equals(delta.getFieldName())); assertNull(delta.getOptionalKey()); assertTrue(savePet == delta.getSourceValue()); assertTrue(null == delta.getTargetValue()); assertTrue((Long) delta.getId() == id); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // An element within an array having a primitive field differences // on elements within the array. @Test public void testArrayItemDifferences() throws Exception { Person[] persons = createTwoPersons(); Person p2 = persons[1]; p2.pets[0].name = "Edward"; p2.pets[1].age = 2; long edId = persons[0].pets[0].id; long bellaId = persons[0].pets[1].id; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertEquals(2, deltas.size()); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("name".equals(delta.getFieldName())); assertNull(delta.getOptionalKey()); assertTrue("Eddie".equals(delta.getSourceValue())); assertTrue("Edward".equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == edId); delta = deltas.get(1); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("age".equals(delta.getFieldName())); assertNull(delta.getOptionalKey()); assertTrue(1 == (Integer) delta.getSourceValue()); assertTrue(2 == (Integer) delta.getTargetValue()); assertTrue((Long) delta.getId() == bellaId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New array is shorter than original @Test public void testShortenArray() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; long bellaId = persons[0].pets[1].id; Person p2 = persons[1]; p2.pets = new Pet[1]; p2.pets[0] = persons[0].pets[0]; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(persons[0].pets.equals(delta.getSourceValue())); assertTrue(persons[1].pets.equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); assertTrue(1 == (Integer) delta.getOptionalKey()); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertTrue((Long) delta.getId() == bellaId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New array has no elements (but not null) @Test public void testShortenArrayToZeroLength() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; long bellaId = persons[0].pets[1].id; Person p2 = persons[1]; p2.pets = new Pet[0]; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(persons[0].pets.equals(delta.getSourceValue())); assertTrue(persons[1].pets.equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); assertTrue(0 == (Integer) delta.getOptionalKey()); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertTrue((Long) delta.getId() == bellaId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New array has no elements (but not null) @Test public void testShortenPrimitiveArrayToZeroLength() throws Exception { Person[] persons = createTwoPersons(); long petId = persons[0].pets[0].id; persons[1].pets[0].nickNames = new String[]{}; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); // No orphan command in Delta list because this is an array of primitives (only 1 delta, not 2 like above) assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(persons[0].pets[0].nickNames.equals(delta.getSourceValue())); assertTrue(persons[1].pets[0].nickNames.equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == petId); assertTrue(0 == (Integer) delta.getOptionalKey()); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New array is longer than original @Test public void testLengthenArray() throws Exception { Person[] persons = createTwoPersons(); long pid = persons[0].id; Person p2 = persons[1]; Pet[] pets = new Pet[3]; System.arraycopy(p2.pets, 0, pets, 0, 2); long id = UniqueIdGenerator.getUniqueId(); pets[2] = new Pet(id, "Andy", "feline", 3, new String[]{"andrew", "candy", "dandy", "dumbo"}); p2.pets = pets; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(persons[0].pets.equals(delta.getSourceValue())); assertTrue(persons[1].pets.equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == pid); assertTrue(3 == (Integer) delta.getOptionalKey()); delta = deltas.get(1); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(2 == (Integer) delta.getOptionalKey()); assertTrue(null == delta.getSourceValue()); assertTrue(pets[2].equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == pid); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testNullOutArrayElements() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; long bellaId = persons[0].pets[1].id; Person p2 = persons[1]; p2.pets[0] = null; p2.pets[1] = null; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 3); GraphComparator.Delta delta = deltas.get(1); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(0 == (Integer) delta.getOptionalKey()); assertTrue(persons[0].pets[0].equals(delta.getSourceValue())); assertTrue(null == delta.getTargetValue()); assertTrue((Long) delta.getId() == id); delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(1 == (Integer) delta.getOptionalKey()); assertTrue(persons[0].pets[1].equals(delta.getSourceValue())); assertTrue(null == delta.getTargetValue()); assertTrue((Long) delta.getId() == id); // Note: Only one orphan (Bella) because Eddie is pointed to by favoritePet field. delta = deltas.get(2); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertTrue((Long) delta.getId() == bellaId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New array is shorter than original array, plus element 0 is what was in element 1 @Test public void testArrayLengthDifferenceAndMove() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; Person p2 = persons[1]; p2.pets = new Pet[1]; p2.pets[0] = persons[0].pets[1]; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(persons[0].pets.equals(delta.getSourceValue())); assertTrue(persons[1].pets.equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); assertTrue(1 == (Integer) delta.getOptionalKey()); delta = deltas.get(1); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(0 == (Integer) delta.getOptionalKey()); assertTrue(p2.pets[0].equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } // New element set into an array @Test public void testNewArrayElement() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; long edId = persons[0].pets[0].id; Person p2 = persons[1]; p2.pets[0] = new Pet(UniqueIdGenerator.getUniqueId(), "Andy", "feline", 3, new String[]{"fat cat"}); p2.favoritePet = p2.pets[0]; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 3); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(0 == (Integer) delta.getOptionalKey()); assertTrue(persons[1].pets[0].equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); delta = deltas.get(1); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("favoritePet".equals(delta.getFieldName())); assertTrue(null == delta.getOptionalKey()); assertTrue(persons[1].pets[0].equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == id); delta = deltas.get(2); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertTrue(edId == (Long) delta.getId()); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); assertTrue(persons[0].pets[0] == persons[0].favoritePet); // Ensure same instance is used in array and favoritePet field } @Test public void testPrimitiveArrayElementDifferences() throws Exception { Person[] persons = createTwoPersons(); long edId = persons[0].pets[0].id; Person p2 = persons[1]; p2.pets[0].nickNames[0] = null; p2.pets[0].nickNames[1] = "bobo"; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(0 == (Integer) delta.getOptionalKey()); assertTrue(persons[0].pets[0].nickNames[0].equals(delta.getSourceValue())); assertTrue(null == delta.getTargetValue()); assertTrue((Long) delta.getId() == edId); delta = deltas.get(1); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(1 == (Integer) delta.getOptionalKey()); assertTrue(persons[0].pets[0].nickNames[1].equals(delta.getSourceValue())); assertTrue("bobo".equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == edId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testLengthenPrimitiveArray() throws Exception { Person[] persons = createTwoPersons(); long bellaId = persons[0].pets[1].id; Person p2 = persons[1]; int len = p2.pets[1].nickNames.length; String[] nickNames = new String[len + 1]; System.arraycopy(p2.pets[1].nickNames, 0, nickNames, 0, len); nickNames[len] = "Scissor hands"; p2.pets[1].nickNames = nickNames; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_RESIZE == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(4 == (Integer) delta.getOptionalKey()); assertTrue(persons[0].pets[1].nickNames.equals(delta.getSourceValue())); assertTrue(nickNames == delta.getTargetValue()); assertTrue((Long) delta.getId() == bellaId); delta = deltas.get(1); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(3 == (Integer) delta.getOptionalKey()); assertTrue(null == delta.getSourceValue()); assertTrue("Scissor hands".equals(delta.getTargetValue())); assertTrue((Long) delta.getId() == bellaId); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testNullObjectArrayField() throws Exception { Person[] persons = createTwoPersons(); long id = persons[0].id; long bellaId = persons[0].pets[1].id; Person p2 = persons[1]; p2.pets = null; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("pets".equals(delta.getFieldName())); assertTrue(persons[0].pets.equals(delta.getSourceValue())); assertTrue(persons[1].pets == delta.getTargetValue()); assertTrue((Long) delta.getId() == id); assertNull(delta.getOptionalKey()); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertTrue((Long) delta.getId() == bellaId); // Eddie not orphaned because favoritePet field still points to him GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testNullPrimitiveArrayField() throws Exception { Person[] persons = createTwoPersons(); persons[1].pets[0].nickNames = null; long id = persons[1].pets[0].id; assertFalse(deepEquals(persons[0], persons[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], persons[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("nickNames".equals(delta.getFieldName())); assertTrue(persons[0].pets[0].nickNames.equals(delta.getSourceValue())); assertTrue(persons[1].pets[0].nickNames == delta.getTargetValue()); assertTrue((Long) delta.getId() == id); assertNull(delta.getOptionalKey()); GraphComparator.applyDelta(persons[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(persons[0], persons[1])); } @Test public void testObjectArrayWithPrimitives() throws Exception { ObjectArray source = new ObjectArray(); source.id = UniqueIdGenerator.getUniqueId(); source.array = new Object[]{'a', 'b', 'c', 'd'}; ObjectArray target = (ObjectArray) clone(source); target.array[3] = 5; assertFalse(deepEquals(source, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(source, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertEquals("array", delta.getFieldName()); assertEquals(3, delta.getOptionalKey()); assertEquals('d', delta.getSourceValue()); assertEquals(5, delta.getTargetValue()); GraphComparator.applyDelta(source, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(source, target)); } @Test public void testObjectArrayWithArraysAsElements() throws Exception { ObjectArray source = new ObjectArray(); source.id = UniqueIdGenerator.getUniqueId(); source.array = new Object[]{new String[]{"1a", "1b", "1c"}, new String[]{"2a", "2b", "2c"}}; ObjectArray target = (ObjectArray) clone(source); String[] strings = (String[]) target.array[1]; strings[2] = "2C"; assertFalse(deepEquals(source, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(source, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertEquals("array", delta.getFieldName()); assertEquals(1, delta.getOptionalKey()); assertTrue(((String[]) delta.getSourceValue())[2] == "2c"); assertTrue(((String[]) delta.getTargetValue())[2] == "2C"); GraphComparator.applyDelta(source, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(source, target)); } @Test public void testArraySetElementOutOfBounds() throws Exception { ObjectArray src = new ObjectArray(); src.array = new Object[3]; src.array[0] = "one"; src.array[1] = 2; src.array[2] = 3L; ObjectArray target = new ObjectArray(); target.array = new Object[3]; target.array[0] = "one"; target.array[1] = 2; target.array[2] = null; assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(ARRAY_SET_ELEMENT == delta.getCmd()); assertEquals("array", delta.getFieldName()); assertEquals(2, delta.getOptionalKey()); delta.setOptionalKey(20); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); GraphComparator.DeltaError error = errors.get(0); assertTrue(error.getError().contains("ARRAY_SET_ELEMENT")); assertTrue(error.getError().contains("failed")); } @Test public void testSetRemoveNonPrimitive() throws Exception { Employee[] employees = createTwoEmployees(SET_TYPE_LINKED); long id = employees[0].id; Iterator i = employees[1].addresses.iterator(); employees[1].addresses.remove(i.next()); assertFalse(deepEquals(employees[0], employees[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(employees[0], employees[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(SET_REMOVE == delta.getCmd()); assertTrue("addresses".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertNull(delta.getTargetValue()); assertNull(delta.getOptionalKey()); assertTrue(employees[0].addresses.iterator().next().equals(delta.getSourceValue())); GraphComparator.applyDelta(employees[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(employees[0], employees[1])); } @Test public void testSetAddNonPrimitive() throws Exception { Employee[] employees = createTwoEmployees(SET_TYPE_HASH); long id = employees[0].id; Address addr = new Address(); addr.zip = 90210; addr.state = "CA"; addr.id = UniqueIdGenerator.getUniqueId(); addr.city = "Beverly Hills"; addr.street = "1000 Rodeo Drive"; employees[1].addresses.add(addr); assertFalse(deepEquals(employees[0], employees[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(employees[0], employees[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(SET_ADD == delta.getCmd()); assertTrue("addresses".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertTrue(addr.equals(delta.getTargetValue())); assertNull(delta.getSourceValue()); assertNull(delta.getOptionalKey()); GraphComparator.applyDelta(employees[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(employees[0], employees[1])); } @Test public void testSetAddRemovePrimitive() throws Exception { Employee[] employees = createTwoEmployees(SET_TYPE_LINKED); Iterator i = employees[0].addresses.iterator(); Address address = (Address) i.next(); long id = (Long) address.getId(); address.setJunk(new HashSet()); address.getJunk().add("lat/lon"); Date now = new Date(); address.getJunk().add(now); i = employees[1].addresses.iterator(); address = (Address) i.next(); address.setJunk(new HashSet()); address.getJunk().add(now); address.getJunk().add(19); assertFalse(deepEquals(employees[0], employees[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(employees[0], employees[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(SET_REMOVE == delta.getCmd()); assertTrue("junk".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertNull(delta.getTargetValue()); assertNull(delta.getOptionalKey()); assertTrue("lat/lon".equals(delta.getSourceValue())); delta = deltas.get(1); assertTrue(SET_ADD == delta.getCmd()); assertTrue("junk".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertNull(delta.getSourceValue()); assertNull(delta.getOptionalKey()); assertTrue(19 == (Integer) delta.getTargetValue()); GraphComparator.applyDelta(employees[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(employees[0], employees[1])); } @Test public void testNullSetField() throws Exception { Employee[] employees = createTwoEmployees(SET_TYPE_HASH); long id = employees[0].id; employees[1].addresses = null; assertFalse(deepEquals(employees[0], employees[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(employees[0], employees[1], getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("addresses".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertNull(delta.getTargetValue()); assertNull(delta.getOptionalKey()); assertTrue(employees[0].addresses.equals(delta.getSourceValue())); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); GraphComparator.applyDelta(employees[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(employees[0], employees[1])); } @Test public void testMapPut() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); long id = dictionaries[0].id; dictionaries[1].contents.put("Entry2", "Foo"); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_PUT == delta.getCmd()); assertTrue("contents".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertEquals(delta.getTargetValue(), "Foo"); assertEquals(delta.getOptionalKey(), "Entry2"); assertNull(delta.getSourceValue()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapRemove() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); long id = dictionaries[0].id; dictionaries[1].contents.remove("Eddie"); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_REMOVE == delta.getCmd()); assertTrue("contents".equals(delta.getFieldName())); assertTrue(delta.getId().equals(id)); assertTrue(delta.getSourceValue() instanceof Pet); assertEquals(delta.getOptionalKey(), "Eddie"); assertNull(delta.getTargetValue()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapRemoveUntilEmpty() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); long id = dictionaries[0].id; dictionaries[1].contents.clear(); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 5); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_REMOVE == delta.getCmd()); assertTrue("contents".equals(delta.getFieldName())); assertNull(delta.getTargetValue()); delta = deltas.get(1); assertTrue(MAP_REMOVE == delta.getCmd()); assertTrue("contents".equals(delta.getFieldName())); assertNull(delta.getTargetValue()); delta = deltas.get(2); assertTrue(OBJECT_ORPHAN == delta.getCmd()); delta = deltas.get(3); assertTrue(OBJECT_ORPHAN == delta.getCmd()); delta = deltas.get(4); assertTrue(OBJECT_ORPHAN == delta.getCmd()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapFieldAssignToNull() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); dictionaries[1].contents = null; assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 4); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertTrue("contents".equals(delta.getFieldName())); assertNull(delta.getTargetValue()); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); delta = deltas.get(2); assertTrue(OBJECT_ORPHAN == delta.getCmd()); delta = deltas.get(3); assertTrue(OBJECT_ORPHAN == delta.getCmd()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapValueChange() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); Person p = (Person) dictionaries[0].contents.get("DeRegnaucourt"); dictionaries[1].contents.put("Eddie", p.pets[1]); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_PUT == delta.getCmd()); assertEquals("contents", delta.getFieldName()); assertEquals("Eddie", delta.getOptionalKey()); assertTrue(delta.getTargetValue() instanceof Pet); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapValueChangeToNull() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); dictionaries[1].contents.put("Eddie", null); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_PUT == delta.getCmd()); assertEquals("contents", delta.getFieldName()); assertEquals("Eddie", delta.getOptionalKey()); assertNull(delta.getTargetValue()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } @Test public void testMapValueChangeToPrimitive() throws Exception { Dictionary[] dictionaries = createTwoDictionaries(); dictionaries[1].contents.put("Eddie", Boolean.TRUE); assertFalse(deepEquals(dictionaries[0], dictionaries[1])); List<GraphComparator.Delta> deltas = GraphComparator.compare(dictionaries[0], dictionaries[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(MAP_PUT == delta.getCmd()); assertEquals("contents", delta.getFieldName()); assertEquals("Eddie", delta.getOptionalKey()); assertTrue((Boolean) delta.getTargetValue()); GraphComparator.applyDelta(dictionaries[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(dictionaries[0], dictionaries[1])); } // An element within a List having a primitive field differences // on elements within the List. @Test public void testListItemDifferences() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add("one"); target.list.add(2L); target.list.add(3L); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(1, delta.getOptionalKey()); assertEquals(2, delta.getSourceValue()); assertEquals(2L, delta.getTargetValue()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } // New array is shorter than original @Test public void testShortenList() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add("one"); target.list.add(2); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_RESIZE == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(2, delta.getOptionalKey()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } // New List has no elements (but not null) @Test public void testShortenListToZeroLength() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_RESIZE == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(0, delta.getOptionalKey()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } // New List is longer than original @Test public void testLengthenList() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add("one"); target.list.add(2); target.list.add(3L); target.list.add(Boolean.TRUE); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_RESIZE == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(4, delta.getOptionalKey()); delta = deltas.get(1); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(3, delta.getOptionalKey()); assertNull(delta.getSourceValue()); assertEquals(true, delta.getTargetValue()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testNullOutListElements() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add(null); target.list.add(null); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 3); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_RESIZE == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(2, delta.getOptionalKey()); delta = deltas.get(2); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(0, delta.getOptionalKey()); assertNotNull(delta.getSourceValue()); assertNull(delta.getTargetValue()); delta = deltas.get(1); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(1, delta.getOptionalKey()); assertNotNull(delta.getSourceValue()); assertNull(delta.getTargetValue()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testNullListField() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = null; assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertNull(delta.getOptionalKey()); assertNotNull(delta.getSourceValue()); assertNull(delta.getTargetValue()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testChangeListElementField() throws Exception { Person[] persons = createTwoPersons(); Pet dog1 = persons[0].pets[0]; Pet dog2 = persons[0].pets[1]; ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add(dog1); src.list.add(dog2); ListContainer target = (ListContainer) clone(src); Pet dog2copy = (Pet) target.list.get(1); dog2copy.age = 7; assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertEquals("age", delta.getFieldName()); assertNull(delta.getOptionalKey()); assertEquals(1, delta.getSourceValue()); assertEquals(7, delta.getTargetValue()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testReplaceListElementObject() throws Exception { Pet dog1 = getPet("Eddie"); Pet dog2 = getPet("Bella"); ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add(dog1); src.list.add(dog2); ListContainer target = (ListContainer) clone(src); Pet fido = new Pet(UniqueIdGenerator.getUniqueId(), "Fido", "canine", 3, new String[]{"Buddy", "Captain D-Bag", "Sam"}); target.list.set(1, fido); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(1, delta.getOptionalKey()); assertEquals(dog2, delta.getSourceValue()); assertEquals(fido, delta.getTargetValue()); delta = deltas.get(1); assertTrue(OBJECT_ORPHAN == delta.getCmd()); assertEquals(dog2.id, delta.getId()); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testBadResizeValue() { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_RESIZE == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(0, delta.getOptionalKey()); delta.setOptionalKey(-1); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); GraphComparator.DeltaError error = errors.get(0); assertTrue(error.getError().contains("LIST_RESIZE")); assertTrue(error.getError().contains("failed")); } @Test public void testDiffListTypes() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new LinkedList(); target.list.add("one"); target.list.add(2); target.list.add(3L); assertTrue(deepEquals(src, target)); // Prove that it ignored List type and only considered the contents List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.isEmpty()); } @Test public void testDiffCollectionTypes() throws Exception { Employee emps[] = createTwoEmployees(SET_TYPE_LINKED); Employee empTarget = emps[1]; empTarget.addresses = new ArrayList(); empTarget.addresses.addAll(emps[0].addresses); List<GraphComparator.Delta> deltas = GraphComparator.compare(emps[0], empTarget, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertEquals(delta.getCmd(), OBJECT_FIELD_TYPE_CHANGED); assertEquals(delta.getFieldName(), "addresses"); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(emps[0], deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); GraphComparator.DeltaError error = errors.get(0); assertTrue(error.getError().contains("OBJECT_FIELD_TYPE_CHANGED")); assertTrue(error.getError().contains("failed")); } @Test public void testListSetElementOutOfBounds() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); src.list.add(2); src.list.add(3L); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add("one"); target.list.add(2); target.list.add(null); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(2, delta.getOptionalKey()); delta.setOptionalKey(20); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); GraphComparator.DeltaError error = errors.get(0); assertTrue(error.getError().contains("LIST_SET_ELEMENT")); assertTrue(error.getError().contains("failed")); } @Test public void testDeltaSetterGetter() { GraphComparator.Delta delta = new GraphComparator.Delta(0, "foo", null, null, null, null); delta.setCmd(OBJECT_ASSIGN_FIELD); assertEquals(OBJECT_ASSIGN_FIELD, delta.getCmd()); delta.setFieldName("field"); assertEquals("field", delta.getFieldName()); delta.setId(9); assertEquals(9, delta.getId()); delta.setOptionalKey(6); assertEquals(6, delta.getOptionalKey()); delta.setSourceValue('a'); assertEquals('a', delta.getSourceValue()); delta.setTargetValue(Boolean.TRUE); assertEquals(true, delta.getTargetValue()); assertNotNull(delta.toString()); } @Test public void testDeltaCommandBadEnums() throws Exception { try { GraphComparator.Delta.Command cmd = fromName(null); fail("Should have thrown exception for null enum"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { GraphComparator.Delta.Command cmd = fromName("jonas"); fail("Should have thrown exception for unknown enum"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } @Test public void testApplyDeltaWithCommandParams() throws Exception { ListContainer src = new ListContainer(); src.list = new ArrayList(); src.list.add("one"); ListContainer target = new ListContainer(); target.list = new ArrayList(); target.list.add("once"); assertFalse(deepEquals(src, target)); List<GraphComparator.Delta> deltas = GraphComparator.compare(src, target, getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(LIST_SET_ELEMENT == delta.getCmd()); assertEquals("list", delta.getFieldName()); assertEquals(0, delta.getOptionalKey()); Object id = delta.getId(); delta.setId(19); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); GraphComparator.DeltaError error = errors.get(0); assertTrue(error.getError().contains("LIST_SET_ELEMENT")); assertTrue(error.getError().contains("failed")); delta.setId(id); String name = delta.getFieldName(); delta.setFieldName(null); errors = GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 1); error = errors.get(0); assertTrue(error.getError().contains("LIST_SET_ELEMENT")); assertTrue(error.getError().contains("failed")); delta.setFieldName(name); GraphComparator.applyDelta(src, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(src, target)); } @Test public void testNullSource() throws Exception { Person[] persons = createTwoPersons(); persons[1].first = "Dracula"; List<GraphComparator.Delta> deltas = GraphComparator.compare(null, persons[1], getIdFetcher()); assertTrue(deltas.size() == 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertEquals(GraphComparator.ROOT, delta.getFieldName()); assertNull(delta.getSourceValue()); assertEquals(persons[1], delta.getTargetValue()); assertNull(delta.getOptionalKey()); } @Test public void testNullTarget() throws Exception { Person[] persons = createTwoPersons(); List<GraphComparator.Delta> deltas = GraphComparator.compare(persons[0], null, getIdFetcher()); GraphComparator.Delta delta = deltas.get(0); assertTrue(OBJECT_ASSIGN_FIELD == delta.getCmd()); assertEquals(GraphComparator.ROOT, delta.getFieldName()); assertEquals(delta.getSourceValue(), persons[0]); assertNull(delta.getTargetValue()); assertNull(delta.getOptionalKey()); delta = deltas.get(1); assertTrue(delta.getCmd() == OBJECT_ORPHAN); assertNull(delta.getOptionalKey()); assertNull(delta.getFieldName()); assertNotNull(delta.getId()); delta = deltas.get(2); assertTrue(delta.getCmd() == OBJECT_ORPHAN); assertNull(delta.getOptionalKey()); assertNull(delta.getFieldName()); assertNotNull(delta.getId()); delta = deltas.get(3); assertTrue(delta.getCmd() == OBJECT_ORPHAN); assertNull(delta.getOptionalKey()); assertNull(delta.getFieldName()); assertNotNull(delta.getId()); } @Test public void testRootArray() throws Exception { Pet eddie = getPet("Eddie"); Pet bella = getPet("Bella"); Pet andy = getPet("Andy"); Object[] srcPets = new Object[]{eddie, bella}; Object[] targetPets = new Object[]{eddie, andy}; assertFalse(deepEquals(srcPets, targetPets)); List<GraphComparator.Delta> deltas = GraphComparator.compare(srcPets, targetPets, getIdFetcher()); assertEquals(deltas.size(), 2); GraphComparator.Delta delta = deltas.get(0); assertTrue(delta.getCmd() == ARRAY_SET_ELEMENT); assertEquals(delta.getOptionalKey(), 1); assertEquals(delta.getFieldName(), GraphComparator.ROOT); assertTrue(deepEquals(delta.getTargetValue(), andy)); delta = deltas.get(1); assertTrue(delta.getCmd() == OBJECT_ORPHAN); assertNull(delta.getOptionalKey()); assertNull(delta.getFieldName()); assertEquals(delta.getId(), bella.id); } @Test public void testUnidentifiedObject() throws Exception { Dude sourceDude = getDude("Dan", 48); Dude targetDude = (Dude) clone(sourceDude); assertTrue(deepEquals(sourceDude, targetDude)); targetDude.dude.pets.get(0).name = "bunny"; assertFalse(deepEquals(sourceDude, targetDude)); List<GraphComparator.Delta> deltas = GraphComparator.compare(sourceDude, targetDude, getIdFetcher()); assertEquals(deltas.size(), 1); GraphComparator.Delta delta = deltas.get(0); assertTrue(delta.getCmd() == OBJECT_ASSIGN_FIELD); assertNull(delta.getOptionalKey()); assertEquals(delta.getFieldName(), "dude"); GraphComparator.applyDelta(sourceDude, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(deepEquals(sourceDude, targetDude)); } @Test public void testDeltaCommand() throws Exception { GraphComparator.Delta.Command cmd = MAP_PUT; assertEquals(cmd.getName(), "map.put"); GraphComparator.Delta.Command remove = cmd.fromName("map.remove"); assertTrue(remove == MAP_REMOVE); } @Test public void testApplyDeltaFailFast() throws Exception { Pet eddie = getPet("Eddie"); Pet bella = getPet("Bella"); Pet andy = getPet("Andy"); Object[] srcPets = new Object[]{eddie, bella}; Object[] targetPets = new Object[]{eddie, andy}; assertFalse(deepEquals(srcPets, targetPets)); List<GraphComparator.Delta> deltas = GraphComparator.compare(srcPets, targetPets, getIdFetcher()); assertEquals(deltas.size(), 2); GraphComparator.Delta delta = deltas.get(0); delta.setId(33); delta.setCmd(ARRAY_RESIZE); delta = deltas.get(1); delta.setCmd(LIST_SET_ELEMENT); delta.setFieldName("xyz"); List<GraphComparator.DeltaError> errors = GraphComparator.applyDelta(srcPets, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor()); assertTrue(errors.size() == 2); errors = GraphComparator.applyDelta(srcPets, deltas, getIdFetcher(), GraphComparator.getJavaDeltaProcessor(), true); assertTrue(errors.size() == 1); } @Test public void testSkip() { Person p1 = new Person(); p1.id = 10; p1.first = "George"; p1.last = "Washington"; Person p2 = new Person(); p2.id = 20; p2.first = "John"; p2.last = "Adams"; Person p3 = new Person(); p3.id = 30; p3.first = "Thomas"; p3.last = "Jefferson"; Person p4 = new Person(); p4.id = 40; p4.first = "James"; p4.last = "Madison"; Document doc1 = new Document(); doc1.id = 1; doc1.party1 = p1; doc1.party2 = p2; doc1.party3 = p1; Document doc2 = new Document(); doc2.id = 1; doc2.party1 = p4; doc2.party2 = p2; doc2.party3 = p4; List<GraphComparator.Delta> deltas; deltas = GraphComparator.compare(doc1, doc2, getIdFetcher()); } /** * Initial case * A->B->X * A->C->X * A->D->X * Y (isolated) * Ending case * A->B->Y * A->C->X * A->D->Y * <p/> * Should have two deltas: * 1. B->X goes to B->Y * 2. D->X goes to D->Y */ @Test public void testTwoPointersToSameInstance() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); Doc A = new Doc("A"); A.childB = B; A.childC = C; A.childD = D; Doc Acopy = (Doc) clone(A); Acopy.childB.child = Y; Acopy.childC.child = X; Acopy.childD.child = Y; List<GraphComparator.Delta> deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(deltas.size(), 2); GraphComparator.Delta delta = deltas.get(0); assertEquals(delta.getCmd(), OBJECT_ASSIGN_FIELD); assertTrue(delta.getTargetValue() instanceof Node); Node node = (Node) delta.getTargetValue(); assertEquals(node.name, "Y"); delta = deltas.get(1); assertEquals(delta.getCmd(), OBJECT_ASSIGN_FIELD); assertTrue(delta.getTargetValue() instanceof Node); node = (Node) delta.getTargetValue(); assertEquals(node.name, "Y"); } @Test public void testCycle() throws Exception { Node A = new Node("A"); Node B = new Node("B"); Node C = new Node("C"); A.child = B; B.child = C; C.child = A; Node Acopy = (Node) clone(A); // Equal with cycle List deltas = new ArrayList(); GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(0, deltas.size()); } @Test public void testTwoPointersToSameInstanceArray() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); Object[] A = new Object[3]; A[0] = B; A[1] = C; A[2] = D; Object[] Acopy = (Object[]) clone(A); B = (Node) Acopy[0]; D = (Node) Acopy[2]; B.child = Y; D.child = Y; List deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(2, deltas.size()); } @Test public void testTwoPointersToSameInstanceOrderedCollection() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); List A = new ArrayList(); A.add(B); A.add(C); A.add(D); List Acopy = (List) clone(A); B = (Node) Acopy.get(0); D = (Node) Acopy.get(2); B.child = Y; D.child = Y; List deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(2, deltas.size()); } @Test public void testTwoPointersToSameInstanceUnorderedCollection() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); Set A = new LinkedHashSet(); A.add(B); A.add(C); A.add(D); Set Acopy = (Set) clone(A); Iterator i = Acopy.iterator(); B = (Node) i.next(); i.next(); // skip C D = (Node) i.next(); B.child = Y; D.child = Y; List deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(2, deltas.size()); } @Test public void testTwoPointersToSameInstanceUnorderedMap() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); Map A = new HashMap(); A.put("childB", B); A.put("childC", C); A.put("childD", D); Map Acopy = (Map) clone(A); B = (Node) Acopy.get("childB"); D = (Node) Acopy.get("childD"); B.child = Y; D.child = Y; List deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(2, deltas.size()); } @Test public void testTwoPointersToSameInstanceOrderedMap() throws Exception { Node X = new Node("X"); Node Y = new Node("Y"); Node B = new Node("B", X); Node C = new Node("C", X); Node D = new Node("D", X); Map A = new TreeMap(); A.put("childB", B); A.put("childC", C); A.put("childD", D); Map Acopy = (Map) clone(A); B = (Node) Acopy.get("childB"); D = (Node) Acopy.get("childD"); B.child = Y; D.child = Y; List deltas = GraphComparator.compare(A, Acopy, getIdFetcher()); assertEquals(2, deltas.size()); } // ---------------------------------------------------------- // Helper classes (not tests) // ---------------------------------------------------------- static class Node implements HasId { String name; Node child; Node(String name) { this.name = name; } Node(String name, Node child) { this.name = name; this.child = child; } public Object getId() { return name; } } static class Doc implements HasId { String namex; Node childB; Node childC; Node childD; Doc(String name) { this.namex = name; } public Object getId() { return namex; } } private Dictionary[] createTwoDictionaries() throws Exception { Person[] persons = createTwoPersons(); Dictionary dictionary = new Dictionary(); dictionary.id = UniqueIdGenerator.getUniqueId(); dictionary.name = "Websters"; dictionary.contents = new HashMap(); dictionary.contents.put(persons[0].last, persons[0]); dictionary.contents.put(persons[0].pets[0].name, persons[0].pets[0]); Dictionary dict = (Dictionary) clone(dictionary); return new Dictionary[]{dictionary, dict}; } private Person[] createTwoPersons() throws Exception { Pet dog1 = getPet("eddie"); Pet dog2 = getPet("bella"); Person p1 = new Person(); p1.id = UniqueIdGenerator.getUniqueId(); p1.first = "John"; p1.last = "DeRegnaucourt"; p1.favoritePet = dog1; p1.pets = new Pet[2]; p1.pets[0] = dog1; p1.pets[1] = dog2; Person p2 = (Person) clone(p1); return new Person[]{p1, p2}; } private Pet getPet(String name) { if ("andy".equalsIgnoreCase(name)) { return new Pet(UniqueIdGenerator.getUniqueId(), "Andy", "feline", 3, new String[]{"andrew", "candy", "dandy", "dumbo"}); } else if ("eddie".equalsIgnoreCase(name)) { return new Pet(UniqueIdGenerator.getUniqueId(), "Eddie", "Terrier", 4, new String[]{"edward", "edwardo"}); } else if ("bella".equalsIgnoreCase(name)) { return new Pet(UniqueIdGenerator.getUniqueId(), "Bella", "Chihuahua", 1, new String[]{"bellaboo", "bella weena", "rotten dog"}); } return null; } private Employee[] createTwoEmployees(int setType) throws Exception { Address addr1 = new Address(); addr1.id = UniqueIdGenerator.getUniqueId(); addr1.street = "210 Ballard Drive"; addr1.city = "Springboro"; addr1.state = "OH"; addr1.zip = 45066; Address addr2 = new Address(); addr2.id = UniqueIdGenerator.getUniqueId(); addr2.street = "10101 Pickfair Drive"; addr2.city = "Austin"; addr2.state = "TX"; addr2.zip = 78750; Employee emp1 = new Employee(); emp1.id = UniqueIdGenerator.getUniqueId(); emp1.first = "John"; emp1.last = "DeRegnaucourt"; if (setType == SET_TYPE_HASH) { emp1.addresses = new HashSet<>(); } else if (setType == SET_TYPE_TREE) { emp1.addresses = new TreeSet<>(); } else if (setType == SET_TYPE_LINKED) { emp1.addresses = new LinkedHashSet<>(); } else { throw new RuntimeException("unknown set type: " + setType); } emp1.addresses.add(addr1); emp1.addresses.add(addr2); emp1.mainAddress = addr1; Employee emp2 = (Employee) clone(emp1); return new Employee[]{emp1, emp2}; } private Dude getDude(String name, int age) { Dude dude = new Dude(); dude.id = UniqueIdGenerator.getUniqueId(); dude.dude = new UnidentifiedObject(name, age); dude.dude.addPet(getPet("bella")); dude.dude.addPet(getPet("eddie")); return dude; } private Object clone(Object source) throws Exception { String json = JsonWriter.objectToJson(source); return JsonReader.jsonToJava(json); } private GraphComparator.ID getIdFetcher() { return new GraphComparator.ID() { public Object getId(Object objectToId) { if (objectToId instanceof HasId) { HasId obj = (HasId) objectToId; return obj.getId(); } else if (objectToId instanceof Collection || objectToId instanceof Map) { return null; } throw new RuntimeException("Object does not support getId(): " + (objectToId != null ? objectToId.getClass().getName() : "null")); } }; } }