/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.test.utility.diff;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.persistence.tools.workbench.test.utility.TestTools;
import org.eclipse.persistence.tools.workbench.utility.diff.CompositeDiff;
import org.eclipse.persistence.tools.workbench.utility.diff.Diff;
import org.eclipse.persistence.tools.workbench.utility.diff.Diffable;
import org.eclipse.persistence.tools.workbench.utility.diff.DiffableDifferentiator;
import org.eclipse.persistence.tools.workbench.utility.diff.Differentiator;
import org.eclipse.persistence.tools.workbench.utility.diff.ReflectiveDiff;
import org.eclipse.persistence.tools.workbench.utility.diff.ReflectiveFieldDiff;
import org.eclipse.persistence.tools.workbench.utility.diff.SimpleDiff;
import org.eclipse.persistence.tools.workbench.utility.string.StringTools;
public abstract class AbstractCircularReferenceDiffTests extends TestCase {
Differentiator differentiator;
TestRootNode testRootNode1;
TestRootNode testRootNode2;
AbstractCircularReferenceDiffTests(String name) {
super(name);
}
protected void setUp() throws Exception {
super.setUp();
this.differentiator = this.buildDifferentiator();
this.testRootNode1 = this.buildTestRootNode();
this.testRootNode2 = this.buildTestRootNode();
}
protected void tearDown() throws Exception {
TestTools.clear(this);
super.tearDown();
}
abstract Differentiator buildDifferentiator();
TestRootNode buildTestRootNode() {
TestRootNode root = new TestRootNode("root");
root.setComment("root comment");
TestBranchNode parent1 = new TestBranchNode(root, "parent1");
parent1.setComment("parent1 comment");
TestBranchNode child1 = new TestBranchNode(parent1, "child1");
child1.setComment("child1 comment");
parent1.setChild(child1);
root.setNode1(parent1);
TestBranchNode parent2 = new TestBranchNode(root, "parent2");
parent2.setComment("parent2 comment");
root.setNode2(parent2);
parent1.setSpouse(parent2);
parent2.setSpouse(parent1);
TestBranchNode parent3 = new TestBranchNode(root, "parent3");
parent3.setComment("parent3 comment");
TestBranchNode child3 = new TestBranchNode(parent3, "child3");
child3.setComment("child3 comment");
parent3.setChild(child3);
root.setNode3(parent3);
child1.setSpouse(child3);
child3.setSpouse(child1);
return root;
}
public void testMatch() {
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMatch(diff, this.testRootNode1, this.testRootNode2);
}
public void testMismatch01() {
// changing the root's key modifies everything up...
this.testRootNode2.setName("*" + this.testRootNode1.getName() + "*");
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
}
public void testMismatch02() {
// tweak comment
String differentComment = "*" + this.testRootNode1.getComment() + "*";
this.testRootNode2.setComment(differentComment);
Diff diff = (CompositeDiff) this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
assertEquals(1, leafMismatches.size());
this.verifyMismatch02((CompositeDiff) diff, differentComment);
}
void verifyMismatch02(CompositeDiff cd, String differentComment) {
ReflectiveDiff rd = (ReflectiveDiff) cd.getDiffs()[0];
ReflectiveFieldDiff rfd = (ReflectiveFieldDiff) rd.getDiffs()[0];
assertEquals("comment", rfd.getField().getName());
SimpleDiff ed = (SimpleDiff) rfd.getDiff();
assertTrue(ed.different());
assertEquals(differentComment, ed.getObject2());
}
public void testMismatch03() {
// swap nodes
TestBranchNode node1 = this.testRootNode2.getNode1();
TestBranchNode node2 = this.testRootNode2.getNode2();
this.testRootNode2.setNode1(node2);
this.testRootNode2.setNode2(node1);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
this.verifyMismatch03((CompositeDiff) diff);
}
abstract void verifyMismatch03(CompositeDiff cd);
public void testMismatch04() {
// tweak nested comment
TestBranchNode node = this.testRootNode2.getNode1().getChild();
String originalComment = node.getComment();
String modifiedComment = "*" + originalComment + "*";
node.setComment(modifiedComment);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
assertEquals(1, leafMismatches.size());
Diff leafDiff = (Diff) leafMismatches.get(0);
assertEquals(originalComment, leafDiff.getObject1());
assertEquals(modifiedComment, leafDiff.getObject2());
}
public void testMismatch05() {
// null out nested comment
TestBranchNode node = this.testRootNode2.getNode1().getChild();
String originalComment = node.getComment();
String modifiedComment = null;
node.setComment(modifiedComment);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
assertEquals(1, leafMismatches.size());
Diff leafDiff = (Diff) leafMismatches.get(0);
assertEquals(originalComment, leafDiff.getObject1());
assertEquals(modifiedComment, leafDiff.getObject2());
}
public void testMismatch06() {
// change reference
TestBranchNode node1 = this.testRootNode2.getNode1();
TestBranchNode node3 = this.testRootNode2.getNode3();
String originalName = node1.getSpouse().getName();
node1.setSpouse(node3);
String modifiedName = node1.getSpouse().getName();
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
assertEquals(1, leafMismatches.size());
Diff leafDiff = (Diff) leafMismatches.get(0);
assertEquals(originalName, leafDiff.getObject1());
assertEquals(modifiedName, leafDiff.getObject2());
}
public void testMismatch07() {
// tweak nested key
TestBranchNode node = this.testRootNode2.getNode1().getChild();
String originalName = node.getName();
String modifiedName = "*" + originalName + "*";
node.setName(modifiedName);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
// one as a child, one as a spouse
assertEquals(2, leafMismatches.size());
Diff leafDiff = (Diff) leafMismatches.get(0);
assertEquals(originalName, leafDiff.getObject1());
assertEquals(modifiedName, leafDiff.getObject2());
leafDiff = (Diff) leafMismatches.get(1);
assertEquals(originalName, leafDiff.getObject1());
assertEquals(modifiedName, leafDiff.getObject2());
}
public void testMismatch08() {
// null out nested key
TestBranchNode node = this.testRootNode2.getNode1().getChild();
String originalName = node.getName();
String modifiedName = null;
node.setName(modifiedName);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
List leafMismatches = DiffTestTools.differentLeafDiffList(diff);
// one as a child, one as a spouse
assertEquals(2, leafMismatches.size());
Diff leafDiff = (Diff) leafMismatches.get(0);
assertEquals(originalName, leafDiff.getObject1());
assertEquals(modifiedName, leafDiff.getObject2());
leafDiff = (Diff) leafMismatches.get(1);
assertEquals(originalName, leafDiff.getObject1());
assertEquals(modifiedName, leafDiff.getObject2());
}
public void testMismatch09() {
// null out aggregate
TestBranchNode node = this.testRootNode2.getNode1();
node.setChild(null);
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
this.verifyMismatch09(diff);
}
abstract void verifyMismatch09(Diff diff);
public void testMismatch10() {
// change aggregate class
TestBranchNode node = this.testRootNode2.getNode1();
TestBranchNode child = node.getChild();
node.setChild(new TestBranchNode(node, child.getName() + " (wrong class)") {/* shell subclass */});
Diff diff = this.differentiator.diff(this.testRootNode1, this.testRootNode2);
this.verifyDiffMismatch(diff, this.testRootNode1, this.testRootNode2);
this.verifyMismatch10(node, diff);
}
abstract void verifyMismatch10(TestBranchNode node, Diff diff);
protected void verifyDiffMatch(Diff diff, Object object1, Object object2) {
assertEquals(object1, diff.getObject1());
assertEquals(object2, diff.getObject2());
assertTrue(diff.identical());
assertFalse(diff.different());
assertEquals(0, diff.getDescription().length());
}
protected void verifyDiffMismatch(Diff diff, Object object1, Object object2) {
assertEquals(object1, diff.getObject1());
assertEquals(object2, diff.getObject2());
assertFalse(diff.identical());
assertTrue(diff.different());
assertTrue(diff.getDescription().length() > 0);
}
// ********** member classes **********
static abstract class TestNode implements Diffable {
private String name;
private String comment;
TestNode(String name) {
super();
this.name = name;
}
public String toString() {
return StringTools.buildToStringFor(this, this.name);
}
public void setName(String string) {
this.name = string;
}
public String getName() {
return this.name;
}
public void setComment(String string) {
this.comment = string;
}
public String getComment() {
return this.comment;
}
public Diff diff(Object o) {
if ((o == null) || (this.getClass() != o.getClass())) {
return new SimpleDiff(this, o, "Unable to compare", DiffableDifferentiator.instance());
}
Collection diffs = new ArrayList();
this.addDiffsTo((TestNode) o, diffs);
return new CompositeDiff(this, o, (Diff[]) diffs.toArray(new Diff[diffs.size()]), DiffableDifferentiator.instance());
}
void addDiffsTo(TestNode other, Collection diffs) {
if ( ! this.name.equals(other.name)) {
diffs.add(new SimpleDiff(this.name, other.name, "Names are different", DiffableDifferentiator.instance()));
}
if ( ! this.comment.equals(other.comment)) {
diffs.add(new SimpleDiff(this.comment, other.comment, "Comments are different", DiffableDifferentiator.instance()));
}
}
public Diff keyDiff(Object o) {
if ((o == null) || (this.getClass() != o.getClass())) {
return new SimpleDiff(this, o, "Unable to compare", DiffableDifferentiator.instance());
}
Collection diffs = new ArrayList();
this.addKeyDiffsTo((TestNode) o, diffs);
return new CompositeDiff(this, o, (Diff[]) diffs.toArray(new Diff[diffs.size()]), DiffableDifferentiator.instance());
}
void addKeyDiffsTo(TestNode other, Collection diffs) {
if ( ! this.name.equals(other.name)) {
diffs.add(new SimpleDiff(this.name, other.name, "Names are different", DiffableDifferentiator.instance()));
}
}
}
static class TestRootNode extends TestNode {
private TestBranchNode node1;
private TestBranchNode node2;
private TestBranchNode node3;
TestRootNode(String name) {
super(name);
}
public void setNode1(TestBranchNode node) {
this.node1 = node;
}
public TestBranchNode getNode1() {
return this.node1;
}
public void setNode2(TestBranchNode node) {
this.node2 = node;
}
public TestBranchNode getNode2() {
return this.node2;
}
public void setNode3(TestBranchNode node) {
this.node3 = node;
}
public TestBranchNode getNode3() {
return this.node3;
}
void addDiffsTo(TestNode other, Collection diffs) {
super.addDiffsTo(other, diffs);
TestRootNode otherRoot = (TestRootNode) other;
diffs.add(this.node1.diff(otherRoot.node1));
diffs.add(this.node2.diff(otherRoot.node2));
diffs.add(this.node3.diff(otherRoot.node3));
}
}
static class TestBranchNode extends TestNode {
private TestNode parent;
private TestBranchNode child;
private TestBranchNode spouse;
TestBranchNode(TestNode parent, String name) {
super(name);
this.parent = parent;
}
public TestNode getParent() {
return this.parent;
}
public void setChild(TestBranchNode node) {
this.child = node;
}
public TestBranchNode getChild() {
return this.child;
}
public void setSpouse(TestBranchNode node) {
this.spouse = node;
}
public TestBranchNode getSpouse() {
return this.spouse;
}
void addDiffsTo(TestNode other, Collection diffs) {
super.addDiffsTo(other, diffs);
TestBranchNode otherBranch = (TestBranchNode) other;
diffs.add(this.parent.keyDiff(otherBranch.parent));
if (this.child != null) {
diffs.add(this.child.diff(otherBranch.child));
}
if (this.spouse != null) {
diffs.add(this.spouse.keyDiff(otherBranch.spouse));
}
}
}
}