1# Test file from PPIx::Utilities::Node
2
3use strict;
4use warnings;
5
6use Data::Dumper qw< >;
7use PPI::Document qw< >;
8use PPI::Dumper qw< >;
9use PPIx::Utils::Traversal qw< split_ppi_node_by_namespace >;
10
11use Test::More;
12
13my $DUMP_INDENT = 4;
14
15{
16    my $source = <<'END_SOURCE';
17package Foo;
18$x = 1;
19while (1) { $y = 2 }
20until (1) { $z = 3 }
21if (1) { $w = 4 }
22unless (1) { $v = 5 }
23for (1) { $u = 6 }
24foreach (1) { $t = 7 }
25given (1) { $s = 8 }
26when (1) { $r = 9 }
27END_SOURCE
28
29    my %expected = (
30        Foo => [ <<'END_EXPECTED' ],
31                    PPI::Document
32                        PPI::Statement::Package
33[    1,   1,   1 ]         PPI::Token::Word     'package'
34[    1,   8,   8 ]         PPI::Token::Whitespace   ' '
35[    1,   9,   9 ]         PPI::Token::Word     'Foo'
36[    1,  12,  12 ]         PPI::Token::Structure    ';'
37[    1,  13,  13 ]     PPI::Token::Whitespace   '\n'
38                        PPI::Statement
39[    2,   1,   1 ]         PPI::Token::Symbol   '$x'
40[    2,   3,   3 ]         PPI::Token::Whitespace   ' '
41[    2,   4,   4 ]         PPI::Token::Operator     '='
42[    2,   5,   5 ]         PPI::Token::Whitespace   ' '
43[    2,   6,   6 ]         PPI::Token::Number   '1'
44[    2,   7,   7 ]         PPI::Token::Structure    ';'
45[    2,   8,   8 ]     PPI::Token::Whitespace   '\n'
46                        PPI::Statement::Compound
47[    3,   1,   1 ]         PPI::Token::Word     'while'
48[    3,   6,   6 ]         PPI::Token::Whitespace   ' '
49                            PPI::Structure::Condition   ( ... )
50                                PPI::Statement::Expression
51[    3,   8,   8 ]                 PPI::Token::Number   '1'
52[    3,  10,  10 ]         PPI::Token::Whitespace   ' '
53                            PPI::Structure::Block   { ... }
54[    3,  12,  12 ]             PPI::Token::Whitespace   ' '
55                                PPI::Statement
56[    3,  13,  13 ]                 PPI::Token::Symbol   '$y'
57[    3,  15,  15 ]                 PPI::Token::Whitespace   ' '
58[    3,  16,  16 ]                 PPI::Token::Operator     '='
59[    3,  17,  17 ]                 PPI::Token::Whitespace   ' '
60[    3,  18,  18 ]                 PPI::Token::Number   '2'
61[    3,  19,  19 ]             PPI::Token::Whitespace   ' '
62[    3,  21,  21 ]     PPI::Token::Whitespace   '\n'
63                        PPI::Statement::Compound
64[    4,   1,   1 ]         PPI::Token::Word     'until'
65[    4,   6,   6 ]         PPI::Token::Whitespace   ' '
66                            PPI::Structure::Condition   ( ... )
67                                PPI::Statement::Expression
68[    4,   8,   8 ]                 PPI::Token::Number   '1'
69[    4,  10,  10 ]         PPI::Token::Whitespace   ' '
70                            PPI::Structure::Block   { ... }
71[    4,  12,  12 ]             PPI::Token::Whitespace   ' '
72                                PPI::Statement
73[    4,  13,  13 ]                 PPI::Token::Symbol   '$z'
74[    4,  15,  15 ]                 PPI::Token::Whitespace   ' '
75[    4,  16,  16 ]                 PPI::Token::Operator     '='
76[    4,  17,  17 ]                 PPI::Token::Whitespace   ' '
77[    4,  18,  18 ]                 PPI::Token::Number   '3'
78[    4,  19,  19 ]             PPI::Token::Whitespace   ' '
79[    4,  21,  21 ]     PPI::Token::Whitespace   '\n'
80                        PPI::Statement::Compound
81[    5,   1,   1 ]         PPI::Token::Word     'if'
82[    5,   3,   3 ]         PPI::Token::Whitespace   ' '
83                            PPI::Structure::Condition   ( ... )
84                                PPI::Statement::Expression
85[    5,   5,   5 ]                 PPI::Token::Number   '1'
86[    5,   7,   7 ]         PPI::Token::Whitespace   ' '
87                            PPI::Structure::Block   { ... }
88[    5,   9,   9 ]             PPI::Token::Whitespace   ' '
89                                PPI::Statement
90[    5,  10,  10 ]                 PPI::Token::Symbol   '$w'
91[    5,  12,  12 ]                 PPI::Token::Whitespace   ' '
92[    5,  13,  13 ]                 PPI::Token::Operator     '='
93[    5,  14,  14 ]                 PPI::Token::Whitespace   ' '
94[    5,  15,  15 ]                 PPI::Token::Number   '4'
95[    5,  16,  16 ]             PPI::Token::Whitespace   ' '
96[    5,  18,  18 ]     PPI::Token::Whitespace   '\n'
97                        PPI::Statement::Compound
98[    6,   1,   1 ]         PPI::Token::Word     'unless'
99[    6,   7,   7 ]         PPI::Token::Whitespace   ' '
100                            PPI::Structure::Condition   ( ... )
101                                PPI::Statement::Expression
102[    6,   9,   9 ]                 PPI::Token::Number   '1'
103[    6,  11,  11 ]         PPI::Token::Whitespace   ' '
104                            PPI::Structure::Block   { ... }
105[    6,  13,  13 ]             PPI::Token::Whitespace   ' '
106                                PPI::Statement
107[    6,  14,  14 ]                 PPI::Token::Symbol   '$v'
108[    6,  16,  16 ]                 PPI::Token::Whitespace   ' '
109[    6,  17,  17 ]                 PPI::Token::Operator     '='
110[    6,  18,  18 ]                 PPI::Token::Whitespace   ' '
111[    6,  19,  19 ]                 PPI::Token::Number   '5'
112[    6,  20,  20 ]             PPI::Token::Whitespace   ' '
113[    6,  22,  22 ]     PPI::Token::Whitespace   '\n'
114                        PPI::Statement::Compound
115[    7,   1,   1 ]         PPI::Token::Word     'for'
116[    7,   4,   4 ]         PPI::Token::Whitespace   ' '
117                            PPI::Structure::List    ( ... )
118                                PPI::Statement
119[    7,   6,   6 ]                 PPI::Token::Number   '1'
120[    7,   8,   8 ]         PPI::Token::Whitespace   ' '
121                            PPI::Structure::Block   { ... }
122[    7,  10,  10 ]             PPI::Token::Whitespace   ' '
123                                PPI::Statement
124[    7,  11,  11 ]                 PPI::Token::Symbol   '$u'
125[    7,  13,  13 ]                 PPI::Token::Whitespace   ' '
126[    7,  14,  14 ]                 PPI::Token::Operator     '='
127[    7,  15,  15 ]                 PPI::Token::Whitespace   ' '
128[    7,  16,  16 ]                 PPI::Token::Number   '6'
129[    7,  17,  17 ]             PPI::Token::Whitespace   ' '
130[    7,  19,  19 ]     PPI::Token::Whitespace   '\n'
131                        PPI::Statement::Compound
132[    8,   1,   1 ]         PPI::Token::Word     'foreach'
133[    8,   8,   8 ]         PPI::Token::Whitespace   ' '
134                            PPI::Structure::List    ( ... )
135                                PPI::Statement
136[    8,  10,  10 ]                 PPI::Token::Number   '1'
137[    8,  12,  12 ]         PPI::Token::Whitespace   ' '
138                            PPI::Structure::Block   { ... }
139[    8,  14,  14 ]             PPI::Token::Whitespace   ' '
140                                PPI::Statement
141[    8,  15,  15 ]                 PPI::Token::Symbol   '$t'
142[    8,  17,  17 ]                 PPI::Token::Whitespace   ' '
143[    8,  18,  18 ]                 PPI::Token::Operator     '='
144[    8,  19,  19 ]                 PPI::Token::Whitespace   ' '
145[    8,  20,  20 ]                 PPI::Token::Number   '7'
146[    8,  21,  21 ]             PPI::Token::Whitespace   ' '
147[    8,  23,  23 ]     PPI::Token::Whitespace   '\n'
148                        PPI::Statement::Given
149[    9,   1,   1 ]         PPI::Token::Word     'given'
150[    9,   6,   6 ]         PPI::Token::Whitespace   ' '
151                            PPI::Structure::Given   ( ... )
152                                PPI::Statement::Expression
153[    9,   8,   8 ]                 PPI::Token::Number   '1'
154[    9,  10,  10 ]         PPI::Token::Whitespace   ' '
155                            PPI::Structure::Block   { ... }
156[    9,  12,  12 ]             PPI::Token::Whitespace   ' '
157                                PPI::Statement
158[    9,  13,  13 ]                 PPI::Token::Symbol   '$s'
159[    9,  15,  15 ]                 PPI::Token::Whitespace   ' '
160[    9,  16,  16 ]                 PPI::Token::Operator     '='
161[    9,  17,  17 ]                 PPI::Token::Whitespace   ' '
162[    9,  18,  18 ]                 PPI::Token::Number   '8'
163[    9,  19,  19 ]             PPI::Token::Whitespace   ' '
164[    9,  21,  21 ]     PPI::Token::Whitespace   '\n'
165                        PPI::Statement::When
166[   10,   1,   1 ]         PPI::Token::Word     'when'
167[   10,   5,   5 ]         PPI::Token::Whitespace   ' '
168                            PPI::Structure::When    ( ... )
169                                PPI::Statement::Expression
170[   10,   7,   7 ]                 PPI::Token::Number   '1'
171[   10,   9,   9 ]         PPI::Token::Whitespace   ' '
172                            PPI::Structure::Block   { ... }
173[   10,  11,  11 ]             PPI::Token::Whitespace   ' '
174                                PPI::Statement
175[   10,  12,  12 ]                 PPI::Token::Symbol   '$r'
176[   10,  14,  14 ]                 PPI::Token::Whitespace   ' '
177[   10,  15,  15 ]                 PPI::Token::Operator     '='
178[   10,  16,  16 ]                 PPI::Token::Whitespace   ' '
179[   10,  17,  17 ]                 PPI::Token::Number   '9'
180[   10,  18,  18 ]             PPI::Token::Whitespace   ' '
181[   10,  20,  20 ]     PPI::Token::Whitespace   '\n'
182END_EXPECTED
183    );
184
185    _test($source, \%expected, 'Single namespace.');
186}
187
188
189{
190    my $source = <<'END_SOURCE';
191$x = 1;
192END_SOURCE
193
194    my %expected = (
195        main => [ <<'END_EXPECTED' ],
196                    PPI::Document
197                        PPI::Statement
198[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
199[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
200[    1,   4,   4 ]         PPI::Token::Operator     '='
201[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
202[    1,   6,   6 ]         PPI::Token::Number   '1'
203[    1,   7,   7 ]         PPI::Token::Structure    ';'
204[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
205END_EXPECTED
206    );
207
208    _test($source, \%expected, 'Default namespace.');
209}
210
211
212{
213    my $source = <<'END_SOURCE';
214$x = 1;
215
216package Foo;
217
218$y = 2;
219END_SOURCE
220
221    my %expected = (
222        main => [ <<'END_EXPECTED_MAIN' ],
223                    PPI::Document::Fragment
224                        PPI::Statement
225[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
226[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
227[    1,   4,   4 ]         PPI::Token::Operator     '='
228[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
229[    1,   6,   6 ]         PPI::Token::Number   '1'
230[    1,   7,   7 ]         PPI::Token::Structure    ';'
231[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
232[    2,   1,   1 ]     PPI::Token::Whitespace   '\n'
233END_EXPECTED_MAIN
234
235        Foo => [ <<'END_EXPECTED_FOO' ],
236                    PPI::Document::Fragment
237                        PPI::Statement::Package
238[    3,   1,   1 ]         PPI::Token::Word     'package'
239[    3,   8,   8 ]         PPI::Token::Whitespace   ' '
240[    3,   9,   9 ]         PPI::Token::Word     'Foo'
241[    3,  12,  12 ]         PPI::Token::Structure    ';'
242[    3,  13,  13 ]     PPI::Token::Whitespace   '\n'
243[    4,   1,   1 ]     PPI::Token::Whitespace   '\n'
244                        PPI::Statement
245[    5,   1,   1 ]         PPI::Token::Symbol   '$y'
246[    5,   3,   3 ]         PPI::Token::Whitespace   ' '
247[    5,   4,   4 ]         PPI::Token::Operator     '='
248[    5,   5,   5 ]         PPI::Token::Whitespace   ' '
249[    5,   6,   6 ]         PPI::Token::Number   '2'
250[    5,   7,   7 ]         PPI::Token::Structure    ';'
251[    5,   8,   8 ]     PPI::Token::Whitespace   '\n'
252END_EXPECTED_FOO
253    );
254
255    _test($source, \%expected, 'Simple multiple namespaces: default followed by non-default.');
256}
257
258
259{
260    my $source = <<'END_SOURCE';
261package Foo;
262$x = 1;
263
264package main;
265
266$y = 2;
267END_SOURCE
268
269    my %expected = (
270        main => [ <<'END_EXPECTED_MAIN' ],
271                    PPI::Document::Fragment
272                        PPI::Statement::Package
273[    4,   1,   1 ]         PPI::Token::Word     'package'
274[    4,   8,   8 ]         PPI::Token::Whitespace   ' '
275[    4,   9,   9 ]         PPI::Token::Word     'main'
276[    4,  13,  13 ]         PPI::Token::Structure    ';'
277[    4,  14,  14 ]     PPI::Token::Whitespace   '\n'
278[    5,   1,   1 ]     PPI::Token::Whitespace   '\n'
279                        PPI::Statement
280[    6,   1,   1 ]         PPI::Token::Symbol   '$y'
281[    6,   3,   3 ]         PPI::Token::Whitespace   ' '
282[    6,   4,   4 ]         PPI::Token::Operator     '='
283[    6,   5,   5 ]         PPI::Token::Whitespace   ' '
284[    6,   6,   6 ]         PPI::Token::Number   '2'
285[    6,   7,   7 ]         PPI::Token::Structure    ';'
286[    6,   8,   8 ]     PPI::Token::Whitespace   '\n'
287END_EXPECTED_MAIN
288
289        Foo => [ <<'END_EXPECTED_FOO' ],
290                    PPI::Document::Fragment
291                        PPI::Statement::Package
292[    1,   1,   1 ]         PPI::Token::Word     'package'
293[    1,   8,   8 ]         PPI::Token::Whitespace   ' '
294[    1,   9,   9 ]         PPI::Token::Word     'Foo'
295[    1,  12,  12 ]         PPI::Token::Structure    ';'
296[    1,  13,  13 ]     PPI::Token::Whitespace   '\n'
297                        PPI::Statement
298[    2,   1,   1 ]         PPI::Token::Symbol   '$x'
299[    2,   3,   3 ]         PPI::Token::Whitespace   ' '
300[    2,   4,   4 ]         PPI::Token::Operator     '='
301[    2,   5,   5 ]         PPI::Token::Whitespace   ' '
302[    2,   6,   6 ]         PPI::Token::Number   '1'
303[    2,   7,   7 ]         PPI::Token::Structure    ';'
304[    2,   8,   8 ]     PPI::Token::Whitespace   '\n'
305[    3,   1,   1 ]     PPI::Token::Whitespace   '\n'
306END_EXPECTED_FOO
307    );
308
309    _test($source, \%expected, 'Simple multiple namespaces: non-default followed by default.');
310}
311
312
313{
314    my $source = <<'END_SOURCE';
315$x = 1;
316package Foo;
317$y = 2;
318package main;
319$z = 3;
320package Foo;
321$w = 4;
322package main;
323$v = 5;
324END_SOURCE
325
326    my %expected = (
327        main => [ <<'END_EXPECTED_MAIN' ],
328                    PPI::Document::Fragment
329                        PPI::Statement
330[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
331[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
332[    1,   4,   4 ]         PPI::Token::Operator     '='
333[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
334[    1,   6,   6 ]         PPI::Token::Number   '1'
335[    1,   7,   7 ]         PPI::Token::Structure    ';'
336[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
337                        PPI::Statement::Package
338[    4,   1,   1 ]         PPI::Token::Word     'package'
339[    4,   8,   8 ]         PPI::Token::Whitespace   ' '
340[    4,   9,   9 ]         PPI::Token::Word     'main'
341[    4,  13,  13 ]         PPI::Token::Structure    ';'
342[    4,  14,  14 ]     PPI::Token::Whitespace   '\n'
343                        PPI::Statement
344[    5,   1,   1 ]         PPI::Token::Symbol   '$z'
345[    5,   3,   3 ]         PPI::Token::Whitespace   ' '
346[    5,   4,   4 ]         PPI::Token::Operator     '='
347[    5,   5,   5 ]         PPI::Token::Whitespace   ' '
348[    5,   6,   6 ]         PPI::Token::Number   '3'
349[    5,   7,   7 ]         PPI::Token::Structure    ';'
350[    5,   8,   8 ]     PPI::Token::Whitespace   '\n'
351                        PPI::Statement::Package
352[    8,   1,   1 ]         PPI::Token::Word     'package'
353[    8,   8,   8 ]         PPI::Token::Whitespace   ' '
354[    8,   9,   9 ]         PPI::Token::Word     'main'
355[    8,  13,  13 ]         PPI::Token::Structure    ';'
356[    8,  14,  14 ]     PPI::Token::Whitespace   '\n'
357                        PPI::Statement
358[    9,   1,   1 ]         PPI::Token::Symbol   '$v'
359[    9,   3,   3 ]         PPI::Token::Whitespace   ' '
360[    9,   4,   4 ]         PPI::Token::Operator     '='
361[    9,   5,   5 ]         PPI::Token::Whitespace   ' '
362[    9,   6,   6 ]         PPI::Token::Number   '5'
363[    9,   7,   7 ]         PPI::Token::Structure    ';'
364[    9,   8,   8 ]     PPI::Token::Whitespace   '\n'
365END_EXPECTED_MAIN
366
367        Foo => [ <<'END_EXPECTED_FOO' ],
368                    PPI::Document::Fragment
369                        PPI::Statement::Package
370[    2,   1,   1 ]         PPI::Token::Word     'package'
371[    2,   8,   8 ]         PPI::Token::Whitespace   ' '
372[    2,   9,   9 ]         PPI::Token::Word     'Foo'
373[    2,  12,  12 ]         PPI::Token::Structure    ';'
374[    2,  13,  13 ]     PPI::Token::Whitespace   '\n'
375                        PPI::Statement
376[    3,   1,   1 ]         PPI::Token::Symbol   '$y'
377[    3,   3,   3 ]         PPI::Token::Whitespace   ' '
378[    3,   4,   4 ]         PPI::Token::Operator     '='
379[    3,   5,   5 ]         PPI::Token::Whitespace   ' '
380[    3,   6,   6 ]         PPI::Token::Number   '2'
381[    3,   7,   7 ]         PPI::Token::Structure    ';'
382[    3,   8,   8 ]     PPI::Token::Whitespace   '\n'
383                        PPI::Statement::Package
384[    6,   1,   1 ]         PPI::Token::Word     'package'
385[    6,   8,   8 ]         PPI::Token::Whitespace   ' '
386[    6,   9,   9 ]         PPI::Token::Word     'Foo'
387[    6,  12,  12 ]         PPI::Token::Structure    ';'
388[    6,  13,  13 ]     PPI::Token::Whitespace   '\n'
389                        PPI::Statement
390[    7,   1,   1 ]         PPI::Token::Symbol   '$w'
391[    7,   3,   3 ]         PPI::Token::Whitespace   ' '
392[    7,   4,   4 ]         PPI::Token::Operator     '='
393[    7,   5,   5 ]         PPI::Token::Whitespace   ' '
394[    7,   6,   6 ]         PPI::Token::Number   '4'
395[    7,   7,   7 ]         PPI::Token::Structure    ';'
396[    7,   8,   8 ]     PPI::Token::Whitespace   '\n'
397END_EXPECTED_FOO
398    );
399
400    _test(
401        $source,
402        \%expected,
403        'Simple multiple namespaces: back and forth between two.',
404    );
405}
406
407
408{
409    my $source = <<'END_SOURCE';
410$x = 1;
411
412{
413    package Foo;
414    $a = 17;
415}
416
417$y = 2;
418END_SOURCE
419
420    my %expected = (
421        main => [ <<'END_EXPECTED_MAIN' ],
422                    PPI::Document::Fragment
423                        PPI::Statement
424[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
425[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
426[    1,   4,   4 ]         PPI::Token::Operator     '='
427[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
428[    1,   6,   6 ]         PPI::Token::Number   '1'
429[    1,   7,   7 ]         PPI::Token::Structure    ';'
430[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
431[    2,   1,   1 ]     PPI::Token::Whitespace   '\n'
432                        PPI::Statement::Compound
433                            PPI::Structure::Block   { ... }
434[    3,   2,   2 ]             PPI::Token::Whitespace   '\n'
435[    4,   1,   1 ]             PPI::Token::Whitespace   '    '
436[    6,   2,   2 ]     PPI::Token::Whitespace   '\n'
437[    7,   1,   1 ]     PPI::Token::Whitespace   '\n'
438                        PPI::Statement
439[    8,   1,   1 ]         PPI::Token::Symbol   '$y'
440[    8,   3,   3 ]         PPI::Token::Whitespace   ' '
441[    8,   4,   4 ]         PPI::Token::Operator     '='
442[    8,   5,   5 ]         PPI::Token::Whitespace   ' '
443[    8,   6,   6 ]         PPI::Token::Number   '2'
444[    8,   7,   7 ]         PPI::Token::Structure    ';'
445[    8,   8,   8 ]     PPI::Token::Whitespace   '\n'
446END_EXPECTED_MAIN
447
448        Foo => [ <<'END_EXPECTED_FOO' ],
449                    PPI::Document::Fragment
450                        PPI::Statement::Package
451[    4,   5,   5 ]         PPI::Token::Word     'package'
452[    4,  12,  12 ]         PPI::Token::Whitespace   ' '
453[    4,  13,  13 ]         PPI::Token::Word     'Foo'
454[    4,  16,  16 ]         PPI::Token::Structure    ';'
455[    4,  17,  17 ]     PPI::Token::Whitespace   '\n'
456[    5,   1,   1 ]     PPI::Token::Whitespace   '    '
457                        PPI::Statement
458[    5,   5,   5 ]         PPI::Token::Symbol   '$a'
459[    5,   7,   7 ]         PPI::Token::Whitespace   ' '
460[    5,   8,   8 ]         PPI::Token::Operator     '='
461[    5,   9,   9 ]         PPI::Token::Whitespace   ' '
462[    5,  10,  10 ]         PPI::Token::Number   '17'
463[    5,  12,  12 ]         PPI::Token::Structure    ';'
464[    5,  13,  13 ]     PPI::Token::Whitespace   '\n'
465END_EXPECTED_FOO
466    );
467
468    _test($source, \%expected, 'Single lexically scoped namespace: scope block.');
469}
470
471
472{
473    my $source = <<'END_SOURCE';
474$x = 1;
475
476foreach qw< l m n > {
477    package Foo;
478    $a = 17;
479}
480
481$y = 2;
482END_SOURCE
483
484    my %expected = (
485        main => [ <<'END_EXPECTED_MAIN' ],
486                    PPI::Document::Fragment
487                        PPI::Statement
488[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
489[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
490[    1,   4,   4 ]         PPI::Token::Operator     '='
491[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
492[    1,   6,   6 ]         PPI::Token::Number   '1'
493[    1,   7,   7 ]         PPI::Token::Structure    ';'
494[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
495[    2,   1,   1 ]     PPI::Token::Whitespace   '\n'
496                        PPI::Statement::Compound
497[    3,   1,   1 ]         PPI::Token::Word     'foreach'
498[    3,   8,   8 ]         PPI::Token::Whitespace   ' '
499[    3,   9,   9 ]         PPI::Token::QuoteLike::Words     'qw< l m n >'
500[    3,  20,  20 ]         PPI::Token::Whitespace   ' '
501                            PPI::Structure::Block   { ... }
502[    3,  22,  22 ]             PPI::Token::Whitespace   '\n'
503[    4,   1,   1 ]             PPI::Token::Whitespace   '    '
504[    6,   2,   2 ]     PPI::Token::Whitespace   '\n'
505[    7,   1,   1 ]     PPI::Token::Whitespace   '\n'
506                        PPI::Statement
507[    8,   1,   1 ]         PPI::Token::Symbol   '$y'
508[    8,   3,   3 ]         PPI::Token::Whitespace   ' '
509[    8,   4,   4 ]         PPI::Token::Operator     '='
510[    8,   5,   5 ]         PPI::Token::Whitespace   ' '
511[    8,   6,   6 ]         PPI::Token::Number   '2'
512[    8,   7,   7 ]         PPI::Token::Structure    ';'
513[    8,   8,   8 ]     PPI::Token::Whitespace   '\n'
514END_EXPECTED_MAIN
515
516        Foo => [ <<'END_EXPECTED_FOO' ],
517                    PPI::Document::Fragment
518                        PPI::Statement::Package
519[    4,   5,   5 ]         PPI::Token::Word     'package'
520[    4,  12,  12 ]         PPI::Token::Whitespace   ' '
521[    4,  13,  13 ]         PPI::Token::Word     'Foo'
522[    4,  16,  16 ]         PPI::Token::Structure    ';'
523[    4,  17,  17 ]     PPI::Token::Whitespace   '\n'
524[    5,   1,   1 ]     PPI::Token::Whitespace   '    '
525                        PPI::Statement
526[    5,   5,   5 ]         PPI::Token::Symbol   '$a'
527[    5,   7,   7 ]         PPI::Token::Whitespace   ' '
528[    5,   8,   8 ]         PPI::Token::Operator     '='
529[    5,   9,   9 ]         PPI::Token::Whitespace   ' '
530[    5,  10,  10 ]         PPI::Token::Number   '17'
531[    5,  12,  12 ]         PPI::Token::Structure    ';'
532[    5,  13,  13 ]     PPI::Token::Whitespace   '\n'
533END_EXPECTED_FOO
534    );
535
536    _test(
537        $source,
538        \%expected,
539        'Single lexically scoped namespace: foreach loop.',
540    );
541}
542
543
544{
545    my $source = <<'END_SOURCE';
546$x = 1;
547
548given qw< l m n > {
549    package Foo;
550    $a = 17;
551}
552
553$y = 2;
554END_SOURCE
555
556    my %expected = (
557        main => [ <<'END_EXPECTED_MAIN' ],
558                    PPI::Document::Fragment
559                        PPI::Statement
560[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
561[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
562[    1,   4,   4 ]         PPI::Token::Operator     '='
563[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
564[    1,   6,   6 ]         PPI::Token::Number   '1'
565[    1,   7,   7 ]         PPI::Token::Structure    ';'
566[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
567[    2,   1,   1 ]     PPI::Token::Whitespace   '\n'
568                        PPI::Statement::Given
569[    3,   1,   1 ]         PPI::Token::Word     'given'
570[    3,   6,   6 ]         PPI::Token::Whitespace   ' '
571[    3,   7,   7 ]         PPI::Token::QuoteLike::Words     'qw< l m n >'
572[    3,  18,  18 ]         PPI::Token::Whitespace   ' '
573                            PPI::Structure::Block   { ... }
574[    3,  20,  20 ]             PPI::Token::Whitespace   '\n'
575[    4,   1,   1 ]             PPI::Token::Whitespace   '    '
576[    6,   2,   2 ]     PPI::Token::Whitespace   '\n'
577[    7,   1,   1 ]     PPI::Token::Whitespace   '\n'
578                        PPI::Statement
579[    8,   1,   1 ]         PPI::Token::Symbol   '$y'
580[    8,   3,   3 ]         PPI::Token::Whitespace   ' '
581[    8,   4,   4 ]         PPI::Token::Operator     '='
582[    8,   5,   5 ]         PPI::Token::Whitespace   ' '
583[    8,   6,   6 ]         PPI::Token::Number   '2'
584[    8,   7,   7 ]         PPI::Token::Structure    ';'
585[    8,   8,   8 ]     PPI::Token::Whitespace   '\n'
586END_EXPECTED_MAIN
587
588        Foo => [ <<'END_EXPECTED_FOO' ],
589                    PPI::Document::Fragment
590                        PPI::Statement::Package
591[    4,   5,   5 ]         PPI::Token::Word     'package'
592[    4,  12,  12 ]         PPI::Token::Whitespace   ' '
593[    4,  13,  13 ]         PPI::Token::Word     'Foo'
594[    4,  16,  16 ]         PPI::Token::Structure    ';'
595[    4,  17,  17 ]     PPI::Token::Whitespace   '\n'
596[    5,   1,   1 ]     PPI::Token::Whitespace   '    '
597                        PPI::Statement
598[    5,   5,   5 ]         PPI::Token::Symbol   '$a'
599[    5,   7,   7 ]         PPI::Token::Whitespace   ' '
600[    5,   8,   8 ]         PPI::Token::Operator     '='
601[    5,   9,   9 ]         PPI::Token::Whitespace   ' '
602[    5,  10,  10 ]         PPI::Token::Number   '17'
603[    5,  12,  12 ]         PPI::Token::Structure    ';'
604[    5,  13,  13 ]     PPI::Token::Whitespace   '\n'
605END_EXPECTED_FOO
606    );
607
608    _test(
609        $source,
610        \%expected,
611        'Single lexically scoped namespace: given.',
612    );
613}
614
615
616{
617    my $source = <<'END_SOURCE';
618$x = 1;
619
620when qw< l m n > {
621    package Foo;
622    $a = 17;
623}
624
625$y = 2;
626END_SOURCE
627
628    my %expected = (
629        main => [ <<'END_EXPECTED_MAIN' ],
630                    PPI::Document::Fragment
631                        PPI::Statement
632[    1,   1,   1 ]         PPI::Token::Symbol   '$x'
633[    1,   3,   3 ]         PPI::Token::Whitespace   ' '
634[    1,   4,   4 ]         PPI::Token::Operator     '='
635[    1,   5,   5 ]         PPI::Token::Whitespace   ' '
636[    1,   6,   6 ]         PPI::Token::Number   '1'
637[    1,   7,   7 ]         PPI::Token::Structure    ';'
638[    1,   8,   8 ]     PPI::Token::Whitespace   '\n'
639[    2,   1,   1 ]     PPI::Token::Whitespace   '\n'
640                        PPI::Statement::When
641[    3,   1,   1 ]         PPI::Token::Word     'when'
642[    3,   5,   5 ]         PPI::Token::Whitespace   ' '
643[    3,   6,   6 ]         PPI::Token::QuoteLike::Words     'qw< l m n >'
644[    3,  17,  17 ]         PPI::Token::Whitespace   ' '
645                            PPI::Structure::Block   { ... }
646[    3,  19,  19 ]             PPI::Token::Whitespace   '\n'
647[    4,   1,   1 ]             PPI::Token::Whitespace   '    '
648[    6,   2,   2 ]     PPI::Token::Whitespace   '\n'
649[    7,   1,   1 ]     PPI::Token::Whitespace   '\n'
650                        PPI::Statement
651[    8,   1,   1 ]         PPI::Token::Symbol   '$y'
652[    8,   3,   3 ]         PPI::Token::Whitespace   ' '
653[    8,   4,   4 ]         PPI::Token::Operator     '='
654[    8,   5,   5 ]         PPI::Token::Whitespace   ' '
655[    8,   6,   6 ]         PPI::Token::Number   '2'
656[    8,   7,   7 ]         PPI::Token::Structure    ';'
657[    8,   8,   8 ]     PPI::Token::Whitespace   '\n'
658END_EXPECTED_MAIN
659
660        Foo => [ <<'END_EXPECTED_FOO' ],
661                    PPI::Document::Fragment
662                        PPI::Statement::Package
663[    4,   5,   5 ]         PPI::Token::Word     'package'
664[    4,  12,  12 ]         PPI::Token::Whitespace   ' '
665[    4,  13,  13 ]         PPI::Token::Word     'Foo'
666[    4,  16,  16 ]         PPI::Token::Structure    ';'
667[    4,  17,  17 ]     PPI::Token::Whitespace   '\n'
668[    5,   1,   1 ]     PPI::Token::Whitespace   '    '
669                        PPI::Statement
670[    5,   5,   5 ]         PPI::Token::Symbol   '$a'
671[    5,   7,   7 ]         PPI::Token::Whitespace   ' '
672[    5,   8,   8 ]         PPI::Token::Operator     '='
673[    5,   9,   9 ]         PPI::Token::Whitespace   ' '
674[    5,  10,  10 ]         PPI::Token::Number   '17'
675[    5,  12,  12 ]         PPI::Token::Structure    ';'
676[    5,  13,  13 ]     PPI::Token::Whitespace   '\n'
677END_EXPECTED_FOO
678    );
679
680    _test(
681        $source,
682        \%expected,
683        'Single lexically scoped namespace: when.',
684    );
685}
686
687
688{
689    my $source = <<'END_SOURCE';
690given (0) {
691    package Foo;
692    when (1) {
693        package main;
694    }
695    when (2) {
696        package main;
697    }
698    default {
699        package main;
700        while (3) {
701            package Foo;
702            package Bar;
703            package Foo;
704            package main;
705            foreach (4) {
706                package Foo;
707            }
708        }
709    }
710}
711END_SOURCE
712
713    my %expected = (
714        main => [
715<<'END_EXPECTED_MAIN',
716                    PPI::Document::Fragment
717                        PPI::Statement::Given
718[    1,   1,   1 ]         PPI::Token::Word     'given'
719[    1,   6,   6 ]         PPI::Token::Whitespace   ' '
720                            PPI::Structure::Given   ( ... )
721                                PPI::Statement::Expression
722[    1,   8,   8 ]                 PPI::Token::Number   '0'
723[    1,  10,  10 ]         PPI::Token::Whitespace   ' '
724                            PPI::Structure::Block   { ... }
725[    1,  12,  12 ]             PPI::Token::Whitespace   '\n'
726[    2,   1,   1 ]             PPI::Token::Whitespace   '    '
727[   21,   2,   2 ]     PPI::Token::Whitespace   '\n'
728END_EXPECTED_MAIN
729<<'END_EXPECTED_MAIN',
730                    PPI::Document::Fragment
731                        PPI::Statement::Package
732[    4,   9,   9 ]         PPI::Token::Word     'package'
733[    4,  16,  16 ]         PPI::Token::Whitespace   ' '
734[    4,  17,  17 ]         PPI::Token::Word     'main'
735[    4,  21,  21 ]         PPI::Token::Structure    ';'
736[    4,  22,  22 ]     PPI::Token::Whitespace   '\n'
737[    5,   1,   1 ]     PPI::Token::Whitespace   '    '
738END_EXPECTED_MAIN
739<<'END_EXPECTED_MAIN',
740                    PPI::Document::Fragment
741                        PPI::Statement::Package
742[    7,   9,   9 ]         PPI::Token::Word     'package'
743[    7,  16,  16 ]         PPI::Token::Whitespace   ' '
744[    7,  17,  17 ]         PPI::Token::Word     'main'
745[    7,  21,  21 ]         PPI::Token::Structure    ';'
746[    7,  22,  22 ]     PPI::Token::Whitespace   '\n'
747[    8,   1,   1 ]     PPI::Token::Whitespace   '    '
748END_EXPECTED_MAIN
749<<'END_EXPECTED_MAIN',
750                    PPI::Document::Fragment
751                        PPI::Statement::Package
752[   10,   9,   9 ]         PPI::Token::Word     'package'
753[   10,  16,  16 ]         PPI::Token::Whitespace   ' '
754[   10,  17,  17 ]         PPI::Token::Word     'main'
755[   10,  21,  21 ]         PPI::Token::Structure    ';'
756[   10,  22,  22 ]     PPI::Token::Whitespace   '\n'
757[   11,   1,   1 ]     PPI::Token::Whitespace   '        '
758                        PPI::Statement::Compound
759[   11,   9,   9 ]         PPI::Token::Word     'while'
760[   11,  14,  14 ]         PPI::Token::Whitespace   ' '
761                            PPI::Structure::Condition   ( ... )
762                                PPI::Statement::Expression
763[   11,  16,  16 ]                 PPI::Token::Number   '3'
764[   11,  18,  18 ]         PPI::Token::Whitespace   ' '
765                            PPI::Structure::Block   { ... }
766[   11,  20,  20 ]             PPI::Token::Whitespace   '\n'
767[   12,   1,   1 ]             PPI::Token::Whitespace   '            '
768                                PPI::Statement::Package
769[   15,  13,  13 ]                 PPI::Token::Word     'package'
770[   15,  20,  20 ]                 PPI::Token::Whitespace   ' '
771[   15,  21,  21 ]                 PPI::Token::Word     'main'
772[   15,  25,  25 ]                 PPI::Token::Structure    ';'
773[   15,  26,  26 ]             PPI::Token::Whitespace   '\n'
774[   16,   1,   1 ]             PPI::Token::Whitespace   '            '
775                                PPI::Statement::Compound
776[   16,  13,  13 ]                 PPI::Token::Word     'foreach'
777[   16,  20,  20 ]                 PPI::Token::Whitespace   ' '
778                                    PPI::Structure::List    ( ... )
779                                        PPI::Statement
780[   16,  22,  22 ]                         PPI::Token::Number   '4'
781[   16,  24,  24 ]                 PPI::Token::Whitespace   ' '
782                                    PPI::Structure::Block   { ... }
783[   16,  26,  26 ]                     PPI::Token::Whitespace   '\n'
784[   17,   1,   1 ]                     PPI::Token::Whitespace   '                '
785[   18,  14,  14 ]             PPI::Token::Whitespace   '\n'
786[   19,   1,   1 ]             PPI::Token::Whitespace   '        '
787[   19,  10,  10 ]     PPI::Token::Whitespace   '\n'
788[   20,   1,   1 ]     PPI::Token::Whitespace   '    '
789END_EXPECTED_MAIN
790        ],
791
792        Foo => [
793<<'END_EXPECTED_FOO',
794                    PPI::Document::Fragment
795                        PPI::Statement::Package
796[    2,   5,   5 ]         PPI::Token::Word     'package'
797[    2,  12,  12 ]         PPI::Token::Whitespace   ' '
798[    2,  13,  13 ]         PPI::Token::Word     'Foo'
799[    2,  16,  16 ]         PPI::Token::Structure    ';'
800[    2,  17,  17 ]     PPI::Token::Whitespace   '\n'
801[    3,   1,   1 ]     PPI::Token::Whitespace   '    '
802                        PPI::Statement::When
803[    3,   5,   5 ]         PPI::Token::Word     'when'
804[    3,   9,   9 ]         PPI::Token::Whitespace   ' '
805                            PPI::Structure::When    ( ... )
806                                PPI::Statement::Expression
807[    3,  11,  11 ]                 PPI::Token::Number   '1'
808[    3,  13,  13 ]         PPI::Token::Whitespace   ' '
809                            PPI::Structure::Block   { ... }
810[    3,  15,  15 ]             PPI::Token::Whitespace   '\n'
811[    4,   1,   1 ]             PPI::Token::Whitespace   '        '
812[    5,   6,   6 ]     PPI::Token::Whitespace   '\n'
813[    6,   1,   1 ]     PPI::Token::Whitespace   '    '
814                        PPI::Statement::When
815[    6,   5,   5 ]         PPI::Token::Word     'when'
816[    6,   9,   9 ]         PPI::Token::Whitespace   ' '
817                            PPI::Structure::When    ( ... )
818                                PPI::Statement::Expression
819[    6,  11,  11 ]                 PPI::Token::Number   '2'
820[    6,  13,  13 ]         PPI::Token::Whitespace   ' '
821                            PPI::Structure::Block   { ... }
822[    6,  15,  15 ]             PPI::Token::Whitespace   '\n'
823[    7,   1,   1 ]             PPI::Token::Whitespace   '        '
824[    8,   6,   6 ]     PPI::Token::Whitespace   '\n'
825[    9,   1,   1 ]     PPI::Token::Whitespace   '    '
826                        PPI::Statement::When
827[    9,   5,   5 ]         PPI::Token::Word     'default'
828[    9,  12,  12 ]         PPI::Token::Whitespace   ' '
829                            PPI::Structure::Block   { ... }
830[    9,  14,  14 ]             PPI::Token::Whitespace   '\n'
831[   10,   1,   1 ]             PPI::Token::Whitespace   '        '
832[   20,   6,   6 ]     PPI::Token::Whitespace   '\n'
833END_EXPECTED_FOO
834<<'END_EXPECTED_FOO',
835                    PPI::Document::Fragment
836                        PPI::Statement::Package
837[   12,  13,  13 ]         PPI::Token::Word     'package'
838[   12,  20,  20 ]         PPI::Token::Whitespace   ' '
839[   12,  21,  21 ]         PPI::Token::Word     'Foo'
840[   12,  24,  24 ]         PPI::Token::Structure    ';'
841[   12,  25,  25 ]     PPI::Token::Whitespace   '\n'
842[   13,   1,   1 ]     PPI::Token::Whitespace   '            '
843                        PPI::Statement::Package
844[   14,  13,  13 ]         PPI::Token::Word     'package'
845[   14,  20,  20 ]         PPI::Token::Whitespace   ' '
846[   14,  21,  21 ]         PPI::Token::Word     'Foo'
847[   14,  24,  24 ]         PPI::Token::Structure    ';'
848[   14,  25,  25 ]     PPI::Token::Whitespace   '\n'
849[   15,   1,   1 ]     PPI::Token::Whitespace   '            '
850END_EXPECTED_FOO
851<<'END_EXPECTED_FOO',
852                    PPI::Document::Fragment
853                        PPI::Statement::Package
854[   17,  17,  17 ]         PPI::Token::Word     'package'
855[   17,  24,  24 ]         PPI::Token::Whitespace   ' '
856[   17,  25,  25 ]         PPI::Token::Word     'Foo'
857[   17,  28,  28 ]         PPI::Token::Structure    ';'
858[   17,  29,  29 ]     PPI::Token::Whitespace   '\n'
859[   18,   1,   1 ]     PPI::Token::Whitespace   '            '
860END_EXPECTED_FOO
861        ],
862
863        Bar => [ <<'END_EXPECTED_BAR' ],
864                    PPI::Document::Fragment
865                        PPI::Statement::Package
866[   13,  13,  13 ]         PPI::Token::Word     'package'
867[   13,  20,  20 ]         PPI::Token::Whitespace   ' '
868[   13,  21,  21 ]         PPI::Token::Word     'Bar'
869[   13,  24,  24 ]         PPI::Token::Structure    ';'
870[   13,  25,  25 ]     PPI::Token::Whitespace   '\n'
871[   14,   1,   1 ]     PPI::Token::Whitespace   '            '
872END_EXPECTED_BAR
873    );
874
875    _test(
876        $source,
877        \%expected,
878        'Heavilly nested namespaces.',
879    );
880}
881
882
883sub _test {
884    my ($source, $expected_ref, $test_name) = @_;
885
886    my $document = PPI::Document->new(\$source);
887
888    my %expanded_expected;
889    foreach my $namespace ( keys %{$expected_ref} ) {
890        my $strings = $expected_ref->{$namespace};
891        $expanded_expected{$namespace} =
892            [ map { [ split m/ \n /x ] } @{$strings} ];
893    }
894
895    my $got = split_ppi_node_by_namespace($document);
896    my %got_expanded;
897    foreach my $namespace ( keys %{$got} ) {
898        my $ppi_doms = $got->{$namespace};
899        $got_expanded{$namespace} =
900            [
901                map {
902                        [ map { _expand_tabs($_) } _new_dumper($_)->list() ]
903                    }
904                    @{$ppi_doms}
905            ];
906    }
907
908    is_deeply(\%got_expanded, \%expanded_expected, $test_name)
909        or diag(
910            Data::Dumper->Dump(
911                [\%got_expanded, \%expanded_expected],
912                [ qw<got_expanded expanded_expected> ],
913            )
914        );
915
916    return;
917}
918
919
920sub _new_dumper {
921    my ($node) = @_;
922
923    return PPI::Dumper->new($node, indent => $DUMP_INDENT, locations => 1);
924}
925
926
927# Why Adam had to put @#$^@#$&^ hard tabs in his dumper output, I don't know.
928sub _expand_tabs {
929    my ($string) = @_;
930
931    while (
932        $string =~
933            s< \A ( [^\t]* ) ( \t+ )                          >
934             <$1 . ( ' ' x (length($2) * $DUMP_INDENT - length($1) % $DUMP_INDENT) )>xe
935    ) {
936        # Nothing here.
937    }
938
939    return $string;
940}
941
942done_testing;
943