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 => 'Edge cases for hash start vs. undefined scalar 1', 142 in => [ 143 '---', 144 'one:', 145 ' five: 5', 146 ' two:', 147 ' four: 4', 148 ' three: 3', 149 'six: 6', 150 '...', 151 ], 152 out => { 153 one => { two => undef, three => '3', four => '4', five => '5' }, 154 six => '6' 155 }, 156 }, 157 { name => 'Edge cases for hash start vs. undefined scalar 2', 158 in => [ 159 '---', 160 'one:', 161 ' five: 5', 162 ' two: ~', 163 ' four: 4', 164 ' three: 3', 165 'six: 6', 166 '...', 167 ], 168 out => { 169 one => { two => undef, three => '3', four => '4', five => '5' }, 170 six => '6' 171 }, 172 }, 173 { name => 'Edge cases for hash start vs. undefined scalar 3', 174 in => [ 175 '---', 176 'two:', 177 'four: 4', 178 'three: 3', 179 '...', 180 ], 181 out => { 182 two => undef, three => '3', four => '4', 183 }, 184 }, 185 { name => 'Edge cases for hash start vs. undefined scalar 4', 186 in => [ 187 '---', 188 'two:', 189 ' four: 4', 190 ' three: 3', 191 '...', 192 ], 193 out => { 194 two => { three => '3', four => '4' }, 195 }, 196 }, 197 { name => 'Edge cases for hash start vs. undefined scalar 5', 198 in => [ 199 '---', 200 'two:', 201 '- four: 4', 202 '- three: 3', 203 '...', 204 ], 205 out => { 206 two => [ { four => '4' }, { three => '3' } ], 207 }, 208 }, 209 { name => 'Space after colon', 210 in => [ '---', 'spog: ', ' - 1', ' - 2', '...' ], 211 out => { spog => [ 1, 2 ] }, 212 }, 213 { name => 'Original YAML::Tiny test', 214 in => [ 215 '---', 216 'invoice: 34843', 217 'date : 2001-01-23', 218 'bill-to:', 219 ' given : Chris', 220 ' family : Dumars', 221 ' address:', 222 ' lines: |', 223 ' 458 Walkman Dr.', 224 ' Suite #292', 225 ' city : Royal Oak', 226 ' state : MI', 227 ' postal : 48046', 228 'product:', 229 ' - sku : BL394D', 230 ' quantity : 4', 231 ' description : Basketball', 232 ' price : 450.00', 233 ' - sku : BL4438H', 234 ' quantity : 1', 235 ' description : Super Hoop', 236 ' price : 2392.00', 237 'tax : 251.42', 238 'total: 4443.52', 239 'comments: >', 240 ' Late afternoon is best.', 241 ' Backup contact is Nancy', 242 ' Billsmer @ 338-4338', 243 '...', 244 ], 245 out => { 246 'bill-to' => { 247 'given' => 'Chris', 248 'address' => { 249 'city' => 'Royal Oak', 250 'postal' => '48046', 251 'lines' => "458 Walkman Dr.\nSuite #292\n", 252 'state' => 'MI' 253 }, 254 'family' => 'Dumars' 255 }, 256 'invoice' => '34843', 257 'date' => '2001-01-23', 258 'tax' => '251.42', 259 'product' => [ 260 { 'sku' => 'BL394D', 261 'quantity' => '4', 262 'price' => '450.00', 263 'description' => 'Basketball' 264 }, 265 { 'sku' => 'BL4438H', 266 'quantity' => '1', 267 'price' => '2392.00', 268 'description' => 'Super Hoop' 269 } 270 ], 271 'comments' => 272 "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n", 273 'total' => '4443.52' 274 } 275 }, 276 277 # Tests harvested from YAML::Tiny 278 { in => ['...'], 279 name => 'Regression: empty', 280 error => qr{document\s+header\s+not\s+found} 281 }, 282 { in => [ 283 '# comment', 284 '...' 285 ], 286 name => 'Regression: only_comment', 287 error => qr{document\s+header\s+not\s+found} 288 }, 289 { out => undef, 290 in => [ 291 '---', 292 '...' 293 ], 294 name => 'Regression: only_header', 295 error => qr{Premature\s+end}i, 296 }, 297 { out => undef, 298 in => [ 299 '---', 300 '---', 301 '...' 302 ], 303 name => 'Regression: two_header', 304 error => qr{Unexpected\s+start}i, 305 }, 306 { out => undef, 307 in => [ 308 '--- ~', 309 '...' 310 ], 311 name => 'Regression: one_undef' 312 }, 313 { out => undef, 314 in => [ 315 '--- ~', 316 '...' 317 ], 318 name => 'Regression: one_undef2' 319 }, 320 { in => [ 321 '--- ~', 322 '---', 323 '...' 324 ], 325 name => 'Regression: two_undef', 326 error => qr{Missing\s+'[.][.][.]'}, 327 }, 328 { out => 'foo', 329 in => [ 330 '--- foo', 331 '...' 332 ], 333 name => 'Regression: one_scalar', 334 }, 335 { out => 'foo', 336 in => [ 337 '--- foo', 338 '...' 339 ], 340 name => 'Regression: one_scalar2', 341 }, 342 { in => [ 343 '--- foo', 344 '--- bar', 345 '...' 346 ], 347 name => 'Regression: two_scalar', 348 error => qr{Missing\s+'[.][.][.]'}, 349 }, 350 { out => ['foo'], 351 in => [ 352 '---', 353 '- foo', 354 '...' 355 ], 356 name => 'Regression: one_list1' 357 }, 358 { out => [ 359 'foo', 360 'bar' 361 ], 362 in => [ 363 '---', 364 '- foo', 365 '- bar', 366 '...' 367 ], 368 name => 'Regression: one_list2' 369 }, 370 { out => [ 371 undef, 372 'bar' 373 ], 374 in => [ 375 '---', 376 '- ~', 377 '- bar', 378 '...' 379 ], 380 name => 'Regression: one_listundef' 381 }, 382 { out => { 'foo' => 'bar' }, 383 in => [ 384 '---', 385 'foo: bar', 386 '...' 387 ], 388 name => 'Regression: one_hash1' 389 }, 390 { out => { 391 'foo' => 'bar', 392 'this' => undef 393 }, 394 in => [ 395 '---', 396 'foo: bar', 397 'this: ~', 398 '...' 399 ], 400 name => 'Regression: one_hash2' 401 }, 402 { out => { 403 'foo' => [ 404 'bar', 405 undef, 406 'baz' 407 ] 408 }, 409 in => [ 410 '---', 411 'foo:', 412 ' - bar', 413 ' - ~', 414 ' - baz', 415 '...' 416 ], 417 name => 'Regression: array_in_hash' 418 }, 419 { out => { 420 'bar' => { 'foo' => 'bar' }, 421 'foo' => undef 422 }, 423 in => [ 424 '---', 425 'foo: ~', 426 'bar:', 427 ' foo: bar', 428 '...' 429 ], 430 name => 'Regression: hash_in_hash' 431 }, 432 { out => [ 433 { 'foo' => undef, 434 'this' => 'that' 435 }, 436 'foo', undef, 437 { 'foo' => 'bar', 438 'this' => 'that' 439 } 440 ], 441 in => [ 442 '---', 443 '-', 444 ' foo: ~', 445 ' this: that', 446 '- foo', 447 '- ~', 448 '-', 449 ' foo: bar', 450 ' this: that', 451 '...' 452 ], 453 name => 'Regression: hash_in_array' 454 }, 455 { out => ['foo'], 456 in => [ 457 '---', 458 '- \'foo\'', 459 '...' 460 ], 461 name => 'Regression: single_quote1' 462 }, 463 { out => [' '], 464 in => [ 465 '---', 466 '- \' \'', 467 '...' 468 ], 469 name => 'Regression: single_spaces' 470 }, 471 { out => [''], 472 in => [ 473 '---', 474 '- \'\'', 475 '...' 476 ], 477 name => 'Regression: single_null' 478 }, 479 { out => ' ', 480 in => [ 481 '--- " "', 482 '...' 483 ], 484 name => 'Regression: only_spaces' 485 }, 486 { out => ['first','second'], 487 in => [ 488 '--- ', 489 '- first ', 490 '- second ', 491 '...' 492 ], 493 name => "Space after header for array", 494 }, 495 { out => {'key' => [{'value' => {'key2' => 'value2'}}]}, 496 in => [ 497 '--- ', 498 'key: ', 499 '- value: ', 500 ' key2: value2 ', 501 '... ' 502 ], 503 name => "Space after header for hash", 504 }, 505 { out => [ 506 undef, 507 { 'foo' => 'bar', 508 'this' => 'that' 509 }, 510 'baz' 511 ], 512 in => [ 513 '---', 514 '- ~', 515 '- foo: bar', 516 ' this: that', 517 '- baz', 518 '...' 519 ], 520 name => 'Regression: inline_nested_hash' 521 }, 522 { name => "Unprintables", # This is an ASCII centric test 523 in => [ 524 "---", 525 "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"", 526 "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"", 527 "- \" !\\\"#\$%&'()*+,-./\"", 528 "- 0123456789:;<=>?", 529 "- '\@ABCDEFGHIJKLMNO'", 530 "- 'PQRSTUVWXYZ[\\]^_'", 531 "- '`abcdefghijklmno'", 532 "- 'pqrstuvwxyz{|}~\177'", 533 "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", 534 "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", 535 "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", 536 "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", 537 "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", 538 "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", 539 "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", 540 "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", 541 "..." 542 ], 543 out => [ 544 "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17", 545 "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37", 546 " !\"#\$%&'()*+,-./", 547 "0123456789:;<=>?", 548 "\@ABCDEFGHIJKLMNO", 549 "PQRSTUVWXYZ[\\]^_", 550 "`abcdefghijklmno", 551 "pqrstuvwxyz{|}~\177", 552 "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217", 553 "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237", 554 "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257", 555 "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277", 556 "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317", 557 "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337", 558 "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357", 559 "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" 560 ], 561 }, 562 { name => 'Quoted hash keys', 563 in => [ 564 '---', 565 ' "quoted": Magic!', 566 ' "\n\t": newline, tab', 567 '...', 568 ], 569 out => { 570 quoted => 'Magic!', 571 "\n\t" => 'newline, tab', 572 }, 573 }, 574 { name => 'Empty', 575 in => [], 576 out => undef, 577 }, 578 ); 579 580 plan tests => @SCHEDULE * 5; 581} 582 583sub iter { 584 my $ar = shift; 585 return sub { 586 return shift @$ar; 587 }; 588} 589 590for my $test (@SCHEDULE) { 591 my $name = $test->{name}; 592 ok my $yaml = TAP::Parser::YAMLish::Reader->new, "$name: Created"; 593 isa_ok $yaml, 'TAP::Parser::YAMLish::Reader'; 594 595 my $source = join( "\n", @{ $test->{in} } ) . "\n"; 596 597 my $iter = iter( $test->{in} ); 598 my $got = eval { $yaml->read($iter) }; 599 600 my $raw = $yaml->get_raw; 601 602 if ( my $err = $test->{error} ) { 603 unless ( like $@, $err, "$name: Error message" ) { 604 diag "Error: $@\n"; 605 } 606 ok !$got, "$name: No result"; 607 pass; 608 } 609 else { 610 my $want = $test->{out}; 611 unless ( ok !$@, "$name: No error" ) { 612 diag "Error: $@\n"; 613 } 614 is_deeply $got, $want, "$name: Result matches"; 615 is $raw, $source, "$name: Captured source matches"; 616 } 617} 618