1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6use Test::More;
7
8eval "use Test::Memory::Cycle 1.02";
9plan skip_all => "Test::Memory::Cycle required for testing memory leaks" if $@;
10
11plan tests => 51;
12
13use_ok('Tree::Simple');
14
15#diag "parental connections must be destroyed manually";
16
17{ #diag "verify the problem exists";
18
19    my $tree2 = Tree::Simple->new("2");
20    ok($tree2->isRoot(), '... tree2 is a ROOT');    
21    my $tree1_UID;
22    {
23        my $tree1 = Tree::Simple->new("1");
24        $tree1_UID = $tree1->getUID();
25        $tree1->addChild($tree2);
26        ok(!$tree2->isRoot(), '... now tree2 is not a ROOT');
27
28        memory_cycle_exists($tree2, '... there is a cycle in tree2');
29    }
30    
31    memory_cycle_exists($tree2, '... tree1 is still connected with tree2');
32    ok(!$tree2->isRoot(), '... now tree2 is not a ROOT');
33    ok(defined($tree2->getParent()), '... now tree2s parent is still defined');    
34    is($tree2->getParent()->getUID(), $tree1_UID, '... and tree2s parent is tree1');        
35
36}
37
38{ #diag "this fixes the problem";
39
40    my $tree2 = Tree::Simple->new("2");
41    ok($tree2->isRoot(), '... tree2 is a ROOT');    
42    
43    {
44        my $tree1 = Tree::Simple->new("1");
45        $tree1->addChild($tree2);
46        ok(!$tree2->isRoot(), '... now tree2 is not a ROOT');
47
48        memory_cycle_exists($tree2, '... there is a cycle in tree2');
49        $tree1->DESTROY();
50    }
51    
52    memory_cycle_ok($tree2, '... calling DESTORY on tree1 broke the connection with tree2');
53    ok($tree2->isRoot(), '... now tree2 is a ROOT again');
54    ok(!defined($tree2->getParent()), '... now tree2s parent is no longer defined');    
55}
56
57#diag "expand the original problem and see how it effects children";
58
59{ 
60
61    my $tree2 = Tree::Simple->new("2");
62    ok($tree2->isRoot(), '... tree2 is a ROOT');  
63    ok($tree2->isLeaf(), '... tree2 is a Leaf');      
64    my $tree3 = Tree::Simple->new("3");  
65    ok($tree3->isRoot(), '... tree3 is a ROOT');  
66    ok($tree3->isLeaf(), '... tree3 is a Leaf'); 
67    
68    {
69        my $tree1 = Tree::Simple->new("1");
70        $tree1->addChild($tree2);
71        ok(!$tree2->isRoot(), '... now tree2 is not a ROOT');
72        $tree2->addChild($tree3);
73        ok(!$tree2->isLeaf(), '... now tree2 is not a Leaf');
74        ok(!$tree3->isRoot(), '... tree3 is no longer a ROOT');  
75        ok($tree3->isLeaf(), '... but tree3 is still a Leaf'); 
76
77        memory_cycle_exists($tree1, '... there is a cycle in tree1');
78        memory_cycle_exists($tree2, '... there is a cycle in tree2');
79        memory_cycle_exists($tree3, '... there is a cycle in tree3');        
80        $tree1->DESTROY();
81
82        memory_cycle_exists($tree1, '... there is still a cycle in tree1 because of the children');
83    }
84    
85    memory_cycle_exists($tree2, '... calling DESTORY on tree1 broke the connection with tree2');
86    ok($tree2->isRoot(), '... now tree2 is a ROOT again');
87    ok(!$tree2->isLeaf(), '... now tree2 is not a leaf again');    
88    ok(!defined($tree2->getParent()), '... now tree2s parent is no longer defined');    
89    cmp_ok($tree2->getChildCount(), '==', 1, '... now tree2 has one child');    
90    memory_cycle_exists($tree3, '... calling DESTORY on tree1 did not break the connection betwee tree2 and tree3');
91    ok(!$tree3->isRoot(), '... now tree3 is not a ROOT');
92    ok($tree3->isLeaf(), '... now tree3 is still a leaf');    
93    ok(defined($tree3->getParent()), '... now tree3s parent is still defined'); 
94    is($tree3->getParent(), $tree2, '... now tree3s parent is still tree2');           
95}
96
97#diag "child connections are strong";
98{
99    my $tree1 = Tree::Simple->new("1");
100    my $tree2_UID;
101
102    {
103        my $tree2 = Tree::Simple->new("2");    
104        $tree1->addChild($tree2);
105        $tree2_UID = $tree2->getUID();
106        
107        memory_cycle_exists($tree1, '... tree1 is connected to tree2');
108        memory_cycle_exists($tree2, '... tree2 is connected to tree1');    
109        
110        $tree2->DESTROY(); # this doesn't make sense to do
111    }
112
113    memory_cycle_exists($tree1, '... tree2 is still connected to tree1 because child connections are strong');
114    is($tree1->getChild(0)->getUID(), $tree2_UID, '... tree2 is still connected to tree1');
115    is($tree1->getChild(0)->getParent(), $tree1, '... tree2s parent is tree1');
116    cmp_ok($tree1->getChildCount(), '==', 1, '... tree1 has a child count of 1');        
117}
118
119#diag "expand upon this issue";
120{
121    my $tree1 = Tree::Simple->new("1");
122    my $tree2_UID;
123    my $tree3 = Tree::Simple->new("3");    
124
125    {
126        my $tree2 = Tree::Simple->new("2");    
127        $tree1->addChild($tree2);
128        $tree2_UID = $tree2->getUID();
129        $tree2->addChild($tree3);
130        
131        memory_cycle_exists($tree1, '... tree1 is connected to tree2');
132        memory_cycle_exists($tree2, '... tree2 is connected to tree1');    
133        memory_cycle_exists($tree3, '... tree3 is connected to tree2');            
134        
135        $tree2->DESTROY(); # this doesn't make sense to do
136    }
137
138    memory_cycle_exists($tree1, '... tree2 is still connected to tree1 because child connections are strong');
139    is($tree1->getChild(0)->getUID(), $tree2_UID, '... tree2 is still connected to tree1');
140    is($tree1->getChild(0)->getParent(), $tree1, '... tree2s parent is tree1');
141    cmp_ok($tree1->getChildCount(), '==', 1, '... tree1 has a child count of 1');        
142    cmp_ok($tree1->getChild(0)->getChildCount(), '==', 1, '... tree2 is still connected to tree3');
143    is($tree1->getChild(0)->getChild(0), $tree3, '... tree2 is still connected to tree3');    
144}
145