/* * Copyright 2014 the original author or authors. * * 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.springframework.sync; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class DiffTest { @Test public void noChanges() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); Patch diff = Diff.diff(original, modified); assertEquals(0, diff.size()); } @Test public void nullPropertyToNonNullProperty() throws Exception { Todo original = new Todo(null, "A", false); Todo modified = new Todo(1L, "A", false); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/id", op.getPath()); assertNull(op.getValue()); } @Test public void singleBooleanPropertyChangeOnObject() throws Exception { Todo original = new Todo(1L, "A", false); Todo modified = new Todo(1L, "A", true); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/complete", op.getPath()); assertFalse((Boolean) op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/complete", op.getPath()); assertTrue((Boolean) op.getValue()); } @Test public void singleStringPropertyChangeOnObject() throws Exception { Todo original = new Todo(1L, "A", false); Todo modified = new Todo(1L, "B", false); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/description", op.getPath()); assertEquals("A", op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/description", op.getPath()); assertEquals("B", op.getValue()); } @Test public void singleNumericPropertyChangeOnObject() throws Exception { Todo original = new Todo(1L, "A", false); Todo modified = new Todo(2L, "A", false); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/id", op.getPath()); assertEquals(1L, op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/id", op.getPath()); assertEquals(2L, op.getValue()); } @Test public void changeTwoPropertiesOnObject() throws Exception { Todo original = new Todo(1L, "A", false); Todo modified = new Todo(1L, "B", true); Patch diff = Diff.diff(original, modified); assertEquals(4, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/description", op.getPath()); assertEquals("A", op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/description", op.getPath()); assertEquals("B", op.getValue()); op = ops.get(2); assertEquals("test", op.getOp()); assertEquals("/complete", op.getPath()); assertEquals(false, op.getValue()); op = ops.get(3); assertEquals("replace", op.getOp()); assertEquals("/complete", op.getPath()); assertEquals(true, op.getValue()); } @Test public void singleBooleanPropertyChangeOnItemInList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.get(1).setComplete(true); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(false, op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(true, op.getValue()); } @Test public void singleStringPropertyChangeOnItemInList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.get(1).setDescription("BBB"); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/1/description", op.getPath()); assertEquals("B", op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/1/description", op.getPath()); assertEquals("BBB", op.getValue()); } @Test public void singleMultiplePropertyChangeOnItemInList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.get(1).setComplete(true); modified.get(1).setDescription("BBB"); Patch diff = Diff.diff(original, modified); assertEquals(4, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/1/description", op.getPath()); assertEquals("B", op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/1/description", op.getPath()); assertEquals("BBB", op.getValue()); op = ops.get(2); assertEquals("test", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(false, op.getValue()); op = ops.get(3); assertEquals("replace", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(true, op.getValue()); } @Test public void propertyChangeOnTwoItemsInList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.get(0).setDescription("AAA"); modified.get(1).setComplete(true); Patch diff = Diff.diff(original, modified); assertEquals(4, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/0/description", op.getPath()); assertEquals("A", op.getValue()); op = ops.get(1); assertEquals("replace", op.getOp()); assertEquals("/0/description", op.getPath()); assertEquals("AAA", op.getValue()); op = ops.get(2); assertEquals("test", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(false, op.getValue()); op = ops.get(3); assertEquals("replace", op.getOp()); assertEquals("/1/complete", op.getPath()); assertEquals(true, op.getValue()); } @Test public void insertItemAtBeginningOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(0, new Todo(0L, "Z", false)); Patch diff = Diff.diff(original, modified); assertEquals(1, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/0", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(0L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(false, value.isComplete()); } @Test public void insertTwoItemsAtBeginningOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(0, new Todo(25L, "Y", false)); modified.add(0, new Todo(26L, "Z", true)); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/0", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(26L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(true, value.isComplete()); op = ops.get(1); assertEquals("add", op.getOp()); assertEquals("/1", op.getPath()); value = (Todo) op.getValue(); assertEquals(25L, value.getId().longValue()); assertEquals("Y", value.getDescription()); assertEquals(false, value.isComplete()); } @Test public void insertItemAtMiddleOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(2, new Todo(0L, "Z", false)); Patch diff = Diff.diff(original, modified); assertEquals(1, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/2", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(0L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(false, value.isComplete()); } @Test public void insertTwoItemsAtMiddleOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(2, new Todo(25L, "Y", false)); modified.add(2, new Todo(26L, "Z", true)); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/2", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(26L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(true, value.isComplete()); op = ops.get(1); assertEquals("add", op.getOp()); assertEquals("/3", op.getPath()); value = (Todo) op.getValue(); assertEquals(25L, value.getId().longValue()); assertEquals("Y", value.getDescription()); assertEquals(false, value.isComplete()); } public void insertItemAtEndOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(3, new Todo(0L, "Z", false)); Patch diff = Diff.diff(original, modified); assertEquals(1, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/3", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(0L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(false, value.isComplete()); } @Test public void insertTwoItemsAtEndOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(3, new Todo(25L, "Y", false)); modified.add(4, new Todo(26L, "Z", true)); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/3", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(25L, value.getId().longValue()); assertEquals("Y", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("add", op.getOp()); assertEquals("/4", op.getPath()); value = (Todo) op.getValue(); assertEquals(26L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(true, value.isComplete()); } @Test public void insertItemsAtBeginningAndEndOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.add(0, new Todo(25L, "Y", false)); modified.add(4, new Todo(26L, "Z", true)); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("add", op.getOp()); assertEquals("/0", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(25L, value.getId().longValue()); assertEquals("Y", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("add", op.getOp()); assertEquals("/4", op.getPath()); value = (Todo) op.getValue(); assertEquals(26L, value.getId().longValue()); assertEquals("Z", value.getDescription()); assertEquals(true, value.isComplete()); } @Test public void removeItemFromBeginningOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.remove(0); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/0", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(1L, value.getId().longValue()); assertEquals("A", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("remove", op.getOp()); assertEquals("/0", op.getPath()); } @Test public void removeItemFromMiddleOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.remove(1); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/1", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(2L, value.getId().longValue()); assertEquals("B", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("remove", op.getOp()); assertEquals("/1", op.getPath()); } @Test public void removeItemFromEndOfList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.remove(2); Patch diff = Diff.diff(original, modified); assertEquals(2, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/2", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(3L, value.getId().longValue()); assertEquals("C", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("remove", op.getOp()); assertEquals("/2", op.getPath()); } @Test public void removeAllItemsFromList() throws Exception { List<Todo> original = buildTodoList(); List<Todo> modified = buildTodoList(); modified.remove(0); modified.remove(0); modified.remove(0); Patch diff = Diff.diff(original, modified); assertEquals(6, diff.size()); List<PatchOperation> ops = diff.getOperations(); PatchOperation op = ops.get(0); assertEquals("test", op.getOp()); assertEquals("/0", op.getPath()); Todo value = (Todo) op.getValue(); assertEquals(1L, value.getId().longValue()); assertEquals("A", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(1); assertEquals("remove", op.getOp()); assertEquals("/0", op.getPath()); op = ops.get(2); assertEquals("test", op.getOp()); assertEquals("/0", op.getPath()); value = (Todo) op.getValue(); assertEquals(2L, value.getId().longValue()); assertEquals("B", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(3); assertEquals("remove", op.getOp()); assertEquals("/0", op.getPath()); op = ops.get(4); assertEquals("test", op.getOp()); assertEquals("/0", op.getPath()); value = (Todo) op.getValue(); assertEquals(3L, value.getId().longValue()); assertEquals("C", value.getDescription()); assertEquals(false, value.isComplete()); op = ops.get(5); assertEquals("remove", op.getOp()); assertEquals("/0", op.getPath()); } @Test public void addEntryToListProperty() throws Exception { ArrayList<Todo> todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(2L, "B", false)); todos.add(new Todo(3L, "C", false)); TodoList before = new TodoList(); before.setTodos(todos); todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(2L, "B", false)); todos.add(new Todo(3L, "C", false)); todos.add(new Todo(4L, "D", false)); TodoList after = new TodoList(); after.setTodos(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(1, diff.size()); assertEquals("add", operations.get(0).getOp()); assertEquals("/todos/3", operations.get(0).getPath()); assertEquals(new Todo(4L, "D", false), operations.get(0).getValue()); } @Test public void removeEntryFromListProperty() throws Exception { ArrayList<Todo> todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(2L, "B", false)); todos.add(new Todo(3L, "C", false)); TodoList before = new TodoList(); before.setTodos(todos); todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(3L, "C", false)); TodoList after = new TodoList(); after.setTodos(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(2, diff.size()); assertEquals("test", operations.get(0).getOp()); assertEquals("/todos/1", operations.get(0).getPath()); assertEquals(new Todo(2L, "B", false), operations.get(0).getValue()); assertEquals("remove", operations.get(1).getOp()); assertEquals("/todos/1", operations.get(1).getPath()); } @Test public void editEntryInListProperty() throws Exception { ArrayList<Todo> todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(2L, "B", false)); todos.add(new Todo(3L, "C", false)); TodoList before = new TodoList(); before.setTodos(todos); todos = new ArrayList<Todo>(); todos.add(new Todo(1L, "A", false)); todos.add(new Todo(2L, "BBB", true)); todos.add(new Todo(3L, "C", false)); TodoList after = new TodoList(); after.setTodos(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(4, diff.size()); assertEquals("test", operations.get(0).getOp()); assertEquals("/todos/1/description", operations.get(0).getPath()); assertEquals("B", operations.get(0).getValue()); assertEquals("replace", operations.get(1).getOp()); assertEquals("/todos/1/description", operations.get(1).getPath()); assertEquals("BBB", operations.get(1).getValue()); assertEquals("test", operations.get(2).getOp()); assertEquals("/todos/1/complete", operations.get(2).getPath()); assertEquals(false, operations.get(2).getValue()); assertEquals("replace", operations.get(3).getOp()); assertEquals("/todos/1/complete", operations.get(3).getPath()); assertEquals(true, operations.get(3).getValue()); } @Test public void addEntryToArrayProperty() throws Exception { Todo[] todos = new Todo[3]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(2L, "B", false); todos[2] = new Todo(3L, "C", false); TodoList before = new TodoList(); before.setTodoArray(todos); todos = new Todo[4]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(2L, "B", false); todos[2] = new Todo(3L, "C", false); todos[3] = new Todo(4L, "D", false); TodoList after = new TodoList(); after.setTodoArray(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(1, diff.size()); assertEquals("add", operations.get(0).getOp()); assertEquals("/todoArray/3", operations.get(0).getPath()); assertEquals(new Todo(4L, "D", false), operations.get(0).getValue()); } @Test public void removeEntryFromArrayProperty() throws Exception { Todo[] todos = new Todo[3]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(2L, "B", false); todos[2] = new Todo(3L, "C", false); TodoList before = new TodoList(); before.setTodoArray(todos); todos = new Todo[2]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(3L, "C", false); TodoList after = new TodoList(); after.setTodoArray(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(2, diff.size()); assertEquals("test", operations.get(0).getOp()); assertEquals("/todoArray/1", operations.get(0).getPath()); assertEquals(new Todo(2L, "B", false), operations.get(0).getValue()); assertEquals("remove", operations.get(1).getOp()); assertEquals("/todoArray/1", operations.get(1).getPath()); } @Test public void editEntryInArrayProperty() throws Exception { Todo[] todos = new Todo[3]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(2L, "B", false); todos[2] = new Todo(3L, "C", false); TodoList before = new TodoList(); before.setTodoArray(todos); todos = new Todo[3]; todos[0] = new Todo(1L, "A", false); todos[1] = new Todo(2L, "BBB", true); todos[2] = new Todo(3L, "C", false); TodoList after = new TodoList(); after.setTodoArray(todos); Patch diff = Diff.diff(before, after); List<PatchOperation> operations = diff.getOperations(); assertEquals(4, diff.size()); assertEquals("test", operations.get(0).getOp()); assertEquals("/todoArray/1/description", operations.get(0).getPath()); assertEquals("B", operations.get(0).getValue()); assertEquals("replace", operations.get(1).getOp()); assertEquals("/todoArray/1/description", operations.get(1).getPath()); assertEquals("BBB", operations.get(1).getValue()); assertEquals("test", operations.get(2).getOp()); assertEquals("/todoArray/1/complete", operations.get(2).getPath()); assertEquals(false, operations.get(2).getValue()); assertEquals("replace", operations.get(3).getOp()); assertEquals("/todoArray/1/complete", operations.get(3).getPath()); assertEquals(true, operations.get(3).getValue()); } private List<Todo> buildTodoList() { List<Todo> original = new ArrayList<Todo>(); original.add(new Todo(1L, "A", false)); original.add(new Todo(2L, "B", false)); original.add(new Todo(3L, "C", false)); return original; } }