File Coverage

blib/lib/Test/Role/TinyCommons/Tree.pm
Criterion Covered Total %
statement 258 258 100.0
branch 9 16 56.2
condition 6 13 46.1
subroutine 9 9 100.0
pod 1 1 100.0
total 283 297 95.2


line stmt bran cond sub pod time code
1             package Test::Role::TinyCommons::Tree;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2021-07-02'; # DATE
5             our $DIST = 'Role-TinyCommons-Tree'; # DIST
6             our $VERSION = '0.127'; # VERSION
7              
8 4     4   181168 use strict;
  4         34  
  4         109  
9 4     4   18 use warnings;
  4         7  
  4         107  
10 4     4   1721 use Test::Exception;
  4         11413  
  4         14  
11 4     4   1103 use Test::More 0.98;
  4         61  
  4         24  
12              
13 4     4   855 use Exporter qw(import);
  4         9  
  4         9029  
14             our @EXPORT_OK = qw(test_role_tinycommons_tree);
15              
16             sub test_role_tinycommons_tree {
17 2     2 1 190 my %args = @_;
18              
19 2         7 my $c = $args{class};
20 2         5 my $c1 = $args{subclass1};
21 2         4 my $c2 = $args{subclass2};
22              
23 2   50     21 my $a1 = $args{attribute1} || 'id';
24              
25 2   50     9 my $m = $args{constructor_name} || 'new';
26              
27             subtest "Tree::Node" => sub {
28 2     2   2010 my $pnode = $c->new;
29 2         1369 my $mode1 = $c->new;
30 2         38 my $mode2 = $c->new;
31             lives_ok {
32 2         81 $mode1->parent($pnode);
33 2         14 $mode2->parent($pnode);
34 2         13 $pnode->children([$mode1, $mode2]);
35 2         49 } "set parent & children";
36 2         906 is_deeply($mode1->parent, $pnode, "get parent (1)");
37 2         1191 is_deeply($mode2->parent, $pnode, "get parent (1)");
38 2         1053 my @children = $pnode->children;
39 2 50 33     24 @children = @{$children[0]}
  2         6  
40             if @children==1 && ref($children[0]) eq 'ARRAY';
41 2         8 is_deeply(\@children, [$mode1, $mode2], "get children");
42 2         19 };
43              
44             subtest "Tree::FromStruct" => sub {
45 2     2   1371 my $tree;
46              
47             my $struct = {
48             ( _instantiate => $args{code_instantiate} ) x
49             !!$args{code_instantiate},
50 2         28 _pass_attributes => 0,
51             _constructor => $m,
52              
53             $a1 => 0, _children => [
54             {$a1 => 1, _children => [
55             {$a1 => 3},
56             {$a1 => 4, _class=>$c2},
57             {$a1 => 5, _class=>$c2},
58             {$a1 => 6, _class=>$c1},
59             {$a1 => 7},
60             ]},
61             {$a1 => 2, _children => [
62             {$a1 => 8, _class => $c2, _children => [
63             {$a1 => 9, _class => $c1},
64             ]},
65             ]},
66             ],
67             };
68              
69 2         15 $tree = $c->new_from_struct($struct);
70              
71 2         4 my $exp_tree = do {
72 2         23 my $n0 = $c ->$m; $n0->$a1(0);
  2         74  
73              
74 2         27 my $n1 = $c ->$m; $n1->$a1(1); $n1->parent($n0);
  2         28  
  2         11  
75 2         23 my $n2 = $c ->$m; $n2->$a1(2); $n2->parent($n0);
  2         26  
  2         11  
76 2         10 $n0->children([$n1, $n2]);
77              
78 2         39 my $n3 = $c ->$m; $n3->$a1(3); $n3->parent($n1);
  2         35  
  2         12  
79 2         26 my $n4 = $c2->$m; $n4->$a1(4); $n4->parent($n1);
  2         28  
  2         36  
80 2         60 my $n5 = $c2->$m; $n5->$a1(5); $n5->parent($n1);
  2         32  
  2         10  
81 2         26 my $n6 = $c1->$m; $n6->$a1(6); $n6->parent($n1);
  2         28  
  2         22  
82 2         34 my $n7 = $c ->$m; $n7->$a1(7); $n7->parent($n1);
  2         42  
  2         10  
83 2         10 $n1->children([$n3, $n4, $n5, $n6, $n7]);
84              
85 2         27 my $n8 = $c2->$m; $n8->$a1(8); $n8->parent($n2);
  2         27  
  2         22  
86 2         11 $n2->children([$n8]);
87              
88 2         24 my $n9 = $c1->$m; $n9->$a1(9); $n9->parent($n8);
  2         25  
  2         8  
89 2         9 $n8->children([$n9]);
90              
91 2         8 $n0;
92             };
93              
94 2 50       7 is_deeply($tree, $exp_tree, "result") or diag explain $tree;
95              
96 2         8765 $tree =
97             Code::Includable::Tree::FromStruct::new_from_struct($c, $struct);
98              
99 2         8 is_deeply($tree, $exp_tree, "result (sub call)");
100              
101 2 50       4124 } if $args{test_fromstruct};
102              
103             subtest "Tree::NodeMethods" => sub {
104 2     2   1349 my ($n0, $n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9);
105              
106             BUILD:
107             {
108 2         4 $n0 = $c ->$m; $n0->$a1(0);
  2         32  
  2         34  
109              
110 2         24 $n1 = $c ->$m; $n1->$a1(1); $n1->parent($n0);
  2         26  
  2         12  
111 2         22 $n2 = $c ->$m; $n2->$a1(2); $n2->parent($n0);
  2         29  
  2         10  
112 2         9 $n0->children([$n1, $n2]);
113              
114 2         40 $n3 = $c ->$m; $n3->$a1(3); $n3->parent($n1);
  2         25  
  2         8  
115 2         23 $n4 = $c2->$m; $n4->$a1(4); $n4->parent($n1);
  2         28  
  2         9  
116 2         21 $n5 = $c2->$m; $n5->$a1(5); $n5->parent($n1);
  2         27  
  2         8  
117 2         23 $n6 = $c1->$m; $n6->$a1(6); $n6->parent($n1);
  2         25  
  2         8  
118 2         22 $n7 = $c ->$m; $n7->$a1(7); $n7->parent($n1);
  2         37  
  2         13  
119 2         13 $n1->children([$n3, $n4, $n5, $n6, $n7]);
120              
121 2         31 $n8 = $c2->$m; $n8->$a1(8); $n8->parent($n2);
  2         47  
  2         10  
122 2         15 $n2->children([$n8]);
123              
124 2         29 $n9 = $c1->$m; $n9->$a1(9); $n9->parent($n8);
  2         29  
  2         10  
125 2         19 $n8->children([$n9]);
126              
127             # structure:
128             # 0 (c)
129             # 1 (c)
130             # 3 (c)
131             # 4 (c2)
132             # 5 (c2)
133             # 6 (c1)
134             # 7 (c)
135             # 2 (c)
136             # 8 (c2)
137             # 9 (c1)
138             }
139              
140 2         34 is_deeply([$n9->ancestors],
141             [$n8, $n2, $n0],
142             "ancestors (1)");
143 2         1858 is_deeply([Code::Includable::Tree::NodeMethods::ancestors($n9)],
144             [$n8, $n2, $n0],
145             "ancestors (1) (sub call)");
146 2         2136 is_deeply([$n0->ancestors],
147             [],
148             "ancestors (2)");
149 2         1046 is_deeply([Code::Includable::Tree::NodeMethods::ancestors($n0)],
150             [],
151             "ancestors (2) (sub call)");
152              
153 2         1071 is_deeply([$n9->retrieve_parent],
154             [$n8],
155             "retrieve_parent (1)");
156 2         1332 ok( $n1->retrieve_parent, "retrieve_parent [1]");
157             # XXX more
158              
159 2         640 is_deeply([$n0->descendants],
160             [$n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9],
161             "descendants");
162 2         3298 is_deeply([Code::Includable::Tree::NodeMethods::descendants($n0)],
163             [$n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9],
164             "descendants (sub call)");
165              
166 2         3134 is_deeply([$n0->descendants_depth_first],
167             [$n1, $n3, $n4, $n5, $n6, $n7, $n2, $n8, $n9],
168             "descendants_depth_first");
169 2         3297 is_deeply([Code::Includable::Tree::NodeMethods::descendants_depth_first($n0)],
170             [$n1, $n3, $n4, $n5, $n6, $n7, $n2, $n8, $n9],
171             "descendants_depth_first (sub call)");
172              
173             # XXX test walk
174              
175 2         3134 is_deeply($n0->first_node(sub { $_[0]->id == 5 }),
  10         33  
176             $n5, "first_node");
177 2         1169 is_deeply(Code::Includable::Tree::NodeMethods::first_node($n0, sub { $_[0]->id == 5 }),
  10         29  
178             $n5, "first_node (sub call)");
179              
180 2         1064 ok( $n1->is_first_child, "is_first_child [1]");
181 2         658 ok(!$n2->is_first_child, "is_first_child [2]");
182 2         669 ok(!$n0->is_first_child, "is_first_child [3]");
183 2         683 ok( Code::Includable::Tree::NodeMethods::is_first_child($n1), "is_first_child [1] (sub call)");
184 2         633 ok(!Code::Includable::Tree::NodeMethods::is_first_child($n2), "is_first_child [2] (sub call)");
185 2         640 ok(!Code::Includable::Tree::NodeMethods::is_first_child($n0), "is_first_child [3] (sub call)");
186              
187 2         642 ok(!$n1->is_last_child, "is_last_child [1]");
188 2         713 ok( $n2->is_last_child, "is_last_child [2]");
189 2         624 ok(!$n0->is_last_child, "is_last_child [3]");
190 2         592 ok(!Code::Includable::Tree::NodeMethods::is_last_child($n1), "is_last_child [1] (sub call)");
191 2         597 ok( Code::Includable::Tree::NodeMethods::is_last_child($n2), "is_last_child [2] (sub call)");
192 2         654 ok(!Code::Includable::Tree::NodeMethods::is_last_child($n0), "is_last_child [3] (sub call)");
193              
194 2         647 ok(!$n1->is_only_child, "is_only_child [1]");
195 2         631 ok( $n8->is_only_child, "is_only_child [2]");
196 2         641 ok(!$n0->is_only_child, "is_only_child [3]");
197 2         605 ok(!Code::Includable::Tree::NodeMethods::is_only_child($n1), "is_only_child [1] (sub call)");
198 2         692 ok( Code::Includable::Tree::NodeMethods::is_only_child($n8), "is_only_child [2] (sub call)");
199 2         660 ok(!Code::Includable::Tree::NodeMethods::is_only_child($n0), "is_only_child [3] (sub call)");
200              
201 2         616 ok( $n1 ->is_nth_child(1), "is_nth_child [1]");
202 2         663 ok(!$n1 ->is_nth_child(2), "is_nth_child [2]");
203 2         652 ok( $n2 ->is_nth_child(2), "is_nth_child [3]");
204 2         631 ok( Code::Includable::Tree::NodeMethods::is_nth_child($n1, 1), "is_nth_child [1] (sub call)");
205 2         630 ok(!Code::Includable::Tree::NodeMethods::is_nth_child($n1, 2), "is_nth_child [2] (sub call)");
206 2         654 ok( Code::Includable::Tree::NodeMethods::is_nth_child($n2, 2), "is_nth_child [3] (sub call)");
207              
208 2         618 ok(!$n1 ->is_nth_last_child(1), "is_nth_last_child [1]");
209 2         636 ok( $n1 ->is_nth_last_child(2), "is_nth_last_child [2]");
210 2         633 ok(!$n2 ->is_nth_last_child(2), "is_nth_last_child [3]");
211 2         648 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child($n1, 1), "is_nth_last_child [1] (sub call)");
212 2         691 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child($n1, 2), "is_nth_last_child [2] (sub call)");
213 2         637 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child($n2, 2), "is_nth_last_child [3] (sub call)");
214              
215 2         651 ok( $n3 ->is_first_child_of_type, "is_first_child_of_type [1]");
216 2         693 ok( $n4 ->is_first_child_of_type, "is_first_child_of_type [2]");
217 2         627 ok(!$n5 ->is_first_child_of_type, "is_first_child_of_type [3]");
218 2         625 ok( $n6 ->is_first_child_of_type, "is_first_child_of_type [4]");
219 2         630 ok(!$n7 ->is_first_child_of_type, "is_first_child_of_type [4]");
220 2         699 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n3), "is_first_child_of_type [1] (sub call)");
221 2         656 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n4), "is_first_child_of_type [2] (sub call)");
222 2         661 ok(!Code::Includable::Tree::NodeMethods::is_first_child_of_type($n5), "is_first_child_of_type [3] (sub call)");
223 2         624 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n6), "is_first_child_of_type [4] (sub call)");
224 2         635 ok(!Code::Includable::Tree::NodeMethods::is_first_child_of_type($n7), "is_first_child_of_type [4] (sub call)");
225              
226 2         670 ok(!$n3 ->is_last_child_of_type, "is_last_child_of_type [1]");
227 2         647 ok(!$n4 ->is_last_child_of_type, "is_last_child_of_type [2]");
228 2         644 ok( $n5 ->is_last_child_of_type, "is_last_child_of_type [3]");
229 2         614 ok( $n6 ->is_last_child_of_type, "is_last_child_of_type [4]");
230 2         637 ok( $n7 ->is_last_child_of_type, "is_last_child_of_type [5]");
231 2         624 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n3), "is_last_child_of_type [1] (sub call)");
232 2         630 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n4), "is_last_child_of_type [2] (sub call)");
233 2         639 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n5), "is_last_child_of_type [3] (sub call)");
234 2         607 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n6), "is_last_child_of_type [4] (sub call)");
235 2         636 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n7), "is_last_child_of_type [5] (sub call)");
236              
237 2         640 ok(!$n3 ->is_last_child_of_type, "is_last_child_of_type [1]");
238 2         656 ok(!$n4 ->is_last_child_of_type, "is_last_child_of_type [2]");
239 2         616 ok( $n5 ->is_last_child_of_type, "is_last_child_of_type [3]");
240 2         640 ok( $n6 ->is_last_child_of_type, "is_last_child_of_type [4]");
241 2         618 ok( $n7 ->is_last_child_of_type, "is_last_child_of_type [5]");
242 2         621 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n3), "is_last_child_of_type [1] (sub call)");
243 2         633 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n4), "is_last_child_of_type [2] (sub call)");
244 2         657 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n5), "is_last_child_of_type [3] (sub call)");
245 2         628 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n6), "is_last_child_of_type [4] (sub call)");
246 2         641 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n7), "is_last_child_of_type [5] (sub call)");
247              
248 2         645 ok( $n3 ->is_nth_child_of_type(1), "is_nth_child_of_type [1]");
249 2         607 ok(!$n3 ->is_nth_child_of_type(2), "is_nth_child_of_type [2]");
250 2         618 ok( $n4 ->is_nth_child_of_type(1), "is_nth_child_of_type [3]");
251 2         655 ok(!$n4 ->is_nth_child_of_type(2), "is_nth_child_of_type [4]");
252 2         657 ok( Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n3, 1), "is_nth_child_of_type [1] (sub call)");
253 2         604 ok(!Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n3, 2), "is_nth_child_of_type [2] (sub call)");
254 2         642 ok( Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n4, 1), "is_nth_child_of_type [3] (sub call)");
255 2         670 ok(!Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n4, 2), "is_nth_child_of_type [4] (sub call)");
256              
257 2         625 ok(!$n3 ->is_nth_last_child_of_type(1), "is_nth_last_child_of_type [1]");
258 2         647 ok( $n3 ->is_nth_last_child_of_type(2), "is_nth_last_child_of_type [2]");
259 2         632 ok(!$n4 ->is_nth_last_child_of_type(1), "is_nth_last_child_of_type [3]");
260 2         645 ok( $n4 ->is_nth_last_child_of_type(2), "is_nth_last_child_of_type [4]");
261 2         649 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n3, 1), "is_nth_last_child_of_type [1] (sub call)");
262 2         659 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n3, 2), "is_nth_last_child_of_type [2] (sub call)");
263 2         625 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n4, 1), "is_nth_last_child_of_type [3] (sub call)");
264 2         670 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n4, 2), "is_nth_last_child_of_type [4] (sub call)");
265              
266 2         610 ok(!$n3 ->is_only_child_of_type, "is_only_child_of_type [1]");
267 2         678 ok( $n6 ->is_only_child_of_type, "is_only_child_of_type [2]");
268 2         646 ok(!Code::Includable::Tree::NodeMethods::is_only_child_of_type($n3), "is_only_child_of_type [1]");
269 2         609 ok( Code::Includable::Tree::NodeMethods::is_only_child_of_type($n6), "is_only_child_of_type [2]");
270              
271 2         638 is_deeply($n3->prev_sibling, undef, "prev_sibling [1]");
272 2         843 is_deeply($n5->prev_sibling, $n4 , "prev_sibling [2]");
273 2         1140 is_deeply($n7->prev_sibling, $n6 , "prev_sibling [3]");
274 2         1068 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n3), undef, "prev_sibling [1] (sub call)");
275 2         819 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n5), $n4 , "prev_sibling [2] (sub call)");
276 2         1088 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n7), $n6 , "prev_sibling [3] (sub call)");
277              
278 2         1047 is_deeply($n3->next_sibling, $n4 , "next_sibling [1]");
279 2         1136 is_deeply($n5->next_sibling, $n6 , "next_sibling [2]");
280 2         1062 is_deeply($n7->next_sibling, undef, "next_sibling [3]");
281 2         793 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n3), $n4 , "next_sibling [1] (sub call)");
282 2         1092 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n5), $n6 , "next_sibling [2] (sub call)");
283 2         1119 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n7), undef, "next_sibling [3] (sub call)");
284              
285 2         842 is_deeply([$n3->prev_siblings], [] , "prev_siblings [1] (sub call)");
286 2         1075 is_deeply([$n5->prev_siblings], [$n3, $n4], "prev_siblings [2] (sub call)");
287 2         1545 is_deeply([Code::Includable::Tree::NodeMethods::prev_siblings($n3)], [] , "prev_siblings [1] (sub call)");
288 2         1013 is_deeply([Code::Includable::Tree::NodeMethods::prev_siblings($n5)], [$n3, $n4], "prev_siblings [2] (sub call)");
289              
290 2         1590 is_deeply([$n5->next_siblings], [$n6, $n7], "next_siblings [1] (sub call)");
291 2         1535 is_deeply([$n7->next_siblings], [] , "next_siblings [2] (sub call)");
292 2         1005 is_deeply([Code::Includable::Tree::NodeMethods::next_siblings($n5)], [$n6, $n7], "next_siblings [1] (sub call)");
293 2         1563 is_deeply([Code::Includable::Tree::NodeMethods::next_siblings($n7)], [] , "next_siblings [2] (sub call)");
294              
295 2         1001 ok( $n0->is_root, "is_root [0]");
296 2         688 ok(!$n1->is_root, "is_root [1]");
297              
298             # check
299             {
300 2         21 lives_ok { $n0->check({check_root=>1}) };
  2         90  
301              
302 2         675 $n3->parent($n2);
303 2         19 lives_ok { $n0->check };
  2         55  
304 2         681 dies_ok { $n1->check };
  2         60  
305 2         628 dies_ok { $n1->check({recurse=>1}) };
  2         60  
306 2         625 $n3->parent($n1);
307              
308             # opt:check_root=1
309 2         12 $n0->parent($n0);
310 2         17 dies_ok { $n0->check({check_root => 1}) };
  2         67  
311 2         641 $n0->parent(undef);
312             }
313              
314             # remove
315             {
316 2         661 my @children;
  2         11  
  2         4  
317              
318 2         12 Code::Includable::Tree::NodeMethods::remove($n8);
319 2         26 @children = $n2->children;
320 2 50 33     27 if (@children == 1 && ref $children[0] eq 'ARRAY') { @children = @{ $children[0] } }
  2         6  
  2         5  
321 2 50       9 is_deeply(\@children, [])
322             or diag explain \@children;
323              
324 2         1088 Code::Includable::Tree::NodeMethods::remove($n6);
325 2         14 @children = $n1->children;
326 2 100 66     20 if (@children == 1 && ref $children[0] eq 'ARRAY') { @children = @{ $children[0] } }
  1         2  
  1         3  
327 2 50       9 is_deeply(\@children, [$n3, $n4, $n5, $n7])
328             or diag explain \@children;
329             }
330              
331 2 50       10720 } if $args{test_nodemethods};
332             }
333              
334             1;
335             # ABSTRACT: Test suite for Role::TinyCommons::Tree
336              
337             __END__