blob: 5af287fcfe36f19f3f05c89dfb02b2a4cf7bb7c5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.utility.tests.internal.node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.HashBag;
import org.eclipse.jpt.utility.internal.Range;
import org.eclipse.jpt.utility.internal.iterators.CloneIterator;
import org.eclipse.jpt.utility.internal.node.AbstractNodeModel;
import org.eclipse.jpt.utility.internal.node.Node;
import org.eclipse.jpt.utility.internal.node.Problem;
import org.eclipse.jpt.utility.tests.internal.TestTools;
import junit.framework.TestCase;
public class AbstractNodeModelTests extends TestCase {
private TestWorkbenchModel root;
public AbstractNodeModelTests(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.root = this.buildRoot();
}
private TestWorkbenchModel buildRoot() {
TestWorkbenchModel r = new RootTestWorkbenchModel("root");
TestWorkbenchModel node1 = r.addTestChildNamed("node 1");
TestWorkbenchModel node1_1 = node1.addTestChildNamed("node 1.1");
node1_1.addTestChildNamed("node 1.1.1");
node1_1.addTestChildNamed("node 1.1.2");
node1_1.addTestChildNamed("node 1.1.3");
node1.addTestChildNamed("node 1.2");
TestWorkbenchModel node2 = r.addTestChildNamed("node 2");
node2.addTestChildNamed("node 2.1");
node2.addTestChildNamed("node 2.2");
r.addTestChildNamed("node 3");
r.addTestChildNamed("node 4");
// mark the entire tree clean
r.markEntireBranchClean();
return r;
}
@Override
protected void tearDown() throws Exception {
TestTools.clear(this);
super.tearDown();
}
public void testTestWorkbenchModel() {
// make sure our test class works OK...
assertNull(this.root.testChildNamed(""));
assertNotNull(this.root.testChildNamed("node 1"));
assertTrue(this.root.testChildNamed("node 1").isClean());
assertTrue(this.root.testChildNamed("node 1").isCleanBranch());
assertNotNull(this.root.testChildNamed("node 2"));
assertTrue(this.root.testChildNamed("node 2").isClean());
assertTrue(this.root.testChildNamed("node 2").isCleanBranch());
assertNull(this.root.testChildNamed("node 2.1"));
assertNull(this.root.testDescendantNamed(""));
assertNotNull(this.root.testDescendantNamed("node 1"));
assertNotNull(this.root.testDescendantNamed("node 2"));
assertNotNull(this.root.testDescendantNamed("node 2.1"));
assertTrue(this.root.testDescendantNamed("node 2.1").isClean());
assertTrue(this.root.testDescendantNamed("node 2.1").isCleanBranch());
assertNotNull(this.root.testDescendantNamed("node 1.1.3"));
assertTrue(this.root.testDescendantNamed("node 1.1.3").isClean());
assertTrue(this.root.testDescendantNamed("node 1.1.3").isCleanBranch());
}
public void testParentAndChildren() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
assertEquals("node 1.1.3", node.getName());
assertEquals(0, CollectionTools.size(node.children()));
node = (TestWorkbenchModel) node.parent();
assertEquals("node 1.1", node.getName());
assertEquals(3, CollectionTools.size(node.children()));
node = (TestWorkbenchModel) node.parent();
assertEquals("node 1", node.getName());
assertEquals(2, CollectionTools.size(node.children()));
node = (TestWorkbenchModel) node.parent();
assertEquals("root", node.getName());
assertEquals(4, CollectionTools.size(node.children()));
node = (TestWorkbenchModel) node.parent();
assertNull(node);
}
public void testDirty() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setSize(42);
assertTrue(node.isDirty());
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
assertTrue(parent.isClean());
assertTrue(this.root.isClean());
}
public void testDirtyUnchangedAttribute() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setSize(42);
assertTrue(node.isDirty());
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
assertTrue(parent.isClean());
assertTrue(this.root.isClean());
this.root.markEntireBranchClean();
// set size to same number - should stay clean
node.setSize(42);
assertTrue(node.isClean());
assertTrue(parent.isClean());
assertTrue(this.root.isClean());
}
public void testDirtyBranch() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setSize(42);
assertTrue(node.isDirtyBranch());
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
assertTrue(parent.isDirtyBranch());
assertTrue(this.root.isDirtyBranch());
parent.setSize(77);
assertTrue(parent.isDirty());
assertTrue(parent.isDirtyBranch());
node.markEntireBranchClean();
assertTrue(parent.isDirty());
assertTrue(parent.isDirtyBranch());
}
public void testDirtyBranchCleanChildDirtyParent() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setSize(42);
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
parent.setSize(77);
assertTrue(parent.isDirty());
assertTrue(parent.isDirtyBranch());
// now, clean the child, but leave the parent dirty
node.markEntireBranchClean();
assertTrue(parent.isDirty());
assertTrue(parent.isDirtyBranch());
}
public void testDirtyBranchCleanChildDirtyChild() {
TestWorkbenchModel node1 = this.root.testDescendantNamed("node 1.1.1");
node1.setSize(41);
TestWorkbenchModel node2 = this.root.testDescendantNamed("node 1.1.2");
node2.setSize(42);
TestWorkbenchModel parent = (TestWorkbenchModel) node1.parent();
assertTrue(parent.isClean());
assertTrue(parent.isDirtyBranch());
// now, clean the first child, but leave the second child dirty
node1.markEntireBranchClean();
assertTrue(parent.isClean());
assertTrue(parent.isDirtyBranch());
}
public void testDirtyBranchForced() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
assertTrue(node.isClean());
assertTrue(node.isCleanBranch());
assertTrue(parent.isClean());
assertTrue(parent.isCleanBranch());
assertTrue(this.root.isClean());
assertTrue(this.root.isCleanBranch());
this.root.markEntireBranchDirty();
assertTrue(node.isDirty());
assertTrue(node.isDirtyBranch());
assertTrue(parent.isDirty());
assertTrue(parent.isDirtyBranch());
assertTrue(this.root.isDirty());
assertTrue(this.root.isDirtyBranch());
}
public void testDirtyTransientAttribute() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setName("BOGUS");
assertTrue(node.isDirty());
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
assertTrue(parent.isClean());
assertTrue(parent.isDirtyBranch());
assertTrue(this.root.isClean());
assertTrue(this.root.isDirtyBranch());
this.root.markEntireBranchClean();
this.root.validateBranch();
assertTrue(this.root.problemsSize() == 0);
assertTrue(node.branchProblems().hasNext());
assertTrue(parent.problemsSize() == 0);
assertTrue(parent.branchProblems().hasNext());
assertTrue(node.problemsSize() > 0);
// since problems are transient, everything should still be clean
assertTrue(node.isClean());
assertTrue(node.isCleanBranch());
assertTrue(parent.isClean());
assertTrue(parent.isCleanBranch());
assertTrue(this.root.isClean());
assertTrue(this.root.isCleanBranch());
}
public void testProblems() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setName("BOGUS");
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
this.root.validateBranch();
assertEquals(0, this.root.problemsSize());
assertTrue(node.branchProblems().hasNext());
assertEquals(0, parent.problemsSize());
assertTrue(parent.branchProblems().hasNext());
assertEquals(1, node.problemsSize());
Problem problem1 = node.problems().next();
// now create another problem that should remove the old problem
node.setName("STILL BOGUS");
this.root.validateBranch();
assertEquals(0, this.root.problemsSize());
assertTrue(node.branchProblems().hasNext());
assertEquals(0, parent.problemsSize());
assertTrue(parent.branchProblems().hasNext());
assertEquals(1, node.problemsSize());
Problem problem2 = node.problems().next();
assertFalse(problem1 == problem2);
problem1 = problem2;
// now create another problem that should replace the old problem
node.setName("STILL BOGUS");
this.root.validateBranch();
assertEquals(0, this.root.problemsSize());
assertTrue(node.branchProblems().hasNext());
assertEquals(0, parent.problemsSize());
assertTrue(parent.branchProblems().hasNext());
assertEquals(1, node.problemsSize());
problem2 = node.problems().next();
// the same problem should be there
assertTrue(problem1.equals(problem2));
}
public void testBranchProblems() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setName("BOGUS");
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
parent.setName("BOGUS TOO");
this.root.setName("BOGUS TOO TOO");
this.root.validateBranch();
assertEquals(1, this.root.problemsSize());
assertEquals(3, this.root.branchProblemsSize());
assertEquals(1, parent.problemsSize());
assertEquals(2, parent.branchProblemsSize());
assertEquals(1, node.problemsSize());
assertEquals(1, node.branchProblemsSize());
node.setName("okie-dokie");
this.root.validateBranch();
assertEquals(1, this.root.problemsSize());
assertEquals(2, this.root.branchProblemsSize());
assertEquals(1, parent.problemsSize());
assertEquals(1, parent.branchProblemsSize());
assertEquals(0, node.problemsSize());
assertEquals(0, node.branchProblemsSize());
}
public void testClearAllBranchProblems() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setName("BOGUS");
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
parent.setName("BOGUS TOO");
this.root.setName("BOGUS TOO TOO");
this.root.validateBranch();
assertEquals(1, this.root.problemsSize());
assertEquals(3, this.root.branchProblemsSize());
assertEquals(1, parent.problemsSize());
assertEquals(2, parent.branchProblemsSize());
assertEquals(1, node.problemsSize());
assertEquals(1, node.branchProblemsSize());
parent.clearAllBranchProblems();
assertEquals(1, this.root.problemsSize());
assertEquals(1, this.root.branchProblemsSize());
assertEquals(0, parent.problemsSize());
assertEquals(0, parent.branchProblemsSize());
assertEquals(0, node.problemsSize());
assertEquals(0, CollectionTools.size(node.branchProblems()));
}
public void testRemovedBranchProblems() {
TestWorkbenchModel node = this.root.testDescendantNamed("node 1.1.3");
node.setName("BOGUS");
TestWorkbenchModel parent = (TestWorkbenchModel) node.parent();
parent.setName("BOGUS TOO");
this.root.setName("BOGUS TOO TOO");
this.root.validateBranch();
assertEquals(1, this.root.problemsSize());
assertEquals(3, CollectionTools.size(this.root.branchProblems()));
assertEquals(1, parent.problemsSize());
assertEquals(2, parent.branchProblemsSize());
assertEquals(1, node.problemsSize());
assertEquals(1, CollectionTools.size(node.branchProblems()));
// completely remove a node that has problems -
// the entire tree should recalculate its "branch" problems
parent.removeTestChild(node);
this.root.validateBranch();
assertEquals(1, this.root.problemsSize());
assertEquals(2, CollectionTools.size(this.root.branchProblems()));
assertEquals(1, parent.problemsSize());
assertEquals(1, parent.branchProblemsSize());
}
public void testSort() {
List<TestWorkbenchModel> nodes = this.buildSortedNodes();
assertTrue(new Range(0, 1).includes(this.indexOf(nodes, "aaa")));
assertTrue(new Range(0, 1).includes(this.indexOf(nodes, "AAA")));
assertTrue(new Range(2, 3).includes(this.indexOf(nodes, "bbb")));
assertTrue(new Range(2, 3).includes(this.indexOf(nodes, "BBB")));
assertTrue(new Range(4, 6).includes(this.indexOf(nodes, "ccc")));
assertTrue(new Range(4, 6).includes(this.indexOf(nodes, "CCC")));
assertTrue(new Range(4, 6).includes(this.indexOf(nodes, "���")));
}
private int indexOf(List<TestWorkbenchModel> nodes, String nodeName) {
for (int i = nodes.size(); i-- > 0; ) {
if (nodes.get(i).getName().equals(nodeName)) {
return i;
}
}
throw new IllegalArgumentException();
}
private List<TestWorkbenchModel> buildSortedNodes() {
List<TestWorkbenchModel> result = new ArrayList<TestWorkbenchModel>();
result.add(new RootTestWorkbenchModel("AAA"));
result.add(new RootTestWorkbenchModel("BBB"));
result.add(new RootTestWorkbenchModel("CCC"));
result.add(new RootTestWorkbenchModel("���"));
result.add(new RootTestWorkbenchModel("ccc"));
result.add(new RootTestWorkbenchModel("bbb"));
result.add(new RootTestWorkbenchModel("aaa"));
return CollectionTools.sort(result);
}
// ********** inner classes **********
private class TestWorkbenchModel extends AbstractNodeModel {
private String name;
public static final String NAME_PROPERTY = "name";
private int size;
public static final String SIZE_PROPERTY = "size";
private Collection<TestWorkbenchModel> testChildren;
public static final String TEST_CHILDREN_COLLECTION = "children";
// ********** construction/initialization **********
public TestWorkbenchModel(TestWorkbenchModel parent, String name) {
super(parent);
if (name == null) {
throw new NullPointerException();
}
this.name = name;
}
@Override
protected void initialize() {
super.initialize();
this.size = 0;
this.testChildren = new HashBag<TestWorkbenchModel>();
}
@Override
protected void checkParent(Node parent) {
// do nothing
}
// ********** accessors **********
public String getName() {
return this.name;
}
public void setName(String name) {
Object old = this.name;
this.name = name;
this.firePropertyChanged(NAME_PROPERTY, old, name);
}
public int getSize() {
return this.size;
}
public void setSize(int size) {
int old = this.size;
this.size = size;
this.firePropertyChanged(SIZE_PROPERTY, old, size);
}
public Iterator<TestWorkbenchModel> testChildren() {
return new CloneIterator<TestWorkbenchModel>(this.testChildren) {
@Override
protected void remove(TestWorkbenchModel current) {
TestWorkbenchModel.this.removeTestChild(current);
}
};
}
public int testChildrenSize() {
return this.testChildren.size();
}
private TestWorkbenchModel addTestChild(TestWorkbenchModel testChild) {
this.addItemToCollection(testChild, this.testChildren, TEST_CHILDREN_COLLECTION);
return testChild;
}
public TestWorkbenchModel addTestChildNamed(String childName) {
if (this.testChildNamed(childName) != null) {
throw new IllegalArgumentException(childName);
}
return this.addTestChild(new TestWorkbenchModel(this, childName));
}
public void removeTestChild(TestWorkbenchModel testChild) {
this.removeItemFromCollection(testChild, this.testChildren, TEST_CHILDREN_COLLECTION);
}
// ********** queries **********
public String displayString() {
return this.name;
}
public TestWorkbenchModel testChildNamed(String childName) {
for (TestWorkbenchModel testChild : this.testChildren) {
if (testChild.getName().equals(childName)) {
return testChild;
}
}
return null;
}
public TestWorkbenchModel testDescendantNamed(String descendantName) {
for (TestWorkbenchModel testDescendant : this.testChildren) {
if (testDescendant.getName().equals(descendantName)) {
return testDescendant;
}
// recurse...
testDescendant = testDescendant.testDescendantNamed(descendantName);
if (testDescendant != null) {
return testDescendant;
}
}
return null;
}
// ********** behavior **********
@Override
protected void addChildrenTo(List<Node> children) {
super.addChildrenTo(children);
children.addAll(this.testChildren);
}
@Override
protected void addProblemsTo(List<Problem> currentProblems) {
super.addProblemsTo(currentProblems);
// names must be all lowercase...
for (int i = this.name.length(); i-- > 0; ) {
char c = this.name.charAt(i);
if (Character.isLetter(c) && ! Character.isLowerCase(c)) {
currentProblems.add(this.buildProblem("NAME_MUST_BE_LOWERCASE", this.name));
return;
}
}
}
@Override
public void toString(StringBuffer sb) {
sb.append(this.name);
}
}
private class RootTestWorkbenchModel extends TestWorkbenchModel {
public RootTestWorkbenchModel(String name) {
super(null, name);
}
@Override
public Validator validator() {
return Node.NULL_VALIDATOR;
}
}
}