File Coverage

blib/lib/Test/Role/TinyCommons/Tree.pm
Criterion Covered Total %
statement 258 258 100.0
branch 11 16 68.7
condition 8 13 61.5
subroutine 9 9 100.0
pod 1 1 100.0
total 287 297 96.6


line stmt bran cond sub pod time code
1             package Test::Role::TinyCommons::Tree;
2              
3 4     4   223886 use strict;
  4         34  
  4         125  
4 4     4   23 use warnings;
  4         9  
  4         105  
5 4     4   1869 use Test::Exception;
  4         13555  
  4         17  
6 4     4   1100 use Test::More 0.98;
  4         78  
  4         31  
7              
8 4     4   1063 use Exporter qw(import);
  4         10  
  4         10543  
9              
10             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
11             our $DATE = '2021-10-07'; # DATE
12             our $DIST = 'RoleBundle-TinyCommons-Tree'; # DIST
13             our $VERSION = '0.129'; # VERSION
14              
15             our @EXPORT_OK = qw(test_role_tinycommons_tree);
16              
17             sub test_role_tinycommons_tree {
18 2     2 1 230 my %args = @_;
19              
20 2         9 my $c = $args{class};
21 2         5 my $c1 = $args{subclass1};
22 2         6 my $c2 = $args{subclass2};
23              
24 2   50     15 my $a1 = $args{attribute1} || 'id';
25              
26 2   50     13 my $m = $args{constructor_name} || 'new';
27              
28             subtest "Tree::Node" => sub {
29 2     2   3099 my $pnode = $c->new;
30 2         1434 my $mode1 = $c->new;
31 2         41 my $mode2 = $c->new;
32             lives_ok {
33 2         99 $mode1->parent($pnode);
34 2         16 $mode2->parent($pnode);
35 2         16 $pnode->children([$mode1, $mode2]);
36 2         42 } "set parent & children";
37 2         1104 is_deeply($mode1->parent, $pnode, "get parent (1)");
38 2         1417 is_deeply($mode2->parent, $pnode, "get parent (1)");
39 2         1259 my @children = $pnode->children;
40 2 100 66     28 @children = @{$children[0]}
  1         4  
41             if @children==1 && ref($children[0]) eq 'ARRAY';
42 2         11 is_deeply(\@children, [$mode1, $mode2], "get children");
43 2         26 };
44              
45             subtest "Tree::FromStruct" => sub {
46 2     2   1730 my $tree;
47              
48             my $struct = {
49             ( _instantiate => $args{code_instantiate} ) x
50             !!$args{code_instantiate},
51 2         35 _pass_attributes => 0,
52             _constructor => $m,
53              
54             $a1 => 0, _children => [
55             {$a1 => 1, _children => [
56             {$a1 => 3},
57             {$a1 => 4, _class=>$c2},
58             {$a1 => 5, _class=>$c2},
59             {$a1 => 6, _class=>$c1},
60             {$a1 => 7},
61             ]},
62             {$a1 => 2, _children => [
63             {$a1 => 8, _class => $c2, _children => [
64             {$a1 => 9, _class => $c1},
65             ]},
66             ]},
67             ],
68             };
69              
70 2         19 $tree = $c->new_from_struct($struct);
71              
72 2         5 my $exp_tree = do {
73 2         23 my $n0 = $c ->$m; $n0->$a1(0);
  2         31  
74              
75 2         26 my $n1 = $c ->$m; $n1->$a1(1); $n1->parent($n0);
  2         29  
  2         12  
76 2         65 my $n2 = $c ->$m; $n2->$a1(2); $n2->parent($n0);
  2         47  
  2         53  
77 2         13 $n0->children([$n1, $n2]);
78              
79 2         31 my $n3 = $c ->$m; $n3->$a1(3); $n3->parent($n1);
  2         29  
  2         12  
80 2         23 my $n4 = $c2->$m; $n4->$a1(4); $n4->parent($n1);
  2         29  
  2         13  
81 2         23 my $n5 = $c2->$m; $n5->$a1(5); $n5->parent($n1);
  2         30  
  2         11  
82 2         24 my $n6 = $c1->$m; $n6->$a1(6); $n6->parent($n1);
  2         30  
  2         11  
83 2         23 my $n7 = $c ->$m; $n7->$a1(7); $n7->parent($n1);
  2         28  
  2         11  
84 2         12 $n1->children([$n3, $n4, $n5, $n6, $n7]);
85              
86 2         24 my $n8 = $c2->$m; $n8->$a1(8); $n8->parent($n2);
  2         30  
  2         11  
87 2         11 $n2->children([$n8]);
88              
89 2         28 my $n9 = $c1->$m; $n9->$a1(9); $n9->parent($n8);
  2         29  
  2         11  
90 2         12 $n8->children([$n9]);
91              
92 2         11 $n0;
93             };
94              
95 2 50       11 is_deeply($tree, $exp_tree, "result") or diag explain $tree;
96              
97 2         10326 $tree =
98             Code::Includable::Tree::FromStruct::new_from_struct($c, $struct);
99              
100 2         10 is_deeply($tree, $exp_tree, "result (sub call)");
101              
102 2 50       5133 } if $args{test_fromstruct};
103              
104             subtest "Tree::NodeMethods" => sub {
105 2     2   1691 my ($n0, $n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9);
106              
107             BUILD:
108             {
109 2         6 $n0 = $c ->$m; $n0->$a1(0);
  2         38  
  2         41  
110              
111 2         29 $n1 = $c ->$m; $n1->$a1(1); $n1->parent($n0);
  2         29  
  2         13  
112 2         26 $n2 = $c ->$m; $n2->$a1(2); $n2->parent($n0);
  2         28  
  2         12  
113 2         11 $n0->children([$n1, $n2]);
114              
115 2         31 $n3 = $c ->$m; $n3->$a1(3); $n3->parent($n1);
  2         29  
  2         14  
116 2         26 $n4 = $c2->$m; $n4->$a1(4); $n4->parent($n1);
  2         32  
  2         10  
117 2         24 $n5 = $c2->$m; $n5->$a1(5); $n5->parent($n1);
  2         29  
  2         12  
118 2         24 $n6 = $c1->$m; $n6->$a1(6); $n6->parent($n1);
  2         29  
  2         11  
119 2         25 $n7 = $c ->$m; $n7->$a1(7); $n7->parent($n1);
  2         28  
  2         17  
120 2         12 $n1->children([$n3, $n4, $n5, $n6, $n7]);
121              
122 2         55 $n8 = $c2->$m; $n8->$a1(8); $n8->parent($n2);
  2         34  
  2         12  
123 2         12 $n2->children([$n8]);
124              
125 2         30 $n9 = $c1->$m; $n9->$a1(9); $n9->parent($n8);
  2         29  
  2         13  
126 2         11 $n8->children([$n9]);
127              
128             # structure:
129             # 0 (c)
130             # 1 (c)
131             # 3 (c)
132             # 4 (c2)
133             # 5 (c2)
134             # 6 (c1)
135             # 7 (c)
136             # 2 (c)
137             # 8 (c2)
138             # 9 (c1)
139             }
140              
141 2         31 is_deeply([$n9->ancestors],
142             [$n8, $n2, $n0],
143             "ancestors (1)");
144 2         2171 is_deeply([Code::Includable::Tree::NodeMethods::ancestors($n9)],
145             [$n8, $n2, $n0],
146             "ancestors (1) (sub call)");
147 2         2114 is_deeply([$n0->ancestors],
148             [],
149             "ancestors (2)");
150 2         1357 is_deeply([Code::Includable::Tree::NodeMethods::ancestors($n0)],
151             [],
152             "ancestors (2) (sub call)");
153              
154 2         1240 is_deeply([$n9->retrieve_parent],
155             [$n8],
156             "retrieve_parent (1)");
157 2         1554 ok( $n1->retrieve_parent, "retrieve_parent [1]");
158             # XXX more
159              
160 2         807 is_deeply([$n0->descendants],
161             [$n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9],
162             "descendants");
163 2         3741 is_deeply([Code::Includable::Tree::NodeMethods::descendants($n0)],
164             [$n1, $n2, $n3, $n4, $n5, $n6, $n7, $n8, $n9],
165             "descendants (sub call)");
166              
167 2         3610 is_deeply([$n0->descendants_depth_first],
168             [$n1, $n3, $n4, $n5, $n6, $n7, $n2, $n8, $n9],
169             "descendants_depth_first");
170 2         3691 is_deeply([Code::Includable::Tree::NodeMethods::descendants_depth_first($n0)],
171             [$n1, $n3, $n4, $n5, $n6, $n7, $n2, $n8, $n9],
172             "descendants_depth_first (sub call)");
173              
174             # XXX test walk
175              
176 2         3646 is_deeply($n0->first_node(sub { $_[0]->id == 5 }),
  10         34  
177             $n5, "first_node");
178 2         1360 is_deeply(Code::Includable::Tree::NodeMethods::first_node($n0, sub { $_[0]->id == 5 }),
  10         34  
179             $n5, "first_node (sub call)");
180              
181 2         1305 ok( $n1->is_first_child, "is_first_child [1]");
182 2         836 ok(!$n2->is_first_child, "is_first_child [2]");
183 2         809 ok(!$n0->is_first_child, "is_first_child [3]");
184 2         808 ok( Code::Includable::Tree::NodeMethods::is_first_child($n1), "is_first_child [1] (sub call)");
185 2         825 ok(!Code::Includable::Tree::NodeMethods::is_first_child($n2), "is_first_child [2] (sub call)");
186 2         763 ok(!Code::Includable::Tree::NodeMethods::is_first_child($n0), "is_first_child [3] (sub call)");
187              
188 2         804 ok(!$n1->is_last_child, "is_last_child [1]");
189 2         867 ok( $n2->is_last_child, "is_last_child [2]");
190 2         758 ok(!$n0->is_last_child, "is_last_child [3]");
191 2         785 ok(!Code::Includable::Tree::NodeMethods::is_last_child($n1), "is_last_child [1] (sub call)");
192 2         803 ok( Code::Includable::Tree::NodeMethods::is_last_child($n2), "is_last_child [2] (sub call)");
193 2         782 ok(!Code::Includable::Tree::NodeMethods::is_last_child($n0), "is_last_child [3] (sub call)");
194              
195 2         776 ok(!$n1->is_only_child, "is_only_child [1]");
196 2         790 ok( $n8->is_only_child, "is_only_child [2]");
197 2         756 ok(!$n0->is_only_child, "is_only_child [3]");
198 2         792 ok(!Code::Includable::Tree::NodeMethods::is_only_child($n1), "is_only_child [1] (sub call)");
199 2         778 ok( Code::Includable::Tree::NodeMethods::is_only_child($n8), "is_only_child [2] (sub call)");
200 2         841 ok(!Code::Includable::Tree::NodeMethods::is_only_child($n0), "is_only_child [3] (sub call)");
201              
202 2         778 ok( $n1 ->is_nth_child(1), "is_nth_child [1]");
203 2         799 ok(!$n1 ->is_nth_child(2), "is_nth_child [2]");
204 2         802 ok( $n2 ->is_nth_child(2), "is_nth_child [3]");
205 2         798 ok( Code::Includable::Tree::NodeMethods::is_nth_child($n1, 1), "is_nth_child [1] (sub call)");
206 2         779 ok(!Code::Includable::Tree::NodeMethods::is_nth_child($n1, 2), "is_nth_child [2] (sub call)");
207 2         755 ok( Code::Includable::Tree::NodeMethods::is_nth_child($n2, 2), "is_nth_child [3] (sub call)");
208              
209 2         803 ok(!$n1 ->is_nth_last_child(1), "is_nth_last_child [1]");
210 2         793 ok( $n1 ->is_nth_last_child(2), "is_nth_last_child [2]");
211 2         782 ok(!$n2 ->is_nth_last_child(2), "is_nth_last_child [3]");
212 2         780 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child($n1, 1), "is_nth_last_child [1] (sub call)");
213 2         756 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child($n1, 2), "is_nth_last_child [2] (sub call)");
214 2         865 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child($n2, 2), "is_nth_last_child [3] (sub call)");
215              
216 2         763 ok( $n3 ->is_first_child_of_type, "is_first_child_of_type [1]");
217 2         838 ok( $n4 ->is_first_child_of_type, "is_first_child_of_type [2]");
218 2         824 ok(!$n5 ->is_first_child_of_type, "is_first_child_of_type [3]");
219 2         827 ok( $n6 ->is_first_child_of_type, "is_first_child_of_type [4]");
220 2         765 ok(!$n7 ->is_first_child_of_type, "is_first_child_of_type [4]");
221 2         773 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n3), "is_first_child_of_type [1] (sub call)");
222 2         840 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n4), "is_first_child_of_type [2] (sub call)");
223 2         794 ok(!Code::Includable::Tree::NodeMethods::is_first_child_of_type($n5), "is_first_child_of_type [3] (sub call)");
224 2         776 ok( Code::Includable::Tree::NodeMethods::is_first_child_of_type($n6), "is_first_child_of_type [4] (sub call)");
225 2         777 ok(!Code::Includable::Tree::NodeMethods::is_first_child_of_type($n7), "is_first_child_of_type [4] (sub call)");
226              
227 2         780 ok(!$n3 ->is_last_child_of_type, "is_last_child_of_type [1]");
228 2         866 ok(!$n4 ->is_last_child_of_type, "is_last_child_of_type [2]");
229 2         778 ok( $n5 ->is_last_child_of_type, "is_last_child_of_type [3]");
230 2         807 ok( $n6 ->is_last_child_of_type, "is_last_child_of_type [4]");
231 2         756 ok( $n7 ->is_last_child_of_type, "is_last_child_of_type [5]");
232 2         805 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n3), "is_last_child_of_type [1] (sub call)");
233 2         765 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n4), "is_last_child_of_type [2] (sub call)");
234 2         779 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n5), "is_last_child_of_type [3] (sub call)");
235 2         807 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n6), "is_last_child_of_type [4] (sub call)");
236 2         794 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n7), "is_last_child_of_type [5] (sub call)");
237              
238 2         769 ok(!$n3 ->is_last_child_of_type, "is_last_child_of_type [1]");
239 2         808 ok(!$n4 ->is_last_child_of_type, "is_last_child_of_type [2]");
240 2         756 ok( $n5 ->is_last_child_of_type, "is_last_child_of_type [3]");
241 2         858 ok( $n6 ->is_last_child_of_type, "is_last_child_of_type [4]");
242 2         756 ok( $n7 ->is_last_child_of_type, "is_last_child_of_type [5]");
243 2         818 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n3), "is_last_child_of_type [1] (sub call)");
244 2         793 ok(!Code::Includable::Tree::NodeMethods::is_last_child_of_type($n4), "is_last_child_of_type [2] (sub call)");
245 2         820 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n5), "is_last_child_of_type [3] (sub call)");
246 2         811 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n6), "is_last_child_of_type [4] (sub call)");
247 2         780 ok( Code::Includable::Tree::NodeMethods::is_last_child_of_type($n7), "is_last_child_of_type [5] (sub call)");
248              
249 2         780 ok( $n3 ->is_nth_child_of_type(1), "is_nth_child_of_type [1]");
250 2         809 ok(!$n3 ->is_nth_child_of_type(2), "is_nth_child_of_type [2]");
251 2         768 ok( $n4 ->is_nth_child_of_type(1), "is_nth_child_of_type [3]");
252 2         805 ok(!$n4 ->is_nth_child_of_type(2), "is_nth_child_of_type [4]");
253 2         833 ok( Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n3, 1), "is_nth_child_of_type [1] (sub call)");
254 2         816 ok(!Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n3, 2), "is_nth_child_of_type [2] (sub call)");
255 2         774 ok( Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n4, 1), "is_nth_child_of_type [3] (sub call)");
256 2         753 ok(!Code::Includable::Tree::NodeMethods::is_nth_child_of_type($n4, 2), "is_nth_child_of_type [4] (sub call)");
257              
258 2         800 ok(!$n3 ->is_nth_last_child_of_type(1), "is_nth_last_child_of_type [1]");
259 2         838 ok( $n3 ->is_nth_last_child_of_type(2), "is_nth_last_child_of_type [2]");
260 2         792 ok(!$n4 ->is_nth_last_child_of_type(1), "is_nth_last_child_of_type [3]");
261 2         773 ok( $n4 ->is_nth_last_child_of_type(2), "is_nth_last_child_of_type [4]");
262 2         837 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n3, 1), "is_nth_last_child_of_type [1] (sub call)");
263 2         778 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n3, 2), "is_nth_last_child_of_type [2] (sub call)");
264 2         768 ok(!Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n4, 1), "is_nth_last_child_of_type [3] (sub call)");
265 2         756 ok( Code::Includable::Tree::NodeMethods::is_nth_last_child_of_type($n4, 2), "is_nth_last_child_of_type [4] (sub call)");
266              
267 2         782 ok(!$n3 ->is_only_child_of_type, "is_only_child_of_type [1]");
268 2         832 ok( $n6 ->is_only_child_of_type, "is_only_child_of_type [2]");
269 2         760 ok(!Code::Includable::Tree::NodeMethods::is_only_child_of_type($n3), "is_only_child_of_type [1]");
270 2         781 ok( Code::Includable::Tree::NodeMethods::is_only_child_of_type($n6), "is_only_child_of_type [2]");
271              
272 2         784 is_deeply($n3->prev_sibling, undef, "prev_sibling [1]");
273 2         1063 is_deeply($n5->prev_sibling, $n4 , "prev_sibling [2]");
274 2         1382 is_deeply($n7->prev_sibling, $n6 , "prev_sibling [3]");
275 2         1247 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n3), undef, "prev_sibling [1] (sub call)");
276 2         1020 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n5), $n4 , "prev_sibling [2] (sub call)");
277 2         1246 is_deeply(Code::Includable::Tree::NodeMethods::prev_sibling($n7), $n6 , "prev_sibling [3] (sub call)");
278              
279 2         1275 is_deeply($n3->next_sibling, $n4 , "next_sibling [1]");
280 2         1340 is_deeply($n5->next_sibling, $n6 , "next_sibling [2]");
281 2         1486 is_deeply($n7->next_sibling, undef, "next_sibling [3]");
282 2         1002 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n3), $n4 , "next_sibling [1] (sub call)");
283 2         1297 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n5), $n6 , "next_sibling [2] (sub call)");
284 2         1314 is_deeply(Code::Includable::Tree::NodeMethods::next_sibling($n7), undef, "next_sibling [3] (sub call)");
285              
286 2         993 is_deeply([$n3->prev_siblings], [] , "prev_siblings [1] (sub call)");
287 2         1354 is_deeply([$n5->prev_siblings], [$n3, $n4], "prev_siblings [2] (sub call)");
288 2         1856 is_deeply([Code::Includable::Tree::NodeMethods::prev_siblings($n3)], [] , "prev_siblings [1] (sub call)");
289 2         1281 is_deeply([Code::Includable::Tree::NodeMethods::prev_siblings($n5)], [$n3, $n4], "prev_siblings [2] (sub call)");
290              
291 2         1784 is_deeply([$n5->next_siblings], [$n6, $n7], "next_siblings [1] (sub call)");
292 2         1871 is_deeply([$n7->next_siblings], [] , "next_siblings [2] (sub call)");
293 2         1222 is_deeply([Code::Includable::Tree::NodeMethods::next_siblings($n5)], [$n6, $n7], "next_siblings [1] (sub call)");
294 2         1858 is_deeply([Code::Includable::Tree::NodeMethods::next_siblings($n7)], [] , "next_siblings [2] (sub call)");
295              
296 2         1238 ok( $n0->is_root, "is_root [0]");
297 2         822 ok(!$n1->is_root, "is_root [1]");
298              
299             # check
300             {
301 2         25 lives_ok { $n0->check({check_root=>1}) };
  2         100  
302              
303 2         882 $n3->parent($n2);
304 2         22 lives_ok { $n0->check };
  2         65  
305 2         784 dies_ok { $n1->check };
  2         66  
306 2         774 dies_ok { $n1->check({recurse=>1}) };
  2         67  
307 2         896 $n3->parent($n1);
308              
309             # opt:check_root=1
310 2         13 $n0->parent($n0);
311 2         19 dies_ok { $n0->check({check_root => 1}) };
  2         79  
312 2         814 $n0->parent(undef);
313             }
314              
315             # remove
316             {
317 2         768 my @children;
  2         10  
  2         7  
318              
319 2         13 Code::Includable::Tree::NodeMethods::remove($n8);
320 2         16 @children = $n2->children;
321 2 100 66     34 if (@children == 1 && ref $children[0] eq 'ARRAY') { @children = @{ $children[0] } }
  1         4  
  1         3  
322 2 50       11 is_deeply(\@children, [])
323             or diag explain \@children;
324              
325 2         1303 Code::Includable::Tree::NodeMethods::remove($n6);
326 2         20 @children = $n1->children;
327 2 100 66     21 if (@children == 1 && ref $children[0] eq 'ARRAY') { @children = @{ $children[0] } }
  1         2  
  1         3  
328 2 50       10 is_deeply(\@children, [$n3, $n4, $n5, $n7])
329             or diag explain \@children;
330             }
331              
332 2 50       12821 } if $args{test_nodemethods};
333             }
334              
335             1;
336             # ABSTRACT: Test suite for Role::TinyCommons::Tree
337              
338             __END__