swingx-master/swingx-core/src/test/java/org/jdesktop/swingx/tree/TreeUtilitiesTest.java
/*
 * Created on 17.02.2012
 *
 */
package org.jdesktop.swingx.tree;

import static org.jdesktop.swingx.tree.TreeUtilities.EMPTY_ENUMERATION;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.logging.Logger;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.jdesktop.swingx.InteractiveTestCase;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.tree.TreeUtilities.BreadthFirstModelEnumeration;
import org.jdesktop.swingx.tree.TreeUtilities.BreadthFirstNodeEnumeration;
import org.jdesktop.swingx.tree.TreeUtilities.PostorderModelEnumeration;
import org.jdesktop.swingx.tree.TreeUtilities.PostorderNodeEnumeration;
import org.jdesktop.swingx.tree.TreeUtilities.PreorderModelEnumeration;
import org.jdesktop.swingx.tree.TreeUtilities.PreorderNodeEnumeration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Test of TreeUtilities.
 * 
 * @author Jeanette Winzenburg, Berlin
 */
@RunWith(JUnit4.class)
public class TreeUtilitiesTest extends InteractiveTestCase {

// traversal tests
// all tests are against the corresponding traversals in DefaultMutableTreeNode
// --> implicit assumption is that core has it correct    
    
    private TreeModel model;
    private DefaultMutableTreeNode root;
    @Test
    public void testBreadthFirstNode() {
        Enumeration<?> coreEnum = root.breadthFirstEnumeration();
        Enumeration<?> xEnum = new BreadthFirstNodeEnumeration<DefaultMutableTreeNode>(root);
        assertSameEnumeration("BreadthFirstNode", coreEnum, xEnum);
    }
    
    @Test
    public void testPostorderNode() {
        Enumeration<?> coreEnum = root.postorderEnumeration();
        Enumeration<?> xEnum = new PostorderNodeEnumeration<DefaultMutableTreeNode>(root);
        assertSameEnumeration("PostOrderNode", coreEnum, xEnum);
    }
    
    @Test
    public void testPreorderNode() {
        Enumeration<?> coreEnum = root.preorderEnumeration();
        Enumeration<?> xEnum = new PreorderNodeEnumeration<TreeNode>(root);
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }

    
    @Test
    public void testPostorderModel() {
        Enumeration<?> coreEnum = root.postorderEnumeration();
        Enumeration<?> xEnum = new PostorderModelEnumeration(model,root);
        assertSameEnumeration("PostOrderModel", coreEnum, xEnum);
    }
    
    @Test
    public void testPostorderModelConstructor() {
        Enumeration<?> coreEnum = root.postorderEnumeration();
        Enumeration<?> xEnum = new PostorderModelEnumeration(model);
        assertSameEnumeration("PostOrderModel", coreEnum, xEnum);
    }
    
    @Test
    public void testBreadthFirstModel() {
        Enumeration<?> coreEnum = root.breadthFirstEnumeration();
        Enumeration<?> xEnum = new BreadthFirstModelEnumeration(model);
        assertSameEnumeration("BreadthFirstModel", coreEnum, xEnum);
    }
    
    @Test
    public void testPreorderModel() {
        Enumeration<?> coreEnum = root.preorderEnumeration();
        Enumeration<?> xEnum = new PreorderModelEnumeration(model);
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }
    
    @Test
    public void testPreorderModelWithRoot() {
        Enumeration<?> coreEnum = root.preorderEnumeration();
        Enumeration<?> xEnum = new PreorderModelEnumeration(model, root);
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }
    
    @Test
    public void testPreorderModelWithRootPath() {
        Enumeration<?> coreEnum = root.preorderEnumeration();
        Enumeration<?> xEnum = new PreorderModelEnumeration(model, new TreePath(root));
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }
    
    
    @Test
    public void testPreorderModelWithPath() {
        TreePath path = new TreePath(root);
        // add first child and first grandChild
        path = path.pathByAddingChild(root.getChildAt(0));
        path = path.pathByAddingChild(root.getChildAt(0).getChildAt(0));
        Enumeration<?> coreEnum = root.preorderEnumeration();
        // build a starting tree path 
        for (int i = 0; i < 2; i++) {
            // move coreEnum so that next == path.lastPathComponent
            coreEnum.nextElement();
        }
        Enumeration<?> xEnum = new PreorderModelEnumeration(model, path);
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }
    
    @Test
    public void testPreorderModelSubtree() {
        Enumeration<?> coreEnum = ((DefaultMutableTreeNode) root.getChildAt(0)).preorderEnumeration();
        Enumeration<?> xEnum = new PreorderModelEnumeration(model, root.getChildAt(0));
        assertSameEnumeration("PreorderModel", coreEnum, xEnum);
    }
    
    /**
     * Asserts that xEnum returns the same elements as the coreEnum.
     *  
     * @param message identifier used in failure output
     * @param coreEnum an enum we think is correct
     * @param xEnum an enum to test for correctness
     */
    private void assertSameEnumeration(String message, Enumeration<?> coreEnum,
            Enumeration<?> xEnum) {
        while(coreEnum.hasMoreElements()) {
            assertTrue(message + " must have more elements", xEnum.hasMoreElements());
            assertSame(message, coreEnum.nextElement(), xEnum.nextElement());
        }
        assertFalse(message + " must not have more elements", xEnum.hasMoreElements());
    }

    @Test(expected = NoSuchElementException.class)
    public void testEmptyEnumeration() {
        assertFalse(EMPTY_ENUMERATION.hasMoreElements());
        EMPTY_ENUMERATION.nextElement();
    }

//------------------
    
    
    @Override
    @Before
    public void setUp() throws Exception {
        JXTree tree = new JXTree();
        model = tree.getModel();
        root = (DefaultMutableTreeNode) model.getRoot();
    }
    
    
//----------------- random generation of trees consisting of DefaultMutableTreeNodes
    
    private static Random random = new Random();
    /**
     * Creates a random tree of nodes of type MutableTreeNode 
     * (actually: DefaultMutableTreeNode). Copied from
     * test.aephyr.swing.TreeSort
     * <p>
     * 
     * PENDING JW: add option to initialize with the same random sequence.
     * 
     * @param text the text of the root
     * @param depth the depth of the tree
     * @return a tree of random nodes
     */
    public static MutableTreeNode createTreeNode(String text, int depth) {
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(text);
        if (--depth >= 0)
            for (int i = bellCurve(); --i >= 0;)
                node.add(createTreeNode(createCellValue(), depth));
        return node;
    }
    
    private static int bellCurve() {
        int i = Integer.bitCount(random.nextInt());
        if (i < 13)
                return i;
        return i-12;
    }
    private static String createCellValue() {
        char[] c = new char[bellCurve() + 2];
        for (int i = c.length; --i >= 0;)
            c[i] = (char) (random.nextInt(26) + 'a');
        c[0] = Character.toUpperCase(c[0]);
        return new String(c);
    }


    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(TreeUtilitiesTest.class
            .getName());
}
