1#!perl -w
2
3use strict;
4use warnings;
5use lib 't/lib';
6
7use Test::More;
8
9use TAP::Parser::YAMLish::Reader;
10
11my @SCHEDULE;
12
13BEGIN {
14    @SCHEDULE = (
15        {   name => 'Hello World',
16            in   => [
17                '--- Hello, World',
18                '...',
19            ],
20            out => "Hello, World",
21        },
22        {   name => 'Hello World 2',
23            in   => [
24                '--- \'Hello, \'\'World\'',
25                '...',
26            ],
27            out => "Hello, 'World",
28        },
29        {   name => 'Hello World 3',
30            in   => [
31                '--- "Hello, World"',
32                '...',
33            ],
34            out => "Hello, World",
35        },
36        {   name => 'Hello World 4',
37            in   => [
38                '--- "Hello, World"',
39                '...',
40            ],
41            out => "Hello, World",
42        },
43        {   name => 'Hello World 4',
44            in   => [
45                '--- >',
46                '   Hello,',
47                '      World',
48                '...',
49            ],
50            out => "Hello, World\n",
51        },
52        {   name => 'Hello World Block',
53            in   => [
54                '--- |',
55                '   Hello,',
56                '      World',
57                '...',
58            ],
59            out => "Hello,\n   World\n",
60        },
61        {   name => 'Hello World 5',
62            in   => [
63                '--- >',
64                '   Hello,',
65                '  World',
66                '...',
67            ],
68            error => qr{Missing\s+'[.][.][.]'},
69        },
70        {   name => 'Simple array',
71            in   => [
72                '---',
73                '- 1',
74                '- 2',
75                '- 3',
76                '...',
77            ],
78            out => [ '1', '2', '3' ],
79        },
80        {   name => 'Mixed array',
81            in   => [
82                '---',
83                '- 1',
84                '- \'two\'',
85                '- "three\n"',
86                '...',
87            ],
88            out => [ '1', 'two', "three\n" ],
89        },
90        {   name => 'Hash in array',
91            in   => [
92                '---',
93                '- 1',
94                '- two: 2',
95                '- 3',
96                '...',
97            ],
98            out => [ '1', { two => '2' }, '3' ],
99        },
100        {   name => 'Hash in array 2',
101            in   => [
102                '---',
103                '- 1',
104                '- two: 2',
105                '  three: 3',
106                '- 4',
107                '...',
108            ],
109            out => [ '1', { two => '2', three => '3' }, '4' ],
110        },
111        {   name => 'Nested array',
112            in   => [
113                '---',
114                '- one',
115                '-',
116                '  - two',
117                '  -',
118                '    - three',
119                '  - four',
120                '- five',
121                '...',
122            ],
123            out => [ 'one', [ 'two', ['three'], 'four' ], 'five' ],
124        },
125        {   name => 'Nested hash',
126            in   => [
127                '---',
128                'one:',
129                '  five: 5',
130                '  two:',
131                '    four: 4',
132                '    three: 3',
133                'six: 6',
134                '...',
135            ],
136            out => {
137                one => { two => { three => '3', four => '4' }, five => '5' },
138                six => '6'
139            },
140        },
141        {   name => 'Space after colon',
142            in   => [ '---', 'spog: ', ' - 1', ' - 2', '...' ],
143            out => { spog => [ 1, 2 ] },
144        },
145        {   name => 'Original YAML::Tiny test',
146            in   => [
147                '---',
148                'invoice: 34843',
149                'date   : 2001-01-23',
150                'bill-to:',
151                '    given  : Chris',
152                '    family : Dumars',
153                '    address:',
154                '        lines: |',
155                '            458 Walkman Dr.',
156                '            Suite #292',
157                '        city    : Royal Oak',
158                '        state   : MI',
159                '        postal  : 48046',
160                'product:',
161                '    - sku         : BL394D',
162                '      quantity    : 4',
163                '      description : Basketball',
164                '      price       : 450.00',
165                '    - sku         : BL4438H',
166                '      quantity    : 1',
167                '      description : Super Hoop',
168                '      price       : 2392.00',
169                'tax  : 251.42',
170                'total: 4443.52',
171                'comments: >',
172                '    Late afternoon is best.',
173                '    Backup contact is Nancy',
174                '    Billsmer @ 338-4338',
175                '...',
176            ],
177            out => {
178                'bill-to' => {
179                    'given'   => 'Chris',
180                    'address' => {
181                        'city'   => 'Royal Oak',
182                        'postal' => '48046',
183                        'lines'  => "458 Walkman Dr.\nSuite #292\n",
184                        'state'  => 'MI'
185                    },
186                    'family' => 'Dumars'
187                },
188                'invoice' => '34843',
189                'date'    => '2001-01-23',
190                'tax'     => '251.42',
191                'product' => [
192                    {   'sku'         => 'BL394D',
193                        'quantity'    => '4',
194                        'price'       => '450.00',
195                        'description' => 'Basketball'
196                    },
197                    {   'sku'         => 'BL4438H',
198                        'quantity'    => '1',
199                        'price'       => '2392.00',
200                        'description' => 'Super Hoop'
201                    }
202                ],
203                'comments' =>
204                  "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n",
205                'total' => '4443.52'
206            }
207        },
208
209        # Tests harvested from YAML::Tiny
210        {   in    => ['...'],
211            name  => 'Regression: empty',
212            error => qr{document\s+header\s+not\s+found}
213        },
214        {   in => [
215                '# comment',
216                '...'
217            ],
218            name  => 'Regression: only_comment',
219            error => qr{document\s+header\s+not\s+found}
220        },
221        {   out => undef,
222            in  => [
223                '---',
224                '...'
225            ],
226            name  => 'Regression: only_header',
227            error => qr{Premature\s+end}i,
228        },
229        {   out => undef,
230            in  => [
231                '---',
232                '---',
233                '...'
234            ],
235            name  => 'Regression: two_header',
236            error => qr{Unexpected\s+start}i,
237        },
238        {   out => undef,
239            in  => [
240                '--- ~',
241                '...'
242            ],
243            name => 'Regression: one_undef'
244        },
245        {   out => undef,
246            in  => [
247                '---  ~',
248                '...'
249            ],
250            name => 'Regression: one_undef2'
251        },
252        {   in => [
253                '--- ~',
254                '---',
255                '...'
256            ],
257            name  => 'Regression: two_undef',
258            error => qr{Missing\s+'[.][.][.]'},
259        },
260        {   out => 'foo',
261            in  => [
262                '--- foo',
263                '...'
264            ],
265            name => 'Regression: one_scalar',
266        },
267        {   out => 'foo',
268            in  => [
269                '---  foo',
270                '...'
271            ],
272            name => 'Regression: one_scalar2',
273        },
274        {   in => [
275                '--- foo',
276                '--- bar',
277                '...'
278            ],
279            name  => 'Regression: two_scalar',
280            error => qr{Missing\s+'[.][.][.]'},
281        },
282        {   out => ['foo'],
283            in  => [
284                '---',
285                '- foo',
286                '...'
287            ],
288            name => 'Regression: one_list1'
289        },
290        {   out => [
291                'foo',
292                'bar'
293            ],
294            in => [
295                '---',
296                '- foo',
297                '- bar',
298                '...'
299            ],
300            name => 'Regression: one_list2'
301        },
302        {   out => [
303                undef,
304                'bar'
305            ],
306            in => [
307                '---',
308                '- ~',
309                '- bar',
310                '...'
311            ],
312            name => 'Regression: one_listundef'
313        },
314        {   out => { 'foo' => 'bar' },
315            in  => [
316                '---',
317                'foo: bar',
318                '...'
319            ],
320            name => 'Regression: one_hash1'
321        },
322        {   out => {
323                'foo'  => 'bar',
324                'this' => undef
325            },
326            in => [
327                '---',
328                'foo: bar',
329                'this: ~',
330                '...'
331            ],
332            name => 'Regression: one_hash2'
333        },
334        {   out => {
335                'foo' => [
336                    'bar',
337                    undef,
338                    'baz'
339                ]
340            },
341            in => [
342                '---',
343                'foo:',
344                '  - bar',
345                '  - ~',
346                '  - baz',
347                '...'
348            ],
349            name => 'Regression: array_in_hash'
350        },
351        {   out => {
352                'bar' => { 'foo' => 'bar' },
353                'foo' => undef
354            },
355            in => [
356                '---',
357                'foo: ~',
358                'bar:',
359                '  foo: bar',
360                '...'
361            ],
362            name => 'Regression: hash_in_hash'
363        },
364        {   out => [
365                {   'foo'  => undef,
366                    'this' => 'that'
367                },
368                'foo', undef,
369                {   'foo'  => 'bar',
370                    'this' => 'that'
371                }
372            ],
373            in => [
374                '---',
375                '-',
376                '  foo: ~',
377                '  this: that',
378                '- foo',
379                '- ~',
380                '-',
381                '  foo: bar',
382                '  this: that',
383                '...'
384            ],
385            name => 'Regression: hash_in_array'
386        },
387        {   out => ['foo'],
388            in  => [
389                '---',
390                '- \'foo\'',
391                '...'
392            ],
393            name => 'Regression: single_quote1'
394        },
395        {   out => ['  '],
396            in  => [
397                '---',
398                '- \'  \'',
399                '...'
400            ],
401            name => 'Regression: single_spaces'
402        },
403        {   out => [''],
404            in  => [
405                '---',
406                '- \'\'',
407                '...'
408            ],
409            name => 'Regression: single_null'
410        },
411        {   out => '  ',
412            in  => [
413                '--- "  "',
414                '...'
415            ],
416            name => 'Regression: only_spaces'
417        },
418        {   out => ['first','second'],
419            in  => [
420                '--- ',
421                '- first ',
422                '- second ',
423                '...'
424            ],
425            name => "Space after header for array",
426        },
427        {   out => {'key' => [{'value' => {'key2' => 'value2'}}]},
428            in  => [
429                '--- ',
430                'key: ',
431                '- value: ',
432                '    key2: value2 ',
433                '... '
434            ],
435            name => "Space after header for hash",
436        },
437        {   out => [
438                undef,
439                {   'foo'  => 'bar',
440                    'this' => 'that'
441                },
442                'baz'
443            ],
444            in => [
445                '---',
446                '- ~',
447                '- foo: bar',
448                '  this: that',
449                '- baz',
450                '...'
451            ],
452            name => 'Regression: inline_nested_hash'
453        },
454        {   name => "Unprintables",
455            in   => [
456                "---",
457                "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"",
458                "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"",
459                "- \" !\\\"#\$%&'()*+,-./\"",
460                "- 0123456789:;<=>?",
461                "- '\@ABCDEFGHIJKLMNO'",
462                "- 'PQRSTUVWXYZ[\\]^_'",
463                "- '`abcdefghijklmno'",
464                "- 'pqrstuvwxyz{|}~\177'",
465                "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217",
466                "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237",
467                "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257",
468                "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",
469                "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317",
470                "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337",
471                "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357",
472                "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
473                "..."
474            ],
475            out => [
476                "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17",
477                "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37",
478                " !\"#\$%&'()*+,-./",
479                "0123456789:;<=>?",
480                "\@ABCDEFGHIJKLMNO",
481                "PQRSTUVWXYZ[\\]^_",
482                "`abcdefghijklmno",
483                "pqrstuvwxyz{|}~\177",
484                "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217",
485                "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237",
486                "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257",
487                "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",
488                "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317",
489                "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337",
490                "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357",
491                "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
492            ],
493        },
494        {   name => 'Quoted hash keys',
495            in   => [
496                '---',
497                '  "quoted": Magic!',
498                '  "\n\t": newline, tab',
499                '...',
500            ],
501            out => {
502                quoted => 'Magic!',
503                "\n\t" => 'newline, tab',
504            },
505        },
506        {   name => 'Empty',
507            in   => [],
508            out  => undef,
509        },
510    );
511
512    plan tests => @SCHEDULE * 5;
513}
514
515sub iter {
516    my $ar = shift;
517    return sub {
518        return shift @$ar;
519    };
520}
521
522for my $test (@SCHEDULE) {
523    my $name = $test->{name};
524    ok my $yaml = TAP::Parser::YAMLish::Reader->new, "$name: Created";
525    isa_ok $yaml, 'TAP::Parser::YAMLish::Reader';
526
527    my $source = join( "\n", @{ $test->{in} } ) . "\n";
528
529    my $iter = iter( $test->{in} );
530    my $got = eval { $yaml->read($iter) };
531
532    my $raw = $yaml->get_raw;
533
534    if ( my $err = $test->{error} ) {
535        unless ( like $@, $err, "$name: Error message" ) {
536            diag "Error: $@\n";
537        }
538        ok !$got, "$name: No result";
539        pass;
540    }
541    else {
542        my $want = $test->{out};
543        unless ( ok !$@, "$name: No error" ) {
544            diag "Error: $@\n";
545        }
546        is_deeply $got, $want,   "$name: Result matches";
547        is $raw,        $source, "$name: Captured source matches";
548    }
549}
550