import java.util.Arrays;
import junit.framework.TestCase;

/**
 * JUnit tests for assignment 5.
 * 
 * @author Dave Matuszek
 * @version Feb 17, 2005
 */
public class TreeTest extends TestCase {
    Tree t1, t2, t3, t4, t5, t6, t7, t8, t9, t10;

    /** <pre>
     *         t1
     *        /  \
     *      t2    t3         t10         t2'
     *     /  \    |                    /  \
     *   t4    t5  t6                 t5'   t6'
     *            / | \
     *          t7 t8  t9
     *          
     * @see TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        t1 = new Tree("t1");
        t2 = new Tree("t2");
        t3 = new Tree("t3");
        t4 = new Tree("t4");
        t5 = new Tree("t5");
        t6 = new Tree("t6");
        t7 = new Tree("t7");
        t8 = new Tree("t8");
        t9 = new Tree("t9");
        t10 = new Tree("t10");
        t1.addChild(t2);
        t2.addChild(t4);
        t2.addChild(t5);
        t1.addChild(t3);
        t6.addChild(t7);
        t6.addChild(t8);
        t6.addChild(t9);
        t3.addChild(t6);
    }

    /*
     * Class under test for void Tree(Object) constructor
     */
    public final void testTreeObject() {
        Tree root = new Tree("abc");
        assertEquals("abc", root.getValue());
        assertEquals(0, root.getNumberOfChildren());
        assertEquals(0, root.getChildren().length);
    }

    /*
     * Class under test for void Tree(Object, Tree) constructor
     */
    public final void testTreeObjectTree() {
        Tree child = new Tree("abc");
        Tree root = new Tree("xyz", child);
        assertEquals("abc", child.getValue());
        assertEquals("xyz", root.getValue());
        assertEquals(1, root.getNumberOfChildren());
        assertEquals(1, root.getChildren().length);
        assertEquals(0, child.getNumberOfChildren());
        assertEquals(0, child.getChildren().length);
        assertEquals(child, root.getChildren()[0]);
    }

    public final void testIsBinaryTree() {
        assertFalse(t1.isBinaryTree());
        assertTrue(t2.isBinaryTree());
        assertFalse(t3.isBinaryTree());
        assertTrue(t4.isBinaryTree());
        assertTrue(t5.isBinaryTree());
        assertFalse(t6.isBinaryTree());
        assertTrue(t7.isBinaryTree());
        assertTrue(t8.isBinaryTree());
        assertTrue(t9.isBinaryTree());
        assertTrue(t10.isBinaryTree());
    }

    public final void testIsLeaf() {
        assertFalse(t1.isLeaf());
        assertFalse(t2.isLeaf());
        assertFalse(t3.isLeaf());
        assertTrue(t4.isLeaf());
        assertTrue(t5.isLeaf());
        assertFalse(t6.isLeaf());
        assertTrue(t7.isLeaf());
        assertTrue(t8.isLeaf());
        assertTrue(t9.isLeaf());
        assertTrue(t10.isLeaf());
    }

    /*
     * Class under test for boolean equals(Object)
     */
    public final void testEqualsObject() {
        Tree t2a = new Tree("t2");
        Tree t4a = new Tree("t4");
        Tree t5a = new Tree("t5");
        assertFalse(t2.equals(t2a));
        assertFalse(t2a.equals(t2));
        
        t2a.addChild(t4a);
        t2a.addChild(t5a);
        assertTrue(t2.equals(t2a));
        assertTrue(t2a.equals(t2));
        assertFalse(t2.equals(t3));
        assertFalse(t4.equals(t5));
        t5a.setValue("t5a");
        assertFalse(t2.equals(t2a));
        assertFalse(t2a.equals(t5));
        assertFalse(t1.equals("string"));
        assertFalse(t1.equals(null));
    }

    public final void testGetLevel() {
        assertEquals(0, t1.getLevel());
        assertEquals(1, t2.getLevel());
        assertEquals(1, t3.getLevel());
        assertEquals(2, t4.getLevel());
        assertEquals(2, t5.getLevel());
        assertEquals(2, t6.getLevel());
        assertEquals(3, t7.getLevel());
        assertEquals(3, t8.getLevel());
        assertEquals(3, t9.getLevel());
        assertEquals(0, t10.getLevel());
    }

    public final void testGetNumberOfChildren() {
        assertEquals(2, t1.getNumberOfChildren());
        assertEquals(2, t2.getNumberOfChildren());
        assertEquals(1, t3.getNumberOfChildren());
        assertEquals(0, t4.getNumberOfChildren());
        assertEquals(0, t5.getNumberOfChildren());
        assertEquals(3, t6.getNumberOfChildren());
        assertEquals(0, t7.getNumberOfChildren());
        assertEquals(0, t8.getNumberOfChildren());
        assertEquals(0, t9.getNumberOfChildren());
        assertEquals(0, t10.getNumberOfChildren());
    }

    public final void testGetValue() {
        assertEquals("t1", t1.getValue());
        assertEquals("t10", t10.getValue());
    }

    public final void testGetChildren() {
        Tree[] emptyArray = new Tree[0];        

        arraysAreEqual(new Tree[] { t2, t3 },     t1.getChildren());
        arraysAreEqual(new Tree[] { t4, t5 },     t2.getChildren());
        arraysAreEqual(new Tree[] { t6 },         t3.getChildren());
        arraysAreNotEqual(new Tree[] {t2, t3},    t4.getChildren());
        arraysAreEqual(emptyArray,                t5.getChildren());
        arraysAreEqual(new Tree[] { t7, t8, t9 }, t6.getChildren());
        arraysAreEqual(emptyArray,                t7.getChildren());
        arraysAreEqual(emptyArray,                t8.getChildren());
        arraysAreEqual(emptyArray,                t9.getChildren());
        arraysAreEqual(emptyArray,               t10.getChildren());
    }
    
    private void arraysAreEqual(Tree[] array1, Tree[] array2) {
        assertTrue(Arrays.equals(array1, array2));
    }
    
    private void arraysAreNotEqual(Tree[] array1, Tree[] array2) {
        assertFalse(Arrays.equals(array1, array2));
    }

    /*
     * Class under test for String toString()
     */
    public final void testToString() {
        fail("You write these tests to match your desired output");
    }
    
    public final void testGetParent() {
        assertNull(t1.getParent());
        assertEquals(t1, t2.getParent());
        assertEquals(t1, t3.getParent());
        assertEquals(t2, t4.getParent());
        assertEquals(t2, t5.getParent());
        assertEquals(t3, t6.getParent());
        assertEquals(t6, t7.getParent());
        assertEquals(t6, t8.getParent());
        assertEquals(t6, t9.getParent());
        assertNull(t10.getParent());
    }

    public final void testGetSubtree() {
        assertEquals(t2, t1.getSubtree("t2"));
        assertEquals(t3, t1.getSubtree("t3"));
        assertEquals(t9, t6.getSubtree("t9"));
        assertNull(t1.getSubtree("t5"));
        Tree tNull = new Tree(null);
        t1.addChild(tNull);
        assertEquals(tNull, t1.getSubtree(null));
    }

    public final void testSetValue() {
        t1.setValue("xyz");
        t10.setValue("pqr");
        assertEquals("xyz", t1.getValue());
        assertEquals("pqr", t10.getValue());
        t6.setValue(null);
        assertNull(t6.getValue());
    }

    public final void testAddChild() {
        Tree t11 = new Tree("11");
        t3.addChild(t11);
        assertEquals(2, t3.getNumberOfChildren());
        arraysAreEqual(new Tree[] { t6, t11 }, t3.getChildren());
        arraysAreEqual(new Tree[] { t6, t11 }, t3.getChildren());
        
        t3.addChild(t6);
        assertEquals(2, t3.getNumberOfChildren());
        arraysAreEqual(new Tree[] { t11, t6 }, t3.getChildren());
        
        Tree a = new Tree("a");   //      a
        Tree b1 = new Tree("b");  //     / \
        Tree b2 = new Tree("b");  //    b1 b2
        Tree c = new Tree("c");   //    |   |
        Tree d = new Tree("d");   //    c   d
        a.addChild(b1);
        a.addChild(b2);
        b1.addChild(c);
        b2.addChild(d);
        arraysAreEqual(new Tree[] { b1, b2 }, a.getChildren());
        arraysAreNotEqual(new Tree[] { b2, b1 }, a.getChildren());
        a.addChild(b1);
        arraysAreEqual(new Tree[] { b2, b1 }, a.getChildren());
        arraysAreNotEqual(new Tree[] { b1, b2 }, a.getChildren());
    }

    public final void testAddChildren() {
        Tree t4a = new Tree("a");
        Tree t4b = new Tree("b");
        Tree t4c = new Tree("c");
        
        t4.addChildren(new String[] { "a", "b", "c" });
        arraysAreEqual(new Tree[] { t4a, t4b, t4c }, t4.getChildren());
        
        t1.addChildren(new String[] { "a", "b", "c" });
        arraysAreEqual(new Tree[] { t2, t3, t4a, t4b, t4c }, t1.getChildren());
        
    }

    public final void testDeleteChild() {
        assertEquals(t4, t2.deleteChild(t4));
        arraysAreEqual(new Tree[] { t5 }, t2.getChildren());
        assertNull(t4.getParent());
        
        assertEquals(t8, t6.deleteChild(t8));
        arraysAreEqual(new Tree[] { t7, t9 }, t6.getChildren());
        assertNull(t8.getParent());
        
        Tree temp = t6.deleteChild(t9);
        assertEquals(t9, temp);
        arraysAreEqual(new Tree[] { t7 }, t6.getChildren());
        assertNull(temp.getParent());
        
        assertNull(t1.deleteChild(new Tree("t3")));
        
        assertEquals(t3, t1.deleteChild(t3));
        arraysAreEqual(new Tree[] { t2 }, t1.getChildren());
    }
}
