import junit.framework.TestCase;

/*
 * Created on Jan 25, 2004
 */

/**
 * @author David Matuszek
 *
 */
public class BinaryTreeTest extends TestCase {
    BinaryTree leafA, leafB, leafC, nodeAB, rootABC;
    BinaryTree leafB2, rootAB;
    String stringA = "A";
    String stringB = "B";    
    String stringB2 = new String("B");
    String stringC = "C";
    String stringAB = "AB";
    String stringAB2 = stringA + stringB;
    String stringABC = "ABC";
    
    /**
     * Constructor for BinaryTreeTest.
     * @param arg0
     */
    public BinaryTreeTest(String arg0) {
        super(arg0);
    }

    /*
     * Constructs the following trees:<pre>
     * 
     *               rootABC:stringABC
     *                 /       \
     *                /         \
     *     nodeAB:stringAB    leafC:stringC         rootAB:stringAB2
     *           /     \                              /        \
     *          /       \                            /          \
     * leafA:stringA  leafB:stringB         leafA:stringA    leafB2:stringB2
     * 
     * </pre>
     * @see TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        
        leafA = new BinaryTree(stringA);
        leafB = new BinaryTree(stringB);
        leafC = new BinaryTree(stringC, null, null);
        leafB2 = new BinaryTree(stringB2);
        
        nodeAB = new BinaryTree(stringAB, leafA, leafB);
        
        rootABC = new BinaryTree(stringABC, nodeAB, leafC);
        rootAB = new BinaryTree(stringAB2, leafA, leafB2);
        
        assertEquals("A", leafA.value);
        assertEquals("AB", rootAB.value);
    }

    public void testGetLeftChild() {
        BinaryTree t = rootABC.getLeftChild();
        assertEquals(nodeAB, t);
        assertEquals(rootAB, t);
        assertSame(t, nodeAB);
        assertNotSame(t, rootAB);
        assertEquals(null, leafA.getLeftChild());        
    }

    public void testGetRightChild() {
        assertEquals(leafC, rootABC.getRightChild());
        assertEquals(leafB, rootABC.getLeftChild().getRightChild());
        assertEquals(null, rootABC.getRightChild().getRightChild());
    }

    public void testSetLeftChild() {
        BinaryTree leafD = new BinaryTree("D");
        leafA.setLeftChild(leafD);
        assertEquals(leafD, leafA.getLeftChild());
        try {
            leafB2.setLeftChild(rootAB);
            fail("Failed loop test");
        }
        catch (IllegalArgumentException e) {}
        leafB2.setLeftChild(rootABC); // should not throw exception
        assertEquals(leafB2.getLeftChild(), rootABC);
    }

    public void testSetRightChild() {
        BinaryTree leafD = new BinaryTree("D");
        leafC.setRightChild(leafD);
        assertEquals(leafD, leafC.getRightChild());
        try {
            leafB.setRightChild(nodeAB);
            fail("Failed loop test");
        }
        catch (IllegalArgumentException e) {}
        leafB2.setRightChild(rootABC); // should not throw exception
        assertEquals(leafB2.getRightChild(), rootABC);
    }
    
    public void testSetAndGetValue() {
        nodeAB.setValue("Test value");
        assertEquals("Test value", nodeAB.getValue());
    }

    public void testIsLeaf() {
        assertTrue(leafA.isLeaf());
        assertFalse(nodeAB.isLeaf());
    }

    /*
     * Test for boolean equals(Object)
     */
    public void testEqualsObject() {
        assertTrue(nodeAB.equals(rootAB));
        assertTrue(rootAB.equals(nodeAB));
        assertNotSame(rootAB, nodeAB);
        assertNull(leafA.getRightChild());
    }
    
    public void testToString() {
        assertEquals("ABC (AB (A, B), C)", rootABC.toString());       
        BinaryTree root = makeTreeWithMissingChildren();
        assertEquals("A (B (D, null), C (null, E))", root.toString());
    }

    private BinaryTree makeTreeWithMissingChildren() {
        BinaryTree root, left, right;
        left = new BinaryTree("D");
        left = new BinaryTree("B", left, null);
        right = new BinaryTree("E");
        right = new BinaryTree("C", null, right);
        root = new BinaryTree("A", left, right);
        return root;
    }
    
    public void testHashCode() {
        BinaryTree first = makeTreeWithMissingChildren();
        BinaryTree second = makeTreeWithMissingChildren();
        assertEquals(first.hashCode(), second.hashCode());
    }
    /**
     * In general we do not want anything printed out when we run
     * our tests. This class can be run as a JUnit test, in which
     * case this method will not be called, or as an application,
     * in which case this method <i>will</i> be called.
     * <p>
     * The only reason to run this class as an application is to
     * test the print() method in BinaryTree; the results have to
     * be evaluated by hand.
     * <p>
     * Note that we could write a print method that took an output
     * stream as a parameter; this would allow JUnit testing.
     * 
     * @param args Not used.
     */
    public static void main(String[] args) {
        BinaryTreeTest test = new BinaryTreeTest("Method used only for testing print()");
        try {
            test.setUp();
            test.rootABC.print();
            System.out.println("--------------");
            test.makeTreeWithMissingChildren().print();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}
