/******************************************************************************* * Copyright 2012 Geoscience Australia * * 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 au.gov.ga.earthsci.core.tree; import static org.junit.Assert.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; /** * Unit tests for the {@link AbstractTreeNode} * * @author James Navin (james.navin@ga.gov.au) */ public class AbstractTreeNodeTest { private AbstractTreeNode<ConcreteTreeNode> classUnderTest; private MockPropertyChangeListener changeListener; @Before public void setup() { classUnderTest = new ConcreteTreeNode("classUnderTest"); changeListener = new MockPropertyChangeListener(); classUnderTest.addPropertyChangeListener(changeListener); } @Test(expected = NullPointerException.class) public void testAddWithNull() { ConcreteTreeNode child = null; classUnderTest.addChild(child); } @Test public void testAddWithNonNull() { ConcreteTreeNode child = new ConcreteTreeNode("child"); classUnderTest.addChild(child); // A children changed event should fire assertEquals(1, changeListener.events.size()); PropertyChangeEvent event = changeListener.events.get(0); assertEquals("children", event.getPropertyName()); assertArrayEquals(new Object[] { child }, ((List) event.getNewValue()).toArray()); // Child should be on node assertEquals(1, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child }, classUnderTest.getChildren().toArray()); // Node should be parent of child assertEquals(classUnderTest, child.getParent()); } @Test public void testAddWithNonNullAndIndex() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); classUnderTest.addChild(child2); classUnderTest.addChild(child3); assertArrayEquals(new Object[] { child0, child1, child2, child3 }, classUnderTest.getChildren().toArray()); ConcreteTreeNode newChild = new ConcreteTreeNode("newChild"); changeListener.clear(); classUnderTest.addChild(2, newChild); assertArrayEquals(new Object[] { child0, child1, newChild, child2, child3 }, classUnderTest.getChildren() .toArray()); // A children changed event should fire assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); assertEquals(classUnderTest, newChild.getParent()); } @Test public void testAddWithNonNullAndIndexOutOfBounds() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); classUnderTest.addChild(child2); classUnderTest.addChild(child3); assertArrayEquals(new Object[] { child0, child1, child2, child3 }, classUnderTest.getChildren().toArray()); ConcreteTreeNode newChild = new ConcreteTreeNode("newChild"); changeListener.clear(); classUnderTest.addChild(200, newChild); assertArrayEquals(new Object[] { child0, child1, child2, child3, newChild }, classUnderTest.getChildren() .toArray()); // A children changed event should fire assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); assertEquals(classUnderTest, newChild.getParent()); } @Test public void testAddWithExistingSingleChild() { ConcreteTreeNode child = new ConcreteTreeNode("child"); classUnderTest.addChild(child); changeListener.clear(); classUnderTest.addChild(child); // No children changed event should fire assertEquals(0, changeListener.events.size()); // Child should be on node assertEquals(1, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child }, classUnderTest.getChildren().toArray()); // Node should be parent of child assertEquals(classUnderTest, child.getParent()); } @Test public void testAddWithExistingTwoChildren() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); changeListener.clear(); classUnderTest.addChild(child0); // A children changed event should fire assertEquals(1, changeListener.events.size()); // Child should be on node assertEquals(2, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child1, child0 }, classUnderTest.getChildren().toArray()); // Node should be parent of child assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); } @Test public void testAddToEndWithExistingMultipleChildren() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); classUnderTest.addChild(child2); classUnderTest.addChild(child3); changeListener.clear(); classUnderTest.addChild(child0); // A single children changed event should fire assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); // Added child should be at the end of the children list assertEquals(4, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child1, child2, child3, child0 }, classUnderTest.getChildren().toArray()); // Node should be parent of children assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); assertEquals(classUnderTest, child2.getParent()); assertEquals(classUnderTest, child3.getParent()); // Indices should be updated assertEquals(3, child0.index()); assertEquals(0, child1.index()); assertEquals(1, child2.index()); assertEquals(2, child3.index()); } @Test public void testAddToMiddleWithExistingMultipleChildren() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); ConcreteTreeNode child4 = new ConcreteTreeNode("child4"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); classUnderTest.addChild(child2); classUnderTest.addChild(child3); classUnderTest.addChild(child4); changeListener.clear(); classUnderTest.addChild(2, child0); // A single children changed event should fire assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); // Added child should be in the middle of the children list assertEquals(5, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child1, child2, child0, child3, child4 }, classUnderTest.getChildren() .toArray()); // Node should be parent of children assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); assertEquals(classUnderTest, child2.getParent()); assertEquals(classUnderTest, child3.getParent()); assertEquals(classUnderTest, child4.getParent()); // Indices should be updated assertEquals(2, child0.index()); assertEquals(0, child1.index()); assertEquals(1, child2.index()); assertEquals(3, child3.index()); assertEquals(4, child4.index()); } @Test public void testAddToStartWithExistingMultipleChildren() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); ConcreteTreeNode child4 = new ConcreteTreeNode("child4"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); classUnderTest.addChild(child2); classUnderTest.addChild(child3); classUnderTest.addChild(child4); changeListener.clear(); classUnderTest.addChild(1, child3); // A single children changed event should fire assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); // Added child should be in the middle of the children list assertEquals(5, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child0, child3, child1, child2, child4 }, classUnderTest.getChildren() .toArray()); // Node should be parent of children assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); assertEquals(classUnderTest, child2.getParent()); assertEquals(classUnderTest, child3.getParent()); assertEquals(classUnderTest, child4.getParent()); // Indices should be updated assertEquals(0, child0.index()); assertEquals(2, child1.index()); assertEquals(3, child2.index()); assertEquals(1, child3.index()); assertEquals(4, child4.index()); } @Test(expected = NullPointerException.class) public void testRemoveWithEmptyChildrenAndNull() { ConcreteTreeNode child = null; classUnderTest.removeChild(child); } @Test public void testRemoveWithEmptyChildrenAndNonNull() { ConcreteTreeNode child = new ConcreteTreeNode("child"); boolean removed = classUnderTest.removeChild(child); assertFalse(removed); assertEquals(0, changeListener.events.size()); } @SuppressWarnings("unchecked") @Test(expected = NullPointerException.class) public void testRemoveWithNonEmptyChildrenNull() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); List<ConcreteTreeNode> children = new ArrayList<ConcreteTreeNode>(); children.add(child0); children.add(child1); children.add(child2); children.add(child3); classUnderTest.setChildren(children); changeListener.clear(); classUnderTest.removeChild(null); } @SuppressWarnings("unchecked") @Test public void testRemoveWithNonEmptyChildrenNonMember() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); List<ConcreteTreeNode> children = new ArrayList<ConcreteTreeNode>(); children.add(child0); children.add(child1); children.add(child2); children.add(child3); classUnderTest.setChildren(children); changeListener.clear(); boolean removed = classUnderTest.removeChild(new ConcreteTreeNode("notAChild")); assertFalse(removed); assertEquals(0, changeListener.events.size()); } @SuppressWarnings("unchecked") @Test public void testRemoveWithNonEmptyChildrenMember() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); List<ConcreteTreeNode> children = new ArrayList<ConcreteTreeNode>(); children.add(child0); children.add(child1); children.add(child2); children.add(child3); classUnderTest.setChildren(children); changeListener.clear(); boolean removed = classUnderTest.removeChild(child1); assertTrue(removed); assertEquals(3, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child0, child2, child3 }, classUnderTest.getChildren().toArray()); assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); } @Test public void testRemoveAllWithEmptyChildren() { classUnderTest.clearChildren(); assertEquals(0, classUnderTest.getChildCount()); assertEquals(0, changeListener.events.size()); } @SuppressWarnings("unchecked") @Test public void testRemoveAllWithNonEmptyChildren() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); ConcreteTreeNode child2 = new ConcreteTreeNode("child2"); ConcreteTreeNode child3 = new ConcreteTreeNode("child3"); List<ConcreteTreeNode> children = new ArrayList<ConcreteTreeNode>(); children.add(child0); children.add(child1); children.add(child2); children.add(child3); classUnderTest.setChildren(children); changeListener.clear(); classUnderTest.clearChildren(); assertEquals(0, classUnderTest.getChildCount()); assertNull(child0.getParent()); assertNull(child1.getParent()); assertNull(child2.getParent()); assertNull(child3.getParent()); assertEquals(1, changeListener.events.size()); assertEquals("children", changeListener.events.get(0).getPropertyName()); } @Test public void testMoveChild() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); changeListener.clear(); classUnderTest.moveChild(child0, 1); // A children changed event should fire assertEquals(1, changeListener.events.size()); // Child should be on node assertEquals(2, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child1, child0 }, classUnderTest.getChildren().toArray()); // Node should be parent of child assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); } @Test public void testMoveChildToInvalidIndex() { ConcreteTreeNode child0 = new ConcreteTreeNode("child0"); ConcreteTreeNode child1 = new ConcreteTreeNode("child1"); classUnderTest.addChild(child0); classUnderTest.addChild(child1); changeListener.clear(); classUnderTest.moveChild(child0, 2); // A children changed event should fire assertEquals(1, changeListener.events.size()); // Child should be on node assertEquals(2, classUnderTest.getChildCount()); assertArrayEquals(new Object[] { child1, child0 }, classUnderTest.getChildren().toArray()); // Node should be parent of child assertEquals(classUnderTest, child0.getParent()); assertEquals(classUnderTest, child1.getParent()); } private static class ConcreteTreeNode extends AbstractTreeNode<ConcreteTreeNode> { private String name; ConcreteTreeNode(String name) { super(ConcreteTreeNode.class); this.name = name; } @Override public String toString() { return name; } } private static class MockPropertyChangeListener implements PropertyChangeListener { List<PropertyChangeEvent> events = new ArrayList<PropertyChangeEvent>(); @Override public void propertyChange(PropertyChangeEvent evt) { events.add(evt); } public void clear() { events.clear(); } } }