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