#!/usr/bin/perl

use strict;
use warnings;

use Test::More tests => 290;

BEGIN { 
    #use_ok('Tree::Compat', 'Tree::Simple'); 
    use_ok('Tree::Compat::Tree::Simple'); 
};

## ----------------------------------------------------------------------------
## Test for Tree::Simple
## ----------------------------------------------------------------------------
# NOTE:
# This test checks the base functionality of the Tree::Simple object. The test
# is so large because (at the moment) each test relies upon the tree created 
# by the previous tests. It is not the most efficient or sensible thing to do
# i know, but its how it is for now. There are close to 300 tests here, so 
# splitting them up would be a chore. 
## ----------------------------------------------------------------------------

# check that we have a constructor
can_ok("Tree::Simple", 'new');
# and that our ROOT constant is properly defined
can_ok("Tree::Simple", 'ROOT');

# make a root for our tree
my $tree = Tree::Simple->new("root tree", Tree::Simple->ROOT);
isa_ok($tree, 'Tree::Simple');

# test the interface

can_ok($tree, '_init');
can_ok($tree, '_setParent');

can_ok($tree, 'isRoot');
can_ok($tree, 'isLeaf');

can_ok($tree, 'setNodeValue');
can_ok($tree, 'getNodeValue');

can_ok($tree, 'getDepth');
can_ok($tree, 'fixDepth');
can_ok($tree, 'getParent');

can_ok($tree, 'getChildCount');

can_ok($tree, 'addChild');
can_ok($tree, 'addChildren');
can_ok($tree, 'insertChild');
can_ok($tree, 'insertChildren');
can_ok($tree, 'removeChildAt');
can_ok($tree, 'removeChild');
can_ok($tree, 'getChild');
can_ok($tree, 'getAllChildren');

can_ok($tree, 'addSibling');
can_ok($tree, 'addSiblings');
can_ok($tree, 'insertSibling');
can_ok($tree, 'insertSiblings');
can_ok($tree, 'getSibling');
can_ok($tree, 'getAllSiblings');

can_ok($tree, 'traverse');
can_ok($tree, 'accept');
can_ok($tree, 'clone');
can_ok($tree, 'cloneShallow');

can_ok($tree, 'DESTROY');

# verfiy that it is a root
ok($tree->isRoot());

# and since it has no children
# it is also a leaf node
ok($tree->isLeaf());

# check the value of the node,
# it should be root
is($tree->getNodeValue(), "root tree", '... this tree is a root');

# we have no children yet
cmp_ok($tree->getChildCount(), '==', 0, '... we have no children yet');

# check the depth
cmp_ok($tree->getDepth(), '==', -1, '... we have no depth yet');

# check the index
cmp_ok($tree->getIndex(), '==', -1, '... root trees have no index');

can_ok($tree, 'getUID');

is($tree->getUID(), $tree->getUID(), '... UIDs match for the same object');

#XXX Test changed
is("$tree", "Tree::Simple=REF(" . $tree->getUID() . ")", '... our UID is derived from our hex address'); 

can_ok($tree, 'setUID');
$tree->setUID("This is our unique identifier");

is($tree->getUID(), 'This is our unique identifier', '... UIDs match what we have set it to');

#XXX Test changed
isnt("$tree", "Tree::Simple=REF(" . $tree->getUID() . ")", '... our UID is no longer derived from our hex address'); 

## ----------------------------------------------------------------------------
## testing adding children
## ----------------------------------------------------------------------------

# create a child
my $sub_tree = Tree::Simple->new("1.0");
isa_ok($sub_tree, 'Tree::Simple');

# check the node value
is($sub_tree->getNodeValue(), "1.0", '... this tree is 1.0');

# since we have not assigned a parent it 
# will still be considered a root
ok($sub_tree->isRoot());

# and since it has no children
# it is also a leaf node
ok($sub_tree->isLeaf());    

# now add the child to our root
$tree->addChild($sub_tree);

# tree is no longer a leaf node
# now that we have a child
ok(!$tree->isLeaf());

# now that we have assigned a parent it
# will no longer be considered a root
ok(!$sub_tree->isRoot());

# check the depth of the sub_tree
cmp_ok($sub_tree->getDepth(), '==', 0, '... depth should be 0 now');

# check the index
cmp_ok($sub_tree->getIndex(), '==', 0, '... index should be 0 now');

# check the child count, 
# it should be one now
cmp_ok($tree->getChildCount(), '==', 1, '... we should have 1 children now');

# get the child we inserted
# and compare it with sub_tree
# they should be the same
is($tree->getChild(0), $sub_tree, '... make sure our sub_tree is fetchable');

# get the parent of sub_tree
my $sub_tree_parent = $sub_tree->getParent();

# now test that the parent of
# our sub_tree is the same as
# our root    
is($tree, $sub_tree_parent, '... make sure our sub_tree parent is tree');

## ----------------------------------------------------------------------------
## testing adding siblings
## ----------------------------------------------------------------------------
    
# create another sub_tree
my $sub_tree_2 = Tree::Simple->new("2.0");
isa_ok($sub_tree_2, 'Tree::Simple');

# check its node value
is($sub_tree_2->getNodeValue(), "2.0", '... this tree is 2.0');

# since we have not assigned a parent to 
# the new sub_tree it will still be
# considered a root
ok($sub_tree_2->isRoot());

# and since it has no children
# it is also a leaf node
ok($sub_tree_2->isLeaf());

# add our new subtree as a sibling
# of our first sub_tree
$sub_tree->addSibling($sub_tree_2);

# now that we have assigned a parent to
# the new sub_tree, it will no longer be 
# considered a root
ok(!$sub_tree_2->isRoot());

# check the depth of the sub_tree
cmp_ok($sub_tree_2->getDepth(), '==', 0, '... depth should be 0 now');

# check the index
cmp_ok($sub_tree_2->getIndex(), '==', 1, '... index should be 1');

# make sure that we now have 2 children in our root    
cmp_ok($tree->getChildCount(), '==', 2, '... we should have 2 children now');    

# and verify that the child at index 1
# is actually our second sub_tree    
is($tree->getChild(1), $sub_tree_2, '... make sure our sub_tree is fetchable');    
    
# get the parent of our second sub_tree
my $sub_tree_2_parent = $sub_tree_2->getParent();

# and make sure that it is the 
# same as our root
is($tree, $sub_tree_2_parent, '... make sure our sub_tree_2 parent is tree');
    
## ----------------------------------------------------------------------------
## test adding child by giving parent as a constructor argument
## ----------------------------------------------------------------------------    

# we create our new sub_tree and attach it
# to our root through its constructor
my $sub_tree_4 = Tree::Simple->new("4.0", $tree);     

# check its node value
is($sub_tree_4->getNodeValue(), "4.0", '... this tree is 4.0');

# since we have assigned a parent to
# the new sub_tree, it will no longer be 
# considered a root
ok(!$sub_tree_4->isRoot());

# check the depth of the sub_tree
cmp_ok($sub_tree_4->getDepth(), '==', 0, '... depth should be 0 now');

# check the index
cmp_ok($sub_tree_4->getIndex(), '==', 2, '... index should be 2 now');

# but since it has no children
# it is also a leaf node
ok($sub_tree_4->isLeaf());

# make sure that we now have 3 children in our root    
cmp_ok($tree->getChildCount(), '==', 3, '... we should have 3 children now');

# and verify that the child at index 2
# is actually our latest sub_tree    
is($tree->getChild(2), $sub_tree_4, '... make sure our sub_tree is fetchable');    

# and make sure that the new sub-trees
# parent is the same as our root
is($tree, $sub_tree_4->getParent(), '... make sure our sub_tree_4 parent is tree');

## ----------------------------------------------------------------------------
## test inserting child 
## ----------------------------------------------------------------------------    

# we create our new sub_tree 
my $sub_tree_3 = Tree::Simple->new("3.0");     

# check its node value
is($sub_tree_3->getNodeValue(), "3.0", '... this tree is 3.0');

# since we have not assigned a parent to 
# the new sub_tree it will still be
# considered a root
ok($sub_tree_3->isRoot());

# but since it has no children
# it is also a leaf node
ok($sub_tree_3->isLeaf());

# now insert the child at index 2
$tree->insertChild(2, $sub_tree_3);

# since we now have assigned a parent to
# the new sub_tree, it will no longer be 
# considered a root
ok(!$sub_tree_3->isRoot());

# check the depth of the sub_tree
cmp_ok($sub_tree_3->getDepth(), '==', 0, '... depth should be 0 now');

# check the index of 3
cmp_ok($sub_tree_3->getIndex(), '==', 2, '... index should be 2 now');

# check the index of 4 now
cmp_ok($sub_tree_4->getIndex(), '==', 3, '... index should be 3 now');

# make sure that we now have 3 children in our root    
cmp_ok($tree->getChildCount(), '==', 4, '... we should have 4 children now');

# and verify that the child at index 2
# is actually our latest sub_tree    
is($tree->getChild(2), $sub_tree_3, '... make sure our sub_tree is fetchable');    

# and verify that the child that was 
# at index 2 is actually now actually
# at index 3    
is($tree->getChild(3), $sub_tree_4, '... make sure our sub_tree is fetchable');    

# and make sure that the new sub-trees
# parent is the same as our root
is($tree, $sub_tree_3->getParent(), '... make sure our sub_tree_3 parent is tree');    

## ----------------------------------------------------------------------------
## test getting all children and siblings
## ----------------------------------------------------------------------------    

# get it in scalar context and
# check that our arrays are equal
my $children = $tree->getAllChildren();
ok eq_array($children, [ $sub_tree, $sub_tree_2, $sub_tree_3, $sub_tree_4 ]);

# get it in array context and
# check that our arrays are equal
my @children = $tree->getAllChildren();
ok eq_array(\@children, [ $sub_tree, $sub_tree_2, $sub_tree_3, $sub_tree_4 ]);

# check that the values from both
# contexts are equal to one another
ok eq_array($children, \@children);

# now check that the siblings of all the 
# sub_trees are the same as the children
foreach my $_sub_tree (@children) {
    # test siblings in scalar context
    my $siblings = $sub_tree->getAllSiblings();
    ok eq_array($children, $siblings);
    # and now in array context
    my @siblings = $sub_tree->getAllSiblings();
    ok eq_array($children, \@siblings);
}

## ----------------------------------------------------------------------------
## test addChildren
## ----------------------------------------------------------------------------    

my @sub_children = (
             Tree::Simple->new("1.1"),
            Tree::Simple->new("1.5"),
            Tree::Simple->new("1.6")
            );

# now go through the children and test them
foreach my $sub_child (@sub_children) {
    # they should think they are root
    ok($sub_child->isRoot());

    # and they should all be leaves
    ok($sub_child->isLeaf());

    # and their node values
    like($sub_child->getNodeValue(), qr/1\.[0-9]/, '... they at least have "1." followed by a digit');
    
    # and they should all have a depth of -1
    cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');    
}

# check to see if we can add children
$sub_tree->addChildren(@sub_children);

# we are no longer a leaf node now
ok(!$sub_tree->isLeaf());

# make sure that we now have 3 children now    
cmp_ok($sub_tree->getChildCount(), '==', 3, '... we should have 3 children now');

# now check that the children of the sub_tree
# are the same as our list
ok eq_array([ $sub_tree->getAllChildren() ], \@sub_children);

# now go through the children again
# and test them
foreach my $sub_child (@sub_children) {
    # they should no longer think
    # they are root
    ok(!$sub_child->isRoot());
    
    # but they should still think they 
    # are leaves
    ok($sub_child->isLeaf());
    
    # now we test their parental relationship
    is($sub_tree, $sub_child->getParent(), '... their parent is the sub_tree');
    
    # and they should all have a depth of 1
    cmp_ok($sub_child->getDepth(), '==', 1, '... depth should be 1');
    
    # now check that its siblings are the same 
    # as the children of its parent            
    ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}

## ----------------------------------------------------------------------------
## test insertingChildren
## ----------------------------------------------------------------------------    

my @more_sub_children = (
             Tree::Simple->new("1.2"),
            Tree::Simple->new("1.3"),
            Tree::Simple->new("1.4")
            );

# now go through the children and test them
foreach my $sub_child (@more_sub_children) {
    # they should think they are root
    ok($sub_child->isRoot());

    # and they should all be leaves
    ok($sub_child->isLeaf());

    # and their node values
    like($sub_child->getNodeValue(), qr/1\.[0-9]/, '... they at least have "1." followed by a digit');
    
    # and they should all have a depth of -1
    cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');    
}

# check to see if we can insert children
$sub_tree->insertChildren(1, @more_sub_children);

# make sure that we now have 6 children now    
cmp_ok($sub_tree->getChildCount(), '==', 6, '... we should have 6 children now');

# now check that the children of the sub_tree
# are the same as our list
ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_children[0], @more_sub_children, @sub_children[1 .. $#sub_children] ]);

# now go through the children again
# and test them
foreach my $sub_child (@more_sub_children) {
    # they should no longer think
    # they are roots
    ok(!$sub_child->isRoot());
    
    # but they should still think they 
    # are leaves
    ok($sub_child->isLeaf());
    
    # now we test their parental relationship
    is($sub_tree, $sub_child->getParent(), '... their parent is the sub_tree');
    
    # and they should all have a depth of 1
    cmp_ok($sub_child->getDepth(), '==', 1, '... depth should be 1');
    
    # now check that its siblings are the same 
    # as the children of its parent
    ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}

## ----------------------------------------------------------------------------
## test addingSiblings
## ----------------------------------------------------------------------------    

my @more_children = (
             Tree::Simple->new("5.0"),
            Tree::Simple->new("9.0")
            );

# now go through the children and test them
foreach my $sub_child (@more_children) {
    # they should think they are root
    ok($sub_child->isRoot());

    # and they should all be leaves
    ok($sub_child->isLeaf());

    # and their node values
    like($sub_child->getNodeValue(), qr/[0-9]\.0/, '... they at least have digit followed by ".0"');
    
    # and they should all have a depth of -1
    cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');    
}

# check to see if we can insert children
$sub_tree->addSiblings(@more_children);

# make sure that we now have 6 children now    
cmp_ok($tree->getChildCount(), '==', 6, '... we should have 6 children now');

# now check that the new children of the tree
# are the same as our list
is($tree->getChild(4), $more_children[0], '... they are the same');
is($tree->getChild(5), $more_children[1], '... they are the same');

# now go through the children again
# and test them
foreach my $sub_child (@more_children) {
    # they should no longer think
    # they are roots
    ok(!$sub_child->isRoot());
    
    # but they should still think they 
    # are leaves
    ok($sub_child->isLeaf());
    
    # now we test their parental relationship
    is($tree, $sub_child->getParent(), '... their parent is the tree');
    
    # and they should all have a depth of 1
    cmp_ok($sub_child->getDepth(), '==', 0, '... depth should be 0');
    
    # now check that its siblings are the same 
    # as the children of its parent            
    ok eq_array([ $tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}

## ----------------------------------------------------------------------------
## test insertSibling
## ----------------------------------------------------------------------------    

my $new_sibling = Tree::Simple->new("8.0"); 

# they should think they are root
ok($new_sibling->isRoot());

# and they should all be leaves
ok($new_sibling->isLeaf());

# and their node values
is($new_sibling->getNodeValue(), "8.0", '... node value should be 6.0');

# and they should all have a depth of -1
cmp_ok($new_sibling->getDepth(), '==', -1, '... depth should be -1');    

# check to see if we can insert children
$sub_tree->insertSibling(5, $new_sibling);

# make sure that we now have 6 children now    
cmp_ok($tree->getChildCount(), '==', 7, '... we should have 7 children now');

# now check that new siblings of the sub_tree
# is in the right place and that it 
# should have displaced the old value at
# that index to index + 1 
is($tree->getChild(4), $more_children[0], '... they are the same');
is($tree->getChild(5), $new_sibling, '... they are the same');
is($tree->getChild(6), $more_children[1], '... they are the same');

# they should no longer think
# they are roots
ok(!$new_sibling->isRoot());

# but they should still think they 
# are leaves
ok($new_sibling->isLeaf());

# now we test their parental relationship
is($tree, $new_sibling->getParent(), '... their parent is the tree');

# and they should all have a depth of 1
cmp_ok($new_sibling->getDepth(), '==', 0, '... depth should be 0');
    
# now check that its siblings are the same 
# as the children of its parent            
ok eq_array([ $tree->getAllChildren() ], [ $new_sibling->getAllSiblings() ]);

## ----------------------------------------------------------------------------
## test inserting Siblings
## ----------------------------------------------------------------------------    

my @even_more_children = (
             Tree::Simple->new("6.0"),
            Tree::Simple->new("7.0")
            );

# now go through the children and test them
foreach my $sub_child (@even_more_children) {
    # they should think they are root
    ok($sub_child->isRoot());

    # and they should all be leaves
    ok($sub_child->isLeaf());

    # and their node values
    like($sub_child->getNodeValue(), qr/[0-9]\.0/, '... they at least have digit followed by ".0"');
    
    # and they should all have a depth of -1
    cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');    
}

# check to see if we can insert children
$sub_tree->insertSiblings(5, @even_more_children);

# make sure that we now have 6 children now    
cmp_ok($tree->getChildCount(), '==', 9, '... we should have 6 children now');

# now check that new children of the tree
# are the same as our list
is($tree->getChild(4), $more_children[0], '... they are the same');
is($tree->getChild(5), $even_more_children[0], '... they are the same');
is($tree->getChild(6), $even_more_children[1], '... they are the same');
is($tree->getChild(7), $new_sibling, '... they are the same');
is($tree->getChild(8), $more_children[1], '... they are the same');

# now go through the children again
# and test them
foreach my $sub_child (@even_more_children) {
    # they should no longer think
    # they are roots
    ok(!$sub_child->isRoot());
    
    # but they should still think they 
    # are leaves
    ok($sub_child->isLeaf());
    
    # now we test their parental relationship
    is($tree, $sub_child->getParent(), '... their parent is the tree');
    
    # and they should all have a depth of 1
    cmp_ok($sub_child->getDepth(), '==', 0, '... depth should be 0');
    
    # now check that its siblings are the same 
    # as the children of its parent            
    ok eq_array([ $tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}

## ----------------------------------------------------------------------------
## test getChild and getSibling
## ----------------------------------------------------------------------------    

# make sure that getChild returns the
# same as getSibling
is($tree->getChild($_), $sub_tree->getSibling($_), '... siblings are the same as children') 
    foreach (0 .. $tree->getChildCount() - 1);

## ----------------------------------------------------------------------------
## test self referential returns
## ----------------------------------------------------------------------------    

# the return value addChildren() is actually $self
# so that method calls can be chained
my $self_ref_tree_test = Tree::Simple->new("3.1", $sub_tree_3)
                                ->addChildren(
                                    Tree::Simple->new("3.1.1"),
                                    Tree::Simple->new("3.1.2")
                                );
# make sure that it true
isa_ok($self_ref_tree_test, 'Tree::Simple');

# it shouldnt be a root
ok(!$self_ref_tree_test->isRoot());

# and it shouldnt be a leaf
ok(!$self_ref_tree_test->isLeaf());

# make sure that the parent in the constructor worked
is($sub_tree_3, $self_ref_tree_test->getParent(), '... should be the same');

# and the parents count should be 1
cmp_ok($sub_tree_3->getChildCount(), '==', 1, '... we should have 1 child here');

# make sure they show up in the count test
cmp_ok($self_ref_tree_test->getChildCount(), '==', 2, '... we should have 2 children here');

foreach my $sub_child ($self_ref_tree_test->getAllChildren()) {
    # they should not think
    # they are roots
    ok(!$sub_child->isRoot());
    
    # but they should think they 
    # are leaves
    ok($sub_child->isLeaf());
    
    # now we test their parental relationship
    is($self_ref_tree_test, $sub_child->getParent(), '... their parent is the tree');
    
    # and they should all have a depth of 1
    cmp_ok($sub_child->getDepth(), '==', 2, '... depth should be 0');
    
    # now check that its siblings are the same 
    # as the children of its parent            
    ok eq_array([ $self_ref_tree_test->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}

## ----------------------------------------------------------------------------    
## Test self-referential version of addChild
## ----------------------------------------------------------------------------

# addChild also returns $self
# so that method calls can be chained
my $self_ref_tree_test_2 = Tree::Simple->new("2.1", $sub_tree_2)
                                ->addChild(
                                    Tree::Simple->new("2.1.1")
                                );
# make sure that it true
isa_ok($self_ref_tree_test_2, 'Tree::Simple');

# it shouldnt be a root
ok(!$self_ref_tree_test_2->isRoot());

# and it shouldnt be a leaf
ok(!$self_ref_tree_test_2->isLeaf());

# make sure that the parent in the constructor worked
is($sub_tree_2, $self_ref_tree_test_2->getParent(), '... should be the same');

# and the parents count should be 1
cmp_ok($sub_tree_2->getChildCount(), '==', 1, '... we should have 1 child here');

# make sure they show up in the count test
cmp_ok($self_ref_tree_test_2->getChildCount(), '==', 1, '... we should have 1 child here');

my $sub_child = $self_ref_tree_test_2->getChild(0);

# they should not think
# they are roots
ok(!$sub_child->isRoot());

# but they should think they 
# are leaves
ok($sub_child->isLeaf());

# now we test their parental relationship
is($self_ref_tree_test_2, $sub_child->getParent(), '... their parent is the tree');

# and they should all have a depth of 1
cmp_ok($sub_child->getDepth(), '==', 2, '... depth should be 0');

# now check that its siblings are the same 
# as the children of its parent        
ok eq_array([ $self_ref_tree_test_2->getAllChildren() ], [ $sub_child->getAllSiblings() ]);

## ----------------------------------------------------------------------------
## test removeChildAt
## ----------------------------------------------------------------------------    

my $sub_tree_of_tree_to_remove = Tree::Simple->new("1.1.a.1");
# make a node to remove
my $tree_to_remove = Tree::Simple->new("1.1.a")->addChild($sub_tree_of_tree_to_remove);

# test that its a root
ok($tree_to_remove->isRoot());

# and that its depth is -1
cmp_ok($tree_to_remove->getDepth(), '==', -1, '... the depth should be -1'); 
# and the sub-trees depth is 0
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 0, '... the depth should be 0'); 

# insert it into the sub_tree
$sub_tree->insertChild(1, $tree_to_remove);

# test that it no longer thinks its a root
ok(!$tree_to_remove->isRoot());

# check thats its depth is now 1
cmp_ok($tree_to_remove->getDepth(), '==', 1, '... the depth should be 1'); 
# and the sub-trees depth is 2
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 2, '... the depth should be 2'); 

# make sure it is there
is($sub_tree->getChild(1), $tree_to_remove, '... these tree should be equal');        

# remove the subtree (it will be returned)
my $removed_tree = $sub_tree->removeChildAt(1);

# now check that the one removed it the one 
# we inserted origianlly
is($removed_tree, $tree_to_remove, '... these tree should be equal');

# it should think its a root again
ok($tree_to_remove->isRoot());
# and its depth should be back to -1
cmp_ok($tree_to_remove->getDepth(), '==', -1, '... the depth should be -1'); 
# and the sub-trees depth is 0
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 0, '... the depth should be 0');     

## ----------------------------------------------------------------------------
## test removeChild
## ----------------------------------------------------------------------------    

my $sub_tree_of_tree_to_remove2 = Tree::Simple->new("1.1.a.1");
# make a node to remove
my $tree_to_remove2 = Tree::Simple->new("1.1.a")->addChild($sub_tree_of_tree_to_remove2);

# test that its a root
ok($tree_to_remove2->isRoot());

# and that its depth is -1
cmp_ok($tree_to_remove2->getDepth(), '==', -1, '... the depth should be -1'); 
# and the sub-trees depth is 0
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 0, '... the depth should be 0'); 

# insert it into the sub_tree
$sub_tree->insertChild(1, $tree_to_remove2);

# test that it no longer thinks its a root
ok(!$tree_to_remove2->isRoot());

# check thats its depth is now 1
cmp_ok($tree_to_remove2->getDepth(), '==', 1, '... the depth should be 1'); 
# and the sub-trees depth is 2
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 2, '... the depth should be 2'); 

# make sure it is there
is($sub_tree->getChild(1), $tree_to_remove2, '... these tree should be equal');        

# remove the subtree (it will be returned)
my $removed_tree2 = $sub_tree->removeChild($tree_to_remove2);

# now check that the one removed it the one 
# we inserted origianlly
is($removed_tree2, $tree_to_remove2, '... these tree should be equal');

# it should think its a root again
ok($tree_to_remove2->isRoot());
# and its depth should be back to -1
cmp_ok($tree_to_remove2->getDepth(), '==', -1, '... the depth should be -1'); 
# and the sub-trees depth is 0
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 0, '... the depth should be 0');     

## ----------------------------------------------------------------------------
## test removeChild backwards compatability
## ----------------------------------------------------------------------------    

# make a node to remove
my $tree_to_remove3 = Tree::Simple->new("1.1.a");

# test that its a root
ok($tree_to_remove3->isRoot());

# and that its depth is -1
cmp_ok($tree_to_remove3->getDepth(), '==', -1, '... the depth should be -1'); 

# insert it into the sub_tree
$sub_tree->insertChild(1, $tree_to_remove3);

# test that it no longer thinks its a root
ok(!$tree_to_remove3->isRoot());

# check thats its depth is now 1
cmp_ok($tree_to_remove3->getDepth(), '==', 1, '... the depth should be 1'); 

# make sure it is there
is($sub_tree->getChild(1), $tree_to_remove3, '... these tree should be equal');        

# remove the subtree (it will be returned)
my $removed_tree3 = $sub_tree->removeChild(1);

# now check that the one removed it the one 
# we inserted origianlly
is($removed_tree3, $tree_to_remove3, '... these tree should be equal');

# it should think its a root again
ok($tree_to_remove3->isRoot());
# and its depth should be back to -1
cmp_ok($tree_to_remove3->getDepth(), '==', -1, '... the depth should be -1'); 

## ----------------------------------------------
## now test the edge cases
## ----------------------------------------------

# trees at the end

# make a node to remove
my $tree_to_remove_2 = Tree::Simple->new("1.7");

# add it into the sub_tree
$sub_tree->addChild($tree_to_remove_2);

# make sure it is there
is($sub_tree->getChild($sub_tree->getChildCount() - 1), $tree_to_remove_2, '... these tree should be equal');        

# remove the subtree (it will be returned)
my $removed_tree_2 = $sub_tree->removeChildAt($sub_tree->getChildCount() - 1);

# now check that the one removed it the one 
# we inserted origianlly
is($removed_tree_2, $tree_to_remove_2, '... these tree should be equal');

# trees at the beginging

# make a node to remove
my $tree_to_remove_3 = Tree::Simple->new("1.1.-1");

# add it into the sub_tree
$sub_tree->insertChild(0, $tree_to_remove_3);

# make sure it is there
is($sub_tree->getChild(0), $tree_to_remove_3, '... these tree should be equal');        

# remove the subtree (it will be returned)
my $removed_tree_3 = $sub_tree->removeChildAt(0);

# now check that the one removed it the one 
# we inserted origianlly
is($removed_tree_3, $tree_to_remove_3, '... these tree should be equal');        

## ----------------------------------------------------------------------------
## test traverse
## ----------------------------------------------------------------------------    

# make a control set of 
# all the nodes we have
my @_all_node_values = qw(
    1.0 
        1.1 
        1.2
        1.3
        1.4
        1.5
        1.6
    2.0
        2.1
            2.1.1
    3.0
        3.1
            3.1.1
            3.1.2
    4.0
    5.0
    6.0
    7.0
    8.0
    9.0
    );

my @all_node_values;
# now collect the nodes in the actual tree
$tree->traverse(sub {
    my ($_tree) = @_;
    push @all_node_values => $_tree->getNodeValue();
    });

# and compare the two
is_deeply(\@all_node_values, \@_all_node_values, '... our nodes match our control nodes');

## ----------------------------------------------------------------------------
## test size
## ----------------------------------------------------------------------------    

cmp_ok($tree->size(), '==', (scalar(@_all_node_values) + 1), '... our size is as we expect it to be');

# NOTE:
# it is (scalar(@_all_node_values) + 1) so that 
# we account for the root node which is not in 
# the list.

## ----------------------------------------------------------------------------
## test height
## ----------------------------------------------------------------------------    

cmp_ok($tree->height(), '==', 4, '... our height is as we expect it to be');

## ----------------------------------------------------------------------------
## test clone
## ----------------------------------------------------------------------------    

# clone the whole tree
my $tree_clone = $tree->clone();

my @all_cloned_node_values;
# collect all the cloned values
$tree_clone->traverse(sub {
    my ($_tree) = @_;
    push @all_cloned_node_values => $_tree->getNodeValue();
    });

# make sure that our cloned values equal to our control
ok eq_array(\@_all_node_values, \@all_cloned_node_values);
# and make sure they also match the original tree
ok eq_array(\@all_node_values, \@all_cloned_node_values);

# now change all the node values
$tree_clone->traverse(sub {
    my ($_tree) = @_;
    $_tree->setNodeValue("-> " . $_tree->getNodeValue());
    });

my @all_cloned_node_values_changed;
# collect them again    
$tree_clone->traverse(sub {
    my ($_tree) = @_;
    push @all_cloned_node_values_changed => $_tree->getNodeValue();
    });    

# make a copy of our control and cange it too    
my @_all_node_values_changed = map { "-> $_" } @_all_node_values;    

# now both our changed values should be correct
ok eq_array(\@_all_node_values_changed, \@all_cloned_node_values_changed);

my @all_node_values_check;
# now traverse the original tree again and make sure
# that the nodes are not changed
$tree->traverse(sub {
    my ($_tree) = @_;
    push @all_node_values_check => $_tree->getNodeValue();
    });

# this can be accomplished by checking them 
# against our control again
ok eq_array(\@_all_node_values, \@all_node_values_check);    
    
## ----------------------------------------------------------------------------
## end test for Tree::Simple
## ----------------------------------------------------------------------------    
