10_Tree_Simple_test.t [plain text]
use strict;
use warnings;
use Test::More tests => 292;
BEGIN {
use_ok('Tree::Simple');
};
can_ok("Tree::Simple", 'new');
can_ok("Tree::Simple", 'ROOT');
my $tree = Tree::Simple->new("root tree", Tree::Simple->ROOT);
isa_ok($tree, 'Tree::Simple');
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');
ok($tree->isRoot());
ok($tree->isLeaf());
is($tree->getNodeValue(), "root tree", '... this tree is a root');
cmp_ok($tree->getChildCount(), '==', 0, '... we have no children yet');
cmp_ok($tree->getDepth(), '==', -1, '... we have no depth yet');
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');
is("$tree", "Tree::Simple=HASH(" . $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');
isnt("$tree", "Tree::Simple=HASH(" . $tree->getUID() . ")", '... our UID is no longer derived from our hex address');
my $sub_tree = Tree::Simple->new("1.0");
isa_ok($sub_tree, 'Tree::Simple');
is($sub_tree->getNodeValue(), "1.0", '... this tree is 1.0');
ok($sub_tree->isRoot());
ok($sub_tree->isLeaf());
$tree->addChild($sub_tree);
ok(!$tree->isLeaf());
ok(!$sub_tree->isRoot());
cmp_ok($sub_tree->getDepth(), '==', 0, '... depth should be 0 now');
cmp_ok($sub_tree->getIndex(), '==', 0, '... index should be 0 now');
cmp_ok($tree->getChildCount(), '==', 1, '... we should have 1 children now');
is($tree->getChild(0), $sub_tree, '... make sure our sub_tree is fetchable');
my $sub_tree_parent = $sub_tree->getParent();
is($tree, $sub_tree_parent, '... make sure our sub_tree parent is tree');
my $sub_tree_2 = Tree::Simple->new("2.0");
isa_ok($sub_tree_2, 'Tree::Simple');
is($sub_tree_2->getNodeValue(), "2.0", '... this tree is 2.0');
ok($sub_tree_2->isRoot());
ok($sub_tree_2->isLeaf());
$sub_tree->addSibling($sub_tree_2);
ok(!$sub_tree_2->isRoot());
cmp_ok($sub_tree_2->getDepth(), '==', 0, '... depth should be 0 now');
cmp_ok($sub_tree_2->getIndex(), '==', 1, '... index should be 1');
cmp_ok($tree->getChildCount(), '==', 2, '... we should have 2 children now');
is($tree->getChild(1), $sub_tree_2, '... make sure our sub_tree is fetchable');
my $sub_tree_2_parent = $sub_tree_2->getParent();
is($tree, $sub_tree_2_parent, '... make sure our sub_tree_2 parent is tree');
my $sub_tree_4 = Tree::Simple->new("4.0", $tree);
is($sub_tree_4->getNodeValue(), "4.0", '... this tree is 4.0');
ok(!$sub_tree_4->isRoot());
cmp_ok($sub_tree_4->getDepth(), '==', 0, '... depth should be 0 now');
cmp_ok($sub_tree_4->getIndex(), '==', 2, '... index should be 2 now');
ok($sub_tree_4->isLeaf());
cmp_ok($tree->getChildCount(), '==', 3, '... we should have 3 children now');
is($tree->getChild(2), $sub_tree_4, '... make sure our sub_tree is fetchable');
is($tree, $sub_tree_4->getParent(), '... make sure our sub_tree_4 parent is tree');
my $sub_tree_3 = Tree::Simple->new("3.0");
is($sub_tree_3->getNodeValue(), "3.0", '... this tree is 3.0');
ok($sub_tree_3->isRoot());
ok($sub_tree_3->isLeaf());
$tree->insertChild(2, $sub_tree_3);
ok(!$sub_tree_3->isRoot());
cmp_ok($sub_tree_3->getDepth(), '==', 0, '... depth should be 0 now');
cmp_ok($sub_tree_3->getIndex(), '==', 2, '... index should be 2 now');
cmp_ok($sub_tree_4->getIndex(), '==', 3, '... index should be 3 now');
cmp_ok($tree->getChildCount(), '==', 4, '... we should have 4 children now');
is($tree->getChild(2), $sub_tree_3, '... make sure our sub_tree is fetchable');
is($tree->getChild(3), $sub_tree_4, '... make sure our sub_tree is fetchable');
is($tree, $sub_tree_3->getParent(), '... make sure our sub_tree_3 parent is tree');
my $children = $tree->getAllChildren();
ok eq_array($children, [ $sub_tree, $sub_tree_2, $sub_tree_3, $sub_tree_4 ]);
my @children = $tree->getAllChildren();
ok eq_array(\@children, [ $sub_tree, $sub_tree_2, $sub_tree_3, $sub_tree_4 ]);
ok eq_array($children, \@children);
foreach my $_sub_tree (@children) {
my $siblings = $sub_tree->getAllSiblings();
ok eq_array($children, $siblings);
my @siblings = $sub_tree->getAllSiblings();
ok eq_array($children, \@siblings);
}
my @sub_children = (
Tree::Simple->new("1.1"),
Tree::Simple->new("1.5"),
Tree::Simple->new("1.6")
);
foreach my $sub_child (@sub_children) {
ok($sub_child->isRoot());
ok($sub_child->isLeaf());
like($sub_child->getNodeValue(), qr/1\.[0-9]/, '... they at least have "1." followed by a digit');
cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');
}
$sub_tree->addChildren(@sub_children);
ok(!$sub_tree->isLeaf());
cmp_ok($sub_tree->getChildCount(), '==', 3, '... we should have 3 children now');
ok eq_array([ $sub_tree->getAllChildren() ], \@sub_children);
foreach my $sub_child (@sub_children) {
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($sub_tree, $sub_child->getParent(), '... their parent is the sub_tree');
cmp_ok($sub_child->getDepth(), '==', 1, '... depth should be 1');
ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}
my @more_sub_children = (
Tree::Simple->new("1.2"),
Tree::Simple->new("1.3"),
Tree::Simple->new("1.4")
);
foreach my $sub_child (@more_sub_children) {
ok($sub_child->isRoot());
ok($sub_child->isLeaf());
like($sub_child->getNodeValue(), qr/1\.[0-9]/, '... they at least have "1." followed by a digit');
cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');
}
$sub_tree->insertChildren(1, @more_sub_children);
cmp_ok($sub_tree->getChildCount(), '==', 6, '... we should have 6 children now');
ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_children[0], @more_sub_children, @sub_children[1 .. $#sub_children] ]);
foreach my $sub_child (@more_sub_children) {
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($sub_tree, $sub_child->getParent(), '... their parent is the sub_tree');
cmp_ok($sub_child->getDepth(), '==', 1, '... depth should be 1');
ok eq_array([ $sub_tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}
my @more_children = (
Tree::Simple->new("5.0"),
Tree::Simple->new("9.0")
);
foreach my $sub_child (@more_children) {
ok($sub_child->isRoot());
ok($sub_child->isLeaf());
like($sub_child->getNodeValue(), qr/[0-9]\.0/, '... they at least have digit followed by ".0"');
cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');
}
$sub_tree->addSiblings(@more_children);
cmp_ok($tree->getChildCount(), '==', 6, '... we should have 6 children now');
is($tree->getChild(4), $more_children[0], '... they are the same');
is($tree->getChild(5), $more_children[1], '... they are the same');
foreach my $sub_child (@more_children) {
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($tree, $sub_child->getParent(), '... their parent is the tree');
cmp_ok($sub_child->getDepth(), '==', 0, '... depth should be 0');
ok eq_array([ $tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}
my $new_sibling = Tree::Simple->new("8.0");
ok($new_sibling->isRoot());
ok($new_sibling->isLeaf());
is($new_sibling->getNodeValue(), "8.0", '... node value should be 6.0');
cmp_ok($new_sibling->getDepth(), '==', -1, '... depth should be -1');
$sub_tree->insertSibling(5, $new_sibling);
cmp_ok($tree->getChildCount(), '==', 7, '... we should have 7 children now');
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');
ok(!$new_sibling->isRoot());
ok($new_sibling->isLeaf());
is($tree, $new_sibling->getParent(), '... their parent is the tree');
cmp_ok($new_sibling->getDepth(), '==', 0, '... depth should be 0');
ok eq_array([ $tree->getAllChildren() ], [ $new_sibling->getAllSiblings() ]);
my @even_more_children = (
Tree::Simple->new("6.0"),
Tree::Simple->new("7.0")
);
foreach my $sub_child (@even_more_children) {
ok($sub_child->isRoot());
ok($sub_child->isLeaf());
like($sub_child->getNodeValue(), qr/[0-9]\.0/, '... they at least have digit followed by ".0"');
cmp_ok($sub_child->getDepth(), '==', -1, '... depth should be -1');
}
$sub_tree->insertSiblings(5, @even_more_children);
cmp_ok($tree->getChildCount(), '==', 9, '... we should have 6 children now');
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');
foreach my $sub_child (@even_more_children) {
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($tree, $sub_child->getParent(), '... their parent is the tree');
cmp_ok($sub_child->getDepth(), '==', 0, '... depth should be 0');
ok eq_array([ $tree->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}
is($tree->getChild($_), $sub_tree->getSibling($_), '... siblings are the same as children')
foreach (0 .. $tree->getChildCount());
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")
);
isa_ok($self_ref_tree_test, 'Tree::Simple');
ok(!$self_ref_tree_test->isRoot());
ok(!$self_ref_tree_test->isLeaf());
is($sub_tree_3, $self_ref_tree_test->getParent(), '... should be the same');
cmp_ok($sub_tree_3->getChildCount(), '==', 1, '... we should have 1 child here');
cmp_ok($self_ref_tree_test->getChildCount(), '==', 2, '... we should have 2 children here');
foreach my $sub_child ($self_ref_tree_test->getAllChildren()) {
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($self_ref_tree_test, $sub_child->getParent(), '... their parent is the tree');
cmp_ok($sub_child->getDepth(), '==', 2, '... depth should be 0');
ok eq_array([ $self_ref_tree_test->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
}
my $self_ref_tree_test_2 = Tree::Simple->new("2.1", $sub_tree_2)
->addChild(
Tree::Simple->new("2.1.1")
);
isa_ok($self_ref_tree_test_2, 'Tree::Simple');
ok(!$self_ref_tree_test_2->isRoot());
ok(!$self_ref_tree_test_2->isLeaf());
is($sub_tree_2, $self_ref_tree_test_2->getParent(), '... should be the same');
cmp_ok($sub_tree_2->getChildCount(), '==', 1, '... we should have 1 child here');
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);
ok(!$sub_child->isRoot());
ok($sub_child->isLeaf());
is($self_ref_tree_test_2, $sub_child->getParent(), '... their parent is the tree');
cmp_ok($sub_child->getDepth(), '==', 2, '... depth should be 0');
ok eq_array([ $self_ref_tree_test_2->getAllChildren() ], [ $sub_child->getAllSiblings() ]);
my $sub_tree_of_tree_to_remove = Tree::Simple->new("1.1.a.1");
my $tree_to_remove = Tree::Simple->new("1.1.a")->addChild($sub_tree_of_tree_to_remove);
ok($tree_to_remove->isRoot());
cmp_ok($tree_to_remove->getDepth(), '==', -1, '... the depth should be -1');
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 0, '... the depth should be 0');
$sub_tree->insertChild(1, $tree_to_remove);
ok(!$tree_to_remove->isRoot());
cmp_ok($tree_to_remove->getDepth(), '==', 1, '... the depth should be 1');
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 2, '... the depth should be 2');
is($sub_tree->getChild(1), $tree_to_remove, '... these tree should be equal');
my $removed_tree = $sub_tree->removeChildAt(1);
is($removed_tree, $tree_to_remove, '... these tree should be equal');
ok($tree_to_remove->isRoot());
cmp_ok($tree_to_remove->getDepth(), '==', -1, '... the depth should be -1');
cmp_ok($sub_tree_of_tree_to_remove->getDepth(), '==', 0, '... the depth should be 0');
my $sub_tree_of_tree_to_remove2 = Tree::Simple->new("1.1.a.1");
my $tree_to_remove2 = Tree::Simple->new("1.1.a")->addChild($sub_tree_of_tree_to_remove2);
ok($tree_to_remove2->isRoot());
cmp_ok($tree_to_remove2->getDepth(), '==', -1, '... the depth should be -1');
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 0, '... the depth should be 0');
$sub_tree->insertChild(1, $tree_to_remove2);
ok(!$tree_to_remove2->isRoot());
cmp_ok($tree_to_remove2->getDepth(), '==', 1, '... the depth should be 1');
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 2, '... the depth should be 2');
is($sub_tree->getChild(1), $tree_to_remove2, '... these tree should be equal');
my $removed_tree2 = $sub_tree->removeChild($tree_to_remove2);
is($removed_tree2, $tree_to_remove2, '... these tree should be equal');
ok($tree_to_remove2->isRoot());
cmp_ok($tree_to_remove2->getDepth(), '==', -1, '... the depth should be -1');
cmp_ok($sub_tree_of_tree_to_remove2->getDepth(), '==', 0, '... the depth should be 0');
my $tree_to_remove3 = Tree::Simple->new("1.1.a");
ok($tree_to_remove3->isRoot());
cmp_ok($tree_to_remove3->getDepth(), '==', -1, '... the depth should be -1');
$sub_tree->insertChild(1, $tree_to_remove3);
ok(!$tree_to_remove3->isRoot());
cmp_ok($tree_to_remove3->getDepth(), '==', 1, '... the depth should be 1');
is($sub_tree->getChild(1), $tree_to_remove3, '... these tree should be equal');
my $removed_tree3 = $sub_tree->removeChild(1);
is($removed_tree3, $tree_to_remove3, '... these tree should be equal');
ok($tree_to_remove3->isRoot());
cmp_ok($tree_to_remove3->getDepth(), '==', -1, '... the depth should be -1');
my $tree_to_remove_2 = Tree::Simple->new("1.7");
$sub_tree->addChild($tree_to_remove_2);
is($sub_tree->getChild($sub_tree->getChildCount() - 1), $tree_to_remove_2, '... these tree should be equal');
my $removed_tree_2 = $sub_tree->removeChildAt($sub_tree->getChildCount() - 1);
is($removed_tree_2, $tree_to_remove_2, '... these tree should be equal');
my $tree_to_remove_3 = Tree::Simple->new("1.1.-1");
$sub_tree->insertChild(0, $tree_to_remove_3);
is($sub_tree->getChild(0), $tree_to_remove_3, '... these tree should be equal');
my $removed_tree_3 = $sub_tree->removeChildAt(0);
is($removed_tree_3, $tree_to_remove_3, '... these tree should be equal');
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;
$tree->traverse(sub {
my ($_tree) = @_;
push @all_node_values => $_tree->getNodeValue();
});
is_deeply(\@_all_node_values, \@all_node_values, '... our nodes match our control nodes');
my @_all_node_values_post_traverse = qw(
1.0
1.1
1.1
1.2
1.2
1.3
1.3
1.4
1.4
1.5
1.5
1.6
1.6
1.0
2.0
2.1
2.1.1
2.1.1
2.1
2.0
3.0
3.1
3.1.1
3.1.1
3.1.2
3.1.2
3.1
3.0
4.0
4.0
5.0
5.0
6.0
6.0
7.0
7.0
8.0
8.0
9.0
9.0
);
my @all_node_values_post_traverse;
$tree->traverse(sub {
my ($_tree) = @_;
push @all_node_values_post_traverse => $_tree->getNodeValue();
},
sub {
my ($_tree) = @_;
push @all_node_values_post_traverse => $_tree->getNodeValue();
}
);
is_deeply(\@_all_node_values_post_traverse, \@all_node_values_post_traverse,
'... our nodes match our control nodes for post traverse method');
cmp_ok($tree->size(), '==', (scalar(@_all_node_values) + 1), '... our size is as we expect it to be');
cmp_ok($tree->height(), '==', 4, '... our height is as we expect it to be');
my $tree_clone = $tree->clone();
my @all_cloned_node_values;
$tree_clone->traverse(sub {
my ($_tree) = @_;
push @all_cloned_node_values => $_tree->getNodeValue();
});
ok eq_array(\@_all_node_values, \@all_cloned_node_values);
ok eq_array(\@all_node_values, \@all_cloned_node_values);
$tree_clone->traverse(sub {
my ($_tree) = @_;
$_tree->setNodeValue("-> " . $_tree->getNodeValue());
});
my @all_cloned_node_values_changed;
$tree_clone->traverse(sub {
my ($_tree) = @_;
push @all_cloned_node_values_changed => $_tree->getNodeValue();
});
my @_all_node_values_changed = map { "-> $_" } @_all_node_values;
ok eq_array(\@_all_node_values_changed, \@all_cloned_node_values_changed);
my @all_node_values_check;
$tree->traverse(sub {
my ($_tree) = @_;
push @all_node_values_check => $_tree->getNodeValue();
});
ok eq_array(\@_all_node_values, \@all_node_values_check);