1#!/usr/bin/perl -w 2 3use strict; 4 5BEGIN { 6 use lib 't/lib'; 7} 8 9use Test::More tests => 294; 10use IO::c55Capture; 11 12use File::Spec; 13 14use TAP::Parser; 15use TAP::Parser::Iterator::Array; 16 17sub _get_results { 18 my $parser = shift; 19 my @results; 20 while ( defined( my $result = $parser->next ) ) { 21 push @results => $result; 22 } 23 return @results; 24} 25 26my ( $PARSER, $PLAN, $PRAGMA, $TEST, $COMMENT, $BAILOUT, $UNKNOWN, $YAML, $VERSION ) = qw( 27 TAP::Parser 28 TAP::Parser::Result::Plan 29 TAP::Parser::Result::Pragma 30 TAP::Parser::Result::Test 31 TAP::Parser::Result::Comment 32 TAP::Parser::Result::Bailout 33 TAP::Parser::Result::Unknown 34 TAP::Parser::Result::YAML 35 TAP::Parser::Result::Version 36); 37 38my $tap = <<'END_TAP'; 39TAP version 13 401..7 41ok 1 - input file opened 42... this is junk 43not ok first line of the input valid # todo some data 44# this is a comment 45ok 3 - read the rest of the file 46not ok 4 - this is a real failure 47 --- YAML! 48 ... 49ok 5 # skip we have no description 50ok 6 - you shall not pass! # TODO should have failed 51not ok 7 - Gandalf wins. Game over. # TODO 'bout time! 52END_TAP 53 54can_ok $PARSER, 'new'; 55my $parser = $PARSER->new( { tap => $tap } ); 56isa_ok $parser, $PARSER, '... and the object it returns'; 57 58ok $ENV{TAP_VERSION}, 'TAP_VERSION env variable should be set'; 59 60# results() is sane? 61 62my @results = _get_results($parser); 63is scalar @results, 12, '... and there should be one for each line'; 64 65my $version = shift @results; 66isa_ok $version, $VERSION; 67is $version->version, '13', '... and the version should be 13'; 68 69# check the test plan 70 71my $result = shift @results; 72isa_ok $result, $PLAN; 73can_ok $result, 'type'; 74is $result->type, 'plan', '... and it should report the correct type'; 75ok $result->is_plan, '... and it should identify itself as a plan'; 76is $result->plan, '1..7', '... and identify the plan'; 77ok !$result->directive, '... and this plan should not have a directive'; 78ok !$result->explanation, '... or a directive explanation'; 79is $result->as_string, '1..7', 80 '... and have the correct string representation'; 81is $result->raw, '1..7', '... and raw() should return the original line'; 82 83# a normal, passing test 84 85my $test = shift @results; 86isa_ok $test, $TEST; 87is $test->type, 'test', '... and it should report the correct type'; 88ok $test->is_test, '... and it should identify itself as a test'; 89is $test->ok, 'ok', '... and it should have the correct ok()'; 90ok $test->is_ok, '... and the correct boolean version of is_ok()'; 91ok $test->is_actual_ok, 92 '... and the correct boolean version of is_actual_ok()'; 93is $test->number, 1, '... and have the correct test number'; 94is $test->description, '- input file opened', 95 '... and the correct description'; 96ok !$test->directive, '... and not have a directive'; 97ok !$test->explanation, '... or a directive explanation'; 98ok !$test->has_skip, '... and it is not a SKIPped test'; 99ok !$test->has_todo, '... nor a TODO test'; 100is $test->as_string, 'ok 1 - input file opened', 101 '... and its string representation should be correct'; 102is $test->raw, 'ok 1 - input file opened', 103 '... and raw() should return the original line'; 104 105# junk lines should be preserved 106 107my $unknown = shift @results; 108isa_ok $unknown, $UNKNOWN; 109is $unknown->type, 'unknown', '... and it should report the correct type'; 110ok $unknown->is_unknown, '... and it should identify itself as unknown'; 111is $unknown->as_string, '... this is junk', 112 '... and its string representation should be returned verbatim'; 113is $unknown->raw, '... this is junk', 114 '... and raw() should return the original line'; 115 116# a failing test, which also happens to have a directive 117 118my $failed = shift @results; 119isa_ok $failed, $TEST; 120is $failed->type, 'test', '... and it should report the correct type'; 121ok $failed->is_test, '... and it should identify itself as a test'; 122is $failed->ok, 'not ok', '... and it should have the correct ok()'; 123ok $failed->is_ok, '... and TODO tests should always pass'; 124ok !$failed->is_actual_ok, 125 '... and the correct boolean version of is_actual_ok ()'; 126is $failed->number, 2, '... and have the correct failed number'; 127is $failed->description, 'first line of the input valid', 128 '... and the correct description'; 129is $failed->directive, 'TODO', '... and should have the correct directive'; 130is $failed->explanation, 'some data', 131 '... and the correct directive explanation'; 132ok !$failed->has_skip, '... and it is not a SKIPped failed'; 133ok $failed->has_todo, '... but it is a TODO succeeded'; 134is $failed->as_string, 135 'not ok 2 first line of the input valid # TODO some data', 136 '... and its string representation should be correct'; 137is $failed->raw, 'not ok first line of the input valid # todo some data', 138 '... and raw() should return the original line'; 139 140# comments 141 142my $comment = shift @results; 143isa_ok $comment, $COMMENT; 144is $comment->type, 'comment', '... and it should report the correct type'; 145ok $comment->is_comment, '... and it should identify itself as a comment'; 146is $comment->comment, 'this is a comment', 147 '... and you should be able to fetch the comment'; 148is $comment->as_string, '# this is a comment', 149 '... and have the correct string representation'; 150is $comment->raw, '# this is a comment', 151 '... and raw() should return the original line'; 152 153# another normal, passing test 154 155$test = shift @results; 156isa_ok $test, $TEST; 157is $test->type, 'test', '... and it should report the correct type'; 158ok $test->is_test, '... and it should identify itself as a test'; 159is $test->ok, 'ok', '... and it should have the correct ok()'; 160ok $test->is_ok, '... and the correct boolean version of is_ok()'; 161ok $test->is_actual_ok, 162 '... and the correct boolean version of is_actual_ok()'; 163is $test->number, 3, '... and have the correct test number'; 164is $test->description, '- read the rest of the file', 165 '... and the correct description'; 166ok !$test->directive, '... and not have a directive'; 167ok !$test->explanation, '... or a directive explanation'; 168ok !$test->has_skip, '... and it is not a SKIPped test'; 169ok !$test->has_todo, '... nor a TODO test'; 170is $test->as_string, 'ok 3 - read the rest of the file', 171 '... and its string representation should be correct'; 172is $test->raw, 'ok 3 - read the rest of the file', 173 '... and raw() should return the original line'; 174 175# a failing test 176 177$failed = shift @results; 178isa_ok $failed, $TEST; 179is $failed->type, 'test', '... and it should report the correct type'; 180ok $failed->is_test, '... and it should identify itself as a test'; 181is $failed->ok, 'not ok', '... and it should have the correct ok()'; 182ok !$failed->is_ok, '... and the tests should not have passed'; 183ok !$failed->is_actual_ok, 184 '... and the correct boolean version of is_actual_ok ()'; 185is $failed->number, 4, '... and have the correct failed number'; 186is $failed->description, '- this is a real failure', 187 '... and the correct description'; 188ok !$failed->directive, '... and should have no directive'; 189ok !$failed->explanation, '... and no directive explanation'; 190ok !$failed->has_skip, '... and it is not a SKIPped failed'; 191ok !$failed->has_todo, '... and not a TODO test'; 192is $failed->as_string, 'not ok 4 - this is a real failure', 193 '... and its string representation should be correct'; 194is $failed->raw, 'not ok 4 - this is a real failure', 195 '... and raw() should return the original line'; 196 197# Some YAML 198my $yaml = shift @results; 199isa_ok $yaml, $YAML; 200is $yaml->type, 'yaml', '... and it should report the correct type'; 201ok $yaml->is_yaml, '... and it should identify itself as yaml'; 202is_deeply $yaml->data, 'YAML!', '... and data should be correct'; 203 204# ok 5 # skip we have no description 205# skipped test 206 207$test = shift @results; 208isa_ok $test, $TEST; 209is $test->type, 'test', '... and it should report the correct type'; 210ok $test->is_test, '... and it should identify itself as a test'; 211is $test->ok, 'ok', '... and it should have the correct ok()'; 212ok $test->is_ok, '... and the correct boolean version of is_ok()'; 213ok $test->is_actual_ok, 214 '... and the correct boolean version of is_actual_ok()'; 215is $test->number, 5, '... and have the correct test number'; 216ok !$test->description, '... and skipped tests have no description'; 217is $test->directive, 'SKIP', '... and the correct directive'; 218is $test->explanation, 'we have no description', 219 '... but we should have an explanation'; 220ok $test->has_skip, '... and it is a SKIPped test'; 221ok !$test->has_todo, '... but not a TODO test'; 222is $test->as_string, 'ok 5 # SKIP we have no description', 223 '... and its string representation should be correct'; 224is $test->raw, 'ok 5 # skip we have no description', 225 '... and raw() should return the original line'; 226 227# a failing test, which also happens to have a directive 228# ok 6 - you shall not pass! # TODO should have failed 229 230my $bonus = shift @results; 231isa_ok $bonus, $TEST; 232can_ok $bonus, 'todo_passed'; 233is $bonus->type, 'test', 'TODO tests should parse correctly'; 234ok $bonus->is_test, '... and it should identify itself as a test'; 235is $bonus->ok, 'ok', '... and it should have the correct ok()'; 236ok $bonus->is_ok, '... and TODO tests should not always pass'; 237ok $bonus->is_actual_ok, 238 '... and the correct boolean version of is_actual_ok ()'; 239is $bonus->number, 6, '... and have the correct failed number'; 240is $bonus->description, '- you shall not pass!', 241 '... and the correct description'; 242is $bonus->directive, 'TODO', '... and should have the correct directive'; 243is $bonus->explanation, 'should have failed', 244 '... and the correct directive explanation'; 245ok !$bonus->has_skip, '... and it is not a SKIPped failed'; 246ok $bonus->has_todo, '... but it is a TODO succeeded'; 247is $bonus->as_string, 'ok 6 - you shall not pass! # TODO should have failed', 248 '... and its string representation should be correct'; 249is $bonus->raw, 'ok 6 - you shall not pass! # TODO should have failed', 250 '... and raw() should return the original line'; 251ok $bonus->todo_passed, 252 '... todo_bonus() should pass for TODO tests which unexpectedly succeed'; 253 254# not ok 7 - Gandalf wins. Game over. # TODO 'bout time! 255 256my $passed = shift @results; 257isa_ok $passed, $TEST; 258can_ok $passed, 'todo_passed'; 259is $passed->type, 'test', 'TODO tests should parse correctly'; 260ok $passed->is_test, '... and it should identify itself as a test'; 261is $passed->ok, 'not ok', '... and it should have the correct ok()'; 262ok $passed->is_ok, '... and TODO tests should always pass'; 263ok !$passed->is_actual_ok, 264 '... and the correct boolean version of is_actual_ok ()'; 265is $passed->number, 7, '... and have the correct passed number'; 266is $passed->description, '- Gandalf wins. Game over.', 267 '... and the correct description'; 268is $passed->directive, 'TODO', '... and should have the correct directive'; 269is $passed->explanation, "'bout time!", 270 '... and the correct directive explanation'; 271ok !$passed->has_skip, '... and it is not a SKIPped passed'; 272ok $passed->has_todo, '... but it is a TODO succeeded'; 273is $passed->as_string, 274 "not ok 7 - Gandalf wins. Game over. # TODO 'bout time!", 275 '... and its string representation should be correct'; 276is $passed->raw, "not ok 7 - Gandalf wins. Game over. # TODO 'bout time!", 277 '... and raw() should return the original line'; 278ok !$passed->todo_passed, 279 '... todo_passed() should not pass for TODO tests which failed'; 280 281# test parse results 282 283can_ok $parser, 'passed'; 284is $parser->passed, 6, 285 '... and we should have the correct number of passed tests'; 286is_deeply [ $parser->passed ], [ 1, 2, 3, 5, 6, 7 ], 287 '... and get a list of the passed tests'; 288 289can_ok $parser, 'failed'; 290is $parser->failed, 1, '... and the correct number of failed tests'; 291is_deeply [ $parser->failed ], [4], '... and get a list of the failed tests'; 292 293can_ok $parser, 'actual_passed'; 294is $parser->actual_passed, 4, 295 '... and we should have the correct number of actually passed tests'; 296is_deeply [ $parser->actual_passed ], [ 1, 3, 5, 6 ], 297 '... and get a list of the actually passed tests'; 298 299can_ok $parser, 'actual_failed'; 300is $parser->actual_failed, 3, 301 '... and the correct number of actually failed tests'; 302is_deeply [ $parser->actual_failed ], [ 2, 4, 7 ], 303 '... or get a list of the actually failed tests'; 304 305can_ok $parser, 'todo'; 306is $parser->todo, 3, 307 '... and we should have the correct number of TODO tests'; 308is_deeply [ $parser->todo ], [ 2, 6, 7 ], 309 '... and get a list of the TODO tests'; 310 311can_ok $parser, 'skipped'; 312is $parser->skipped, 1, 313 '... and we should have the correct number of skipped tests'; 314is_deeply [ $parser->skipped ], [5], 315 '... and get a list of the skipped tests'; 316 317# check the plan 318 319can_ok $parser, 'plan'; 320is $parser->plan, '1..7', '... and we should have the correct plan'; 321is $parser->tests_planned, 7, '... and the correct number of tests'; 322 323# "Unexpectedly succeeded" 324can_ok $parser, 'todo_passed'; 325is scalar $parser->todo_passed, 1, 326 '... and it should report the number of tests which unexpectedly succeeded'; 327is_deeply [ $parser->todo_passed ], [6], 328 '... or *which* tests unexpectedly succeeded'; 329 330# 331# Bug report from Torsten Schoenfeld 332# Makes sure parser can handle blank lines 333# 334 335$tap = <<'END_TAP'; 3361..2 337ok 1 - input file opened 338 339 340ok 2 - read the rest of the file 341END_TAP 342 343my $aref = [ split /\n/ => $tap ]; 344 345can_ok $PARSER, 'new'; 346$parser 347 = $PARSER->new( { iterator => TAP::Parser::Iterator::Array->new($aref) } ); 348isa_ok $parser, $PARSER, '... and calling it should succeed'; 349 350# results() is sane? 351 352ok @results = _get_results($parser), 'The parser should return results'; 353is scalar @results, 5, '... and there should be one for each line'; 354 355# check the test plan 356 357$result = shift @results; 358isa_ok $result, $PLAN; 359can_ok $result, 'type'; 360is $result->type, 'plan', '... and it should report the correct type'; 361ok $result->is_plan, '... and it should identify itself as a plan'; 362is $result->plan, '1..2', '... and identify the plan'; 363is $result->as_string, '1..2', 364 '... and have the correct string representation'; 365is $result->raw, '1..2', '... and raw() should return the original line'; 366 367# a normal, passing test 368 369$test = shift @results; 370isa_ok $test, $TEST; 371is $test->type, 'test', '... and it should report the correct type'; 372ok $test->is_test, '... and it should identify itself as a test'; 373is $test->ok, 'ok', '... and it should have the correct ok()'; 374ok $test->is_ok, '... and the correct boolean version of is_ok()'; 375ok $test->is_actual_ok, 376 '... and the correct boolean version of is_actual_ok()'; 377is $test->number, 1, '... and have the correct test number'; 378is $test->description, '- input file opened', 379 '... and the correct description'; 380ok !$test->directive, '... and not have a directive'; 381ok !$test->explanation, '... or a directive explanation'; 382ok !$test->has_skip, '... and it is not a SKIPped test'; 383ok !$test->has_todo, '... nor a TODO test'; 384is $test->as_string, 'ok 1 - input file opened', 385 '... and its string representation should be correct'; 386is $test->raw, 'ok 1 - input file opened', 387 '... and raw() should return the original line'; 388 389# junk lines should be preserved 390 391$unknown = shift @results; 392isa_ok $unknown, $UNKNOWN; 393is $unknown->type, 'unknown', '... and it should report the correct type'; 394ok $unknown->is_unknown, '... and it should identify itself as unknown'; 395is $unknown->as_string, '', 396 '... and its string representation should be returned verbatim'; 397is $unknown->raw, '', '... and raw() should return the original line'; 398 399# ... and the second empty line 400 401$unknown = shift @results; 402isa_ok $unknown, $UNKNOWN; 403is $unknown->type, 'unknown', '... and it should report the correct type'; 404ok $unknown->is_unknown, '... and it should identify itself as unknown'; 405is $unknown->as_string, '', 406 '... and its string representation should be returned verbatim'; 407is $unknown->raw, '', '... and raw() should return the original line'; 408 409# a passing test 410 411$test = shift @results; 412isa_ok $test, $TEST; 413is $test->type, 'test', '... and it should report the correct type'; 414ok $test->is_test, '... and it should identify itself as a test'; 415is $test->ok, 'ok', '... and it should have the correct ok()'; 416ok $test->is_ok, '... and the correct boolean version of is_ok()'; 417ok $test->is_actual_ok, 418 '... and the correct boolean version of is_actual_ok()'; 419is $test->number, 2, '... and have the correct test number'; 420is $test->description, '- read the rest of the file', 421 '... and the correct description'; 422ok !$test->directive, '... and not have a directive'; 423ok !$test->explanation, '... or a directive explanation'; 424ok !$test->has_skip, '... and it is not a SKIPped test'; 425ok !$test->has_todo, '... nor a TODO test'; 426is $test->as_string, 'ok 2 - read the rest of the file', 427 '... and its string representation should be correct'; 428is $test->raw, 'ok 2 - read the rest of the file', 429 '... and raw() should return the original line'; 430 431is scalar $parser->passed, 2, 432 'Empty junk lines should not affect the correct number of tests passed'; 433 434# Check source => "tap content" 435can_ok $PARSER, 'new'; 436$parser = $PARSER->new( { source => "1..1\nok 1\n" } ); 437isa_ok $parser, $PARSER, '... and calling it should succeed'; 438ok @results = _get_results($parser), 'The parser should return results'; 439is( scalar @results, 2, "Got two lines of TAP" ); 440 441# Check source => [array] 442can_ok $PARSER, 'new'; 443$parser = $PARSER->new( { source => [ "1..1", "ok 1" ] } ); 444isa_ok $parser, $PARSER, '... and calling it should succeed'; 445ok @results = _get_results($parser), 'The parser should return results'; 446is( scalar @results, 2, "Got two lines of TAP" ); 447 448# Check source => $filehandle 449can_ok $PARSER, 'new'; 450open my $fh, 't/data/catme.1'; 451$parser = $PARSER->new( { source => $fh } ); 452isa_ok $parser, $PARSER, '... and calling it should succeed'; 453ok @results = _get_results($parser), 'The parser should return results'; 454is( scalar @results, 2, "Got two lines of TAP" ); 455 456{ 457 458 # set a spool to write to 459 tie local *SPOOL, 'IO::c55Capture'; 460 461 my $tap = <<'END_TAP'; 462TAP version 13 4631..7 464ok 1 - input file opened 465... this is junk 466not ok first line of the input valid # todo some data 467# this is a comment 468ok 3 - read the rest of the file 469not ok 4 - this is a real failure 470 --- YAML! 471 ... 472ok 5 # skip we have no description 473ok 6 - you shall not pass! # TODO should have failed 474not ok 7 - Gandalf wins. Game over. # TODO 'bout time! 475END_TAP 476 477 { 478 my $parser = $PARSER->new( 479 { tap => $tap, 480 spool => \*SPOOL, 481 } 482 ); 483 484 _get_results($parser); 485 486 my @spooled = tied(*SPOOL)->dump(); 487 488 is @spooled, 24, 'coverage testing for spool attribute of parser'; 489 is join( '', @spooled ), $tap, "spooled tap matches"; 490 } 491 492 { 493 my $parser = $PARSER->new( 494 { tap => $tap, 495 spool => \*SPOOL, 496 } 497 ); 498 499 $parser->callback( 'ALL', sub { } ); 500 501 _get_results($parser); 502 503 my @spooled = tied(*SPOOL)->dump(); 504 505 is @spooled, 24, 'coverage testing for spool attribute of parser'; 506 is join( '', @spooled ), $tap, "spooled tap matches"; 507 } 508} 509 510{ 511 512 # _initialize coverage 513 514 my $x = bless [], 'kjsfhkjsdhf'; 515 516 my @die; 517 518 eval { 519 local $SIG{__DIE__} = sub { push @die, @_ }; 520 521 $PARSER->new(); 522 }; 523 524 is @die, 1, 'coverage testing for _initialize'; 525 526 like pop @die, qr/PANIC:\s+could not determine iterator for input\s*at/, 527 '...and it failed as expected'; 528 529 @die = (); 530 531 eval { 532 local $SIG{__DIE__} = sub { push @die, @_ }; 533 534 $PARSER->new( 535 { iterator => 'iterator', 536 tap => 'tap', 537 source => 'source', # only one of these is allowed 538 } 539 ); 540 }; 541 542 is @die, 1, 'coverage testing for _initialize'; 543 544 like pop @die, 545 qr/You may only choose one of 'exec', 'tap', 'source' or 'iterator'/, 546 '...and it failed as expected'; 547} 548 549{ 550 551 # coverage of todo_failed 552 553 my $tap = <<'END_TAP'; 554TAP version 13 5551..7 556ok 1 - input file opened 557... this is junk 558not ok first line of the input valid # todo some data 559# this is a comment 560ok 3 - read the rest of the file 561not ok 4 - this is a real failure 562 --- YAML! 563 ... 564ok 5 # skip we have no description 565ok 6 - you shall not pass! # TODO should have failed 566not ok 7 - Gandalf wins. Game over. # TODO 'bout time! 567END_TAP 568 569 my $parser = $PARSER->new( { tap => $tap } ); 570 571 _get_results($parser); 572 573 my @warn; 574 575 eval { 576 local $SIG{__WARN__} = sub { push @warn, @_ }; 577 578 $parser->todo_failed; 579 }; 580 581 is @warn, 1, 'coverage testing of todo_failed'; 582 583 like pop @warn, 584 qr/"todo_failed" is deprecated. Please use "todo_passed". See the docs[.]/, 585 '..and failed as expected' 586} 587 588{ 589 590 # coverage testing for T::P::_initialize 591 592 # coverage of the source argument paths 593 594 # ref argument to source 595 596 my $parser = TAP::Parser->new( { source => [ split /$/, $tap ] } ); 597 598 isa_ok $parser, 'TAP::Parser'; 599 600 isa_ok $parser->_iterator, 'TAP::Parser::Iterator::Array'; 601 602 SKIP: { 603 skip 'Segfaults Perl 5.6.0' => 2 if $] <= 5.006000; 604 605 # uncategorisable argument to source 606 my @die; 607 608 eval { 609 local $SIG{__DIE__} = sub { push @die, @_ }; 610 611 $parser = TAP::Parser->new( { source => 'nosuchfile' } ); 612 }; 613 614 is @die, 1, 'uncategorisable source'; 615 616 like pop @die, qr/Cannot detect source of 'nosuchfile'/, 617 '... and we died as expected'; 618 } 619} 620 621{ 622 623 # coverage test of perl source with switches 624 625 my $parser = TAP::Parser->new( 626 { source => File::Spec->catfile( 627 't', 628 'sample-tests', 629 'simple' 630 ), 631 } 632 ); 633 634 isa_ok $parser, 'TAP::Parser'; 635 636 isa_ok $parser->_iterator, 'TAP::Parser::Iterator::Process'; 637 638 # Workaround for Mac OS X problem wrt closing the iterator without 639 # reading from it. 640 $parser->next; 641} 642 643{ 644 645 # coverage testing for TAP::Parser::has_problems 646 647 # we're going to need to test lots of fragments of tap 648 # to cover all the different boolean tests 649 650 # currently covered are no problems and failed, so let's next test 651 # todo_passed 652 653 my $tap = <<'END_TAP'; 654TAP version 13 6551..2 656ok 1 - input file opened 657ok 2 - Gandalf wins. Game over. # TODO 'bout time! 658END_TAP 659 660 my $parser = TAP::Parser->new( { tap => $tap } ); 661 662 _get_results($parser); 663 664 ok !$parser->failed, 'parser didnt fail'; 665 ok $parser->todo_passed, '... and todo_passed is true'; 666 667 ok !$parser->has_problems, '... and has_problems is false'; 668 669 # now parse_errors 670 671 $tap = <<'END_TAP'; 672TAP version 13 6731..2 674SMACK 675END_TAP 676 677 $parser = TAP::Parser->new( { tap => $tap } ); 678 679 _get_results($parser); 680 681 ok !$parser->failed, 'parser didnt fail'; 682 ok !$parser->todo_passed, '... and todo_passed is false'; 683 ok $parser->parse_errors, '... and parse_errors is true'; 684 685 ok $parser->has_problems, '... and has_problems'; 686 687 # Now wait and exit are hard to do in an OS platform-independent way, so 688 # we won't even bother 689 690 $tap = <<'END_TAP'; 691TAP version 13 6921..2 693ok 1 - input file opened 694ok 2 - Gandalf wins 695END_TAP 696 697 $parser = TAP::Parser->new( { tap => $tap } ); 698 699 _get_results($parser); 700 701 $parser->wait(1); 702 703 ok !$parser->failed, 'parser didnt fail'; 704 ok !$parser->todo_passed, '... and todo_passed is false'; 705 ok !$parser->parse_errors, '... and parse_errors is false'; 706 707 ok $parser->wait, '... and wait is set'; 708 709 ok $parser->has_problems, '... and has_problems'; 710 711 # and use the same for exit 712 713 $parser->wait(0); 714 $parser->exit(1); 715 716 ok !$parser->failed, 'parser didnt fail'; 717 ok !$parser->todo_passed, '... and todo_passed is false'; 718 ok !$parser->parse_errors, '... and parse_errors is false'; 719 ok !$parser->wait, '... and wait is not set'; 720 721 ok $parser->exit, '... and exit is set'; 722 723 ok $parser->has_problems, '... and has_problems'; 724} 725 726{ 727 728 # coverage testing of the version states 729 730 my $tap = <<'END_TAP'; 731TAP version 12 7321..2 733ok 1 - input file opened 734ok 2 - Gandalf wins 735END_TAP 736 737 my $parser = TAP::Parser->new( { tap => $tap } ); 738 739 _get_results($parser); 740 741 my @errors = $parser->parse_errors; 742 743 is @errors, 1, 'test too low version number'; 744 745 like pop @errors, 746 qr/Explicit TAP version must be at least 13. Got version 12/, 747 '... and trapped expected version error'; 748 749 # now too high a version 750 $tap = <<'END_TAP'; 751TAP version 14 7521..2 753ok 1 - input file opened 754ok 2 - Gandalf wins 755END_TAP 756 757 $parser = TAP::Parser->new( { tap => $tap } ); 758 759 _get_results($parser); 760 761 @errors = $parser->parse_errors; 762 763 is @errors, 1, 'test too high version number'; 764 765 like pop @errors, 766 qr/TAP specified version 14 but we don't know about versions later than 13/, 767 '... and trapped expected version error'; 768} 769 770{ 771 772 # coverage testing of TAP version in the wrong place 773 774 my $tap = <<'END_TAP'; 7751..2 776ok 1 - input file opened 777TAP version 12 778ok 2 - Gandalf wins 779END_TAP 780 781 my $parser = TAP::Parser->new( { tap => $tap } ); 782 783 _get_results($parser); 784 785 my @errors = $parser->parse_errors; 786 787 is @errors, 1, 'test TAP version number in wrong place'; 788 789 like pop @errors, 790 qr/If TAP version is present it must be the first line of output/, 791 '... and trapped expected version error'; 792 793} 794 795{ 796 797 # we're going to bash the internals a bit (but using the API as 798 # much as possible) to force grammar->tokenise() to fail 799 800# firstly we'll create a iterator that dies when its next_raw method is called 801 802 package TAP::Parser::Iterator::Dies; 803 804 use strict; 805 use vars qw(@ISA); 806 807 @ISA = qw(TAP::Parser::Iterator); 808 809 sub next_raw { 810 die 'this is the dying iterator'; 811 } 812 813 # required as part of the TPI interface 814 sub exit { } 815 sub wait { } 816 817 package main; 818 819 # now build a standard parser 820 821 my $tap = <<'END_TAP'; 8221..2 823ok 1 - input file opened 824ok 2 - Gandalf wins 825END_TAP 826 827 { 828 my $parser = TAP::Parser->new( { tap => $tap } ); 829 830 # build a dying iterator 831 my $iterator = TAP::Parser::Iterator::Dies->new; 832 833 # now replace the iterator - we're forced to us an T::P intenal 834 # method for this 835 $parser->_iterator($iterator); 836 837 # build a new grammar 838 my $grammar = TAP::Parser::Grammar->new( 839 { iterator => $iterator, 840 parser => $parser 841 } 842 ); 843 844 # replace our grammar with this new one 845 $parser->_grammar($grammar); 846 847 # now call next on the parser, and the grammar should die 848 my $result = $parser->next; # will die in iterator 849 850 is $result, undef, 'iterator dies'; 851 852 my @errors = $parser->parse_errors; 853 is @errors, 2, '...and caught expected errrors'; 854 855 like shift @errors, qr/this is the dying iterator/, 856 '...and it was what we expected'; 857 } 858 859 # Do it all again with callbacks to exercise the other code path in 860 # the unrolled iterator 861 { 862 my $parser = TAP::Parser->new( { tap => $tap } ); 863 864 $parser->callback( 'ALL', sub { } ); 865 866 # build a dying iterator 867 my $iterator = TAP::Parser::Iterator::Dies->new; 868 869 # now replace the iterator - we're forced to us an T::P intenal 870 # method for this 871 $parser->_iterator($iterator); 872 873 # build a new grammar 874 my $grammar = TAP::Parser::Grammar->new( 875 { iterator => $iterator, 876 parser => $parser 877 } 878 ); 879 880 # replace our grammar with this new one 881 $parser->_grammar($grammar); 882 883 # now call next on the parser, and the grammar should die 884 my $result = $parser->next; # will die in iterator 885 886 is $result, undef, 'iterator dies'; 887 888 my @errors = $parser->parse_errors; 889 is @errors, 2, '...and caught expected errrors'; 890 891 like shift @errors, qr/this is the dying iterator/, 892 '...and it was what we expected'; 893 } 894} 895 896{ 897 898 # coverage testing of TAP::Parser::_next_state 899 900 package TAP::Parser::WithBrokenState; 901 use vars qw(@ISA); 902 903 @ISA = qw( TAP::Parser ); 904 905 sub _make_state_table { 906 return { INIT => { plan => { goto => 'FOO' } } }; 907 } 908 909 package main; 910 911 my $tap = <<'END_TAP'; 9121..2 913ok 1 - input file opened 914ok 2 - Gandalf wins 915END_TAP 916 917 my $parser = TAP::Parser::WithBrokenState->new( { tap => $tap } ); 918 919 my @die; 920 921 eval { 922 local $SIG{__DIE__} = sub { push @die, @_ }; 923 924 $parser->next; 925 $parser->next; 926 }; 927 928 is @die, 1, 'detect broken state machine'; 929 930 like pop @die, qr/Illegal state: FOO/, 931 '...and the message is as we expect'; 932} 933 934{ 935 936 # coverage testing of TAP::Parser::_iter 937 938 package TAP::Parser::WithBrokenIter; 939 use vars qw(@ISA); 940 941 @ISA = qw( TAP::Parser ); 942 943 sub _iter {return} 944 945 package main; 946 947 my $tap = <<'END_TAP'; 9481..2 949ok 1 - input file opened 950ok 2 - Gandalf wins 951END_TAP 952 953 my $parser = TAP::Parser::WithBrokenIter->new( { tap => $tap } ); 954 955 my @die; 956 957 eval { 958 local $SIG{__WARN__} = sub { }; 959 local $SIG{__DIE__} = sub { push @die, @_ }; 960 961 $parser->next; 962 }; 963 964 is @die, 1, 'detect broken iter'; 965 966 like pop @die, qr/Can't use/, '...and the message is as we expect'; 967} 968 969SKIP: { 970 971 # http://markmail.org/message/rkxbo6ft7yorgnzb 972 skip "Crashes on older Perls", 2 if $] <= 5.008004 || $] == 5.009; 973 974 # coverage testing of TAP::Parser::_finish 975 976 my $tap = <<'END_TAP'; 9771..2 978ok 1 - input file opened 979ok 2 - Gandalf wins 980END_TAP 981 982 my $parser = TAP::Parser->new( { tap => $tap } ); 983 984 $parser->tests_run(999); 985 986 my @die; 987 988 eval { 989 local $SIG{__DIE__} = sub { push @die, @_ }; 990 991 _get_results $parser; 992 }; 993 994 is @die, 1, 'detect broken test counts'; 995 996 like pop @die, 997 qr/Panic: planned test count [(]1001[)] did not equal sum of passed [(]0[)] and failed [(]2[)] tests!/, 998 '...and the message is as we expect'; 999} 1000 1001{ 1002 1003 # Sanity check on state table 1004 1005 my $parser = TAP::Parser->new( { tap => "1..1\nok 1\n" } ); 1006 my $state_table = $parser->_make_state_table; 1007 my @states = sort keys %$state_table; 1008 my @expect = sort qw( 1009 bailout comment plan pragma test unknown version yaml 1010 ); 1011 1012 my %reachable = ( INIT => 1 ); 1013 1014 for my $name (@states) { 1015 my $state = $state_table->{$name}; 1016 my @can_handle = sort keys %$state; 1017 is_deeply \@can_handle, \@expect, "token types handled in $name"; 1018 for my $type (@can_handle) { 1019 $reachable{$_}++ 1020 for grep {defined} 1021 map { $state->{$type}->{$_} } qw(goto continue); 1022 } 1023 } 1024 1025 is_deeply [ sort keys %reachable ], [@states], "all states reachable"; 1026} 1027 1028{ 1029 1030 # exit, wait, ignore_exit interactions 1031 1032 my @truth = ( 1033 [ 0, 0, 0, 0 ], 1034 [ 0, 0, 1, 0 ], 1035 [ 1, 0, 0, 1 ], 1036 [ 1, 0, 1, 0 ], 1037 [ 1, 1, 0, 1 ], 1038 [ 1, 1, 1, 0 ], 1039 [ 0, 1, 0, 1 ], 1040 [ 0, 1, 1, 0 ], 1041 ); 1042 1043 for my $t (@truth) { 1044 my ( $wait, $exit, $ignore_exit, $has_problems ) = @$t; 1045 my $test_parser = sub { 1046 my $parser = shift; 1047 $parser->wait($wait); 1048 $parser->exit($exit); 1049 ok $has_problems ? $parser->has_problems : !$parser->has_problems, 1050 "exit=$exit, wait=$wait, ignore=$ignore_exit"; 1051 }; 1052 1053 my $parser = TAP::Parser->new( { tap => "1..1\nok 1\n" } ); 1054 $parser->ignore_exit($ignore_exit); 1055 $test_parser->($parser); 1056 1057 $test_parser->( 1058 TAP::Parser->new( 1059 { tap => "1..1\nok 1\n", ignore_exit => $ignore_exit } 1060 ) 1061 ); 1062 } 1063} 1064