blob: 9cf59134034816ad8a4d1dfbff39af8d515e2688 [file] [log] [blame]
#!/usr/bin/perl -w
use strict;
BEGIN {
use lib 't/lib';
}
use Test::More tests => 294;
use IO::c55Capture;
use File::Spec;
use TAP::Parser;
use TAP::Parser::Iterator::Array;
sub _get_results {
my $parser = shift;
my @results;
while ( defined( my $result = $parser->next ) ) {
push @results => $result;
}
return @results;
}
my ( $PARSER, $PLAN, $PRAGMA, $TEST, $COMMENT, $BAILOUT, $UNKNOWN, $YAML, $VERSION ) = qw(
TAP::Parser
TAP::Parser::Result::Plan
TAP::Parser::Result::Pragma
TAP::Parser::Result::Test
TAP::Parser::Result::Comment
TAP::Parser::Result::Bailout
TAP::Parser::Result::Unknown
TAP::Parser::Result::YAML
TAP::Parser::Result::Version
);
my $tap = <<'END_TAP';
TAP version 13
1..7
ok 1 - input file opened
... this is junk
not ok first line of the input valid # todo some data
# this is a comment
ok 3 - read the rest of the file
not ok 4 - this is a real failure
--- YAML!
...
ok 5 # skip we have no description
ok 6 - you shall not pass! # TODO should have failed
not ok 7 - Gandalf wins. Game over. # TODO 'bout time!
END_TAP
can_ok $PARSER, 'new';
my $parser = $PARSER->new( { tap => $tap } );
isa_ok $parser, $PARSER, '... and the object it returns';
ok $ENV{TAP_VERSION}, 'TAP_VERSION env variable should be set';
# results() is sane?
my @results = _get_results($parser);
is scalar @results, 12, '... and there should be one for each line';
my $version = shift @results;
isa_ok $version, $VERSION;
is $version->version, '13', '... and the version should be 13';
# check the test plan
my $result = shift @results;
isa_ok $result, $PLAN;
can_ok $result, 'type';
is $result->type, 'plan', '... and it should report the correct type';
ok $result->is_plan, '... and it should identify itself as a plan';
is $result->plan, '1..7', '... and identify the plan';
ok !$result->directive, '... and this plan should not have a directive';
ok !$result->explanation, '... or a directive explanation';
is $result->as_string, '1..7',
'... and have the correct string representation';
is $result->raw, '1..7', '... and raw() should return the original line';
# a normal, passing test
my $test = shift @results;
isa_ok $test, $TEST;
is $test->type, 'test', '... and it should report the correct type';
ok $test->is_test, '... and it should identify itself as a test';
is $test->ok, 'ok', '... and it should have the correct ok()';
ok $test->is_ok, '... and the correct boolean version of is_ok()';
ok $test->is_actual_ok,
'... and the correct boolean version of is_actual_ok()';
is $test->number, 1, '... and have the correct test number';
is $test->description, '- input file opened',
'... and the correct description';
ok !$test->directive, '... and not have a directive';
ok !$test->explanation, '... or a directive explanation';
ok !$test->has_skip, '... and it is not a SKIPped test';
ok !$test->has_todo, '... nor a TODO test';
is $test->as_string, 'ok 1 - input file opened',
'... and its string representation should be correct';
is $test->raw, 'ok 1 - input file opened',
'... and raw() should return the original line';
# junk lines should be preserved
my $unknown = shift @results;
isa_ok $unknown, $UNKNOWN;
is $unknown->type, 'unknown', '... and it should report the correct type';
ok $unknown->is_unknown, '... and it should identify itself as unknown';
is $unknown->as_string, '... this is junk',
'... and its string representation should be returned verbatim';
is $unknown->raw, '... this is junk',
'... and raw() should return the original line';
# a failing test, which also happens to have a directive
my $failed = shift @results;
isa_ok $failed, $TEST;
is $failed->type, 'test', '... and it should report the correct type';
ok $failed->is_test, '... and it should identify itself as a test';
is $failed->ok, 'not ok', '... and it should have the correct ok()';
ok $failed->is_ok, '... and TODO tests should always pass';
ok !$failed->is_actual_ok,
'... and the correct boolean version of is_actual_ok ()';
is $failed->number, 2, '... and have the correct failed number';
is $failed->description, 'first line of the input valid',
'... and the correct description';
is $failed->directive, 'TODO', '... and should have the correct directive';
is $failed->explanation, 'some data',
'... and the correct directive explanation';
ok !$failed->has_skip, '... and it is not a SKIPped failed';
ok $failed->has_todo, '... but it is a TODO succeeded';
is $failed->as_string,
'not ok 2 first line of the input valid # TODO some data',
'... and its string representation should be correct';
is $failed->raw, 'not ok first line of the input valid # todo some data',
'... and raw() should return the original line';
# comments
my $comment = shift @results;
isa_ok $comment, $COMMENT;
is $comment->type, 'comment', '... and it should report the correct type';
ok $comment->is_comment, '... and it should identify itself as a comment';
is $comment->comment, 'this is a comment',
'... and you should be able to fetch the comment';
is $comment->as_string, '# this is a comment',
'... and have the correct string representation';
is $comment->raw, '# this is a comment',
'... and raw() should return the original line';
# another normal, passing test
$test = shift @results;
isa_ok $test, $TEST;
is $test->type, 'test', '... and it should report the correct type';
ok $test->is_test, '... and it should identify itself as a test';
is $test->ok, 'ok', '... and it should have the correct ok()';
ok $test->is_ok, '... and the correct boolean version of is_ok()';
ok $test->is_actual_ok,
'... and the correct boolean version of is_actual_ok()';
is $test->number, 3, '... and have the correct test number';
is $test->description, '- read the rest of the file',
'... and the correct description';
ok !$test->directive, '... and not have a directive';
ok !$test->explanation, '... or a directive explanation';
ok !$test->has_skip, '... and it is not a SKIPped test';
ok !$test->has_todo, '... nor a TODO test';
is $test->as_string, 'ok 3 - read the rest of the file',
'... and its string representation should be correct';
is $test->raw, 'ok 3 - read the rest of the file',
'... and raw() should return the original line';
# a failing test
$failed = shift @results;
isa_ok $failed, $TEST;
is $failed->type, 'test', '... and it should report the correct type';
ok $failed->is_test, '... and it should identify itself as a test';
is $failed->ok, 'not ok', '... and it should have the correct ok()';
ok !$failed->is_ok, '... and the tests should not have passed';
ok !$failed->is_actual_ok,
'... and the correct boolean version of is_actual_ok ()';
is $failed->number, 4, '... and have the correct failed number';
is $failed->description, '- this is a real failure',
'... and the correct description';
ok !$failed->directive, '... and should have no directive';
ok !$failed->explanation, '... and no directive explanation';
ok !$failed->has_skip, '... and it is not a SKIPped failed';
ok !$failed->has_todo, '... and not a TODO test';
is $failed->as_string, 'not ok 4 - this is a real failure',
'... and its string representation should be correct';
is $failed->raw, 'not ok 4 - this is a real failure',
'... and raw() should return the original line';
# Some YAML
my $yaml = shift @results;
isa_ok $yaml, $YAML;
is $yaml->type, 'yaml', '... and it should report the correct type';
ok $yaml->is_yaml, '... and it should identify itself as yaml';
is_deeply $yaml->data, 'YAML!', '... and data should be correct';
# ok 5 # skip we have no description
# skipped test
$test = shift @results;
isa_ok $test, $TEST;
is $test->type, 'test', '... and it should report the correct type';
ok $test->is_test, '... and it should identify itself as a test';
is $test->ok, 'ok', '... and it should have the correct ok()';
ok $test->is_ok, '... and the correct boolean version of is_ok()';
ok $test->is_actual_ok,
'... and the correct boolean version of is_actual_ok()';
is $test->number, 5, '... and have the correct test number';
ok !$test->description, '... and skipped tests have no description';
is $test->directive, 'SKIP', '... and the correct directive';
is $test->explanation, 'we have no description',
'... but we should have an explanation';
ok $test->has_skip, '... and it is a SKIPped test';
ok !$test->has_todo, '... but not a TODO test';
is $test->as_string, 'ok 5 # SKIP we have no description',
'... and its string representation should be correct';
is $test->raw, 'ok 5 # skip we have no description',
'... and raw() should return the original line';
# a failing test, which also happens to have a directive
# ok 6 - you shall not pass! # TODO should have failed
my $bonus = shift @results;
isa_ok $bonus, $TEST;
can_ok $bonus, 'todo_passed';
is $bonus->type, 'test', 'TODO tests should parse correctly';
ok $bonus->is_test, '... and it should identify itself as a test';
is $bonus->ok, 'ok', '... and it should have the correct ok()';
ok $bonus->is_ok, '... and TODO tests should not always pass';
ok $bonus->is_actual_ok,
'... and the correct boolean version of is_actual_ok ()';
is $bonus->number, 6, '... and have the correct failed number';
is $bonus->description, '- you shall not pass!',
'... and the correct description';
is $bonus->directive, 'TODO', '... and should have the correct directive';
is $bonus->explanation, 'should have failed',
'... and the correct directive explanation';
ok !$bonus->has_skip, '... and it is not a SKIPped failed';
ok $bonus->has_todo, '... but it is a TODO succeeded';
is $bonus->as_string, 'ok 6 - you shall not pass! # TODO should have failed',
'... and its string representation should be correct';
is $bonus->raw, 'ok 6 - you shall not pass! # TODO should have failed',
'... and raw() should return the original line';
ok $bonus->todo_passed,
'... todo_bonus() should pass for TODO tests which unexpectedly succeed';
# not ok 7 - Gandalf wins. Game over. # TODO 'bout time!
my $passed = shift @results;
isa_ok $passed, $TEST;
can_ok $passed, 'todo_passed';
is $passed->type, 'test', 'TODO tests should parse correctly';
ok $passed->is_test, '... and it should identify itself as a test';
is $passed->ok, 'not ok', '... and it should have the correct ok()';
ok $passed->is_ok, '... and TODO tests should always pass';
ok !$passed->is_actual_ok,
'... and the correct boolean version of is_actual_ok ()';
is $passed->number, 7, '... and have the correct passed number';
is $passed->description, '- Gandalf wins. Game over.',
'... and the correct description';
is $passed->directive, 'TODO', '... and should have the correct directive';
is $passed->explanation, "'bout time!",
'... and the correct directive explanation';
ok !$passed->has_skip, '... and it is not a SKIPped passed';
ok $passed->has_todo, '... but it is a TODO succeeded';
is $passed->as_string,
"not ok 7 - Gandalf wins. Game over. # TODO 'bout time!",
'... and its string representation should be correct';
is $passed->raw, "not ok 7 - Gandalf wins. Game over. # TODO 'bout time!",
'... and raw() should return the original line';
ok !$passed->todo_passed,
'... todo_passed() should not pass for TODO tests which failed';
# test parse results
can_ok $parser, 'passed';
is $parser->passed, 6,
'... and we should have the correct number of passed tests';
is_deeply [ $parser->passed ], [ 1, 2, 3, 5, 6, 7 ],
'... and get a list of the passed tests';
can_ok $parser, 'failed';
is $parser->failed, 1, '... and the correct number of failed tests';
is_deeply [ $parser->failed ], [4], '... and get a list of the failed tests';
can_ok $parser, 'actual_passed';
is $parser->actual_passed, 4,
'... and we should have the correct number of actually passed tests';
is_deeply [ $parser->actual_passed ], [ 1, 3, 5, 6 ],
'... and get a list of the actually passed tests';
can_ok $parser, 'actual_failed';
is $parser->actual_failed, 3,
'... and the correct number of actually failed tests';
is_deeply [ $parser->actual_failed ], [ 2, 4, 7 ],
'... or get a list of the actually failed tests';
can_ok $parser, 'todo';
is $parser->todo, 3,
'... and we should have the correct number of TODO tests';
is_deeply [ $parser->todo ], [ 2, 6, 7 ],
'... and get a list of the TODO tests';
can_ok $parser, 'skipped';
is $parser->skipped, 1,
'... and we should have the correct number of skipped tests';
is_deeply [ $parser->skipped ], [5],
'... and get a list of the skipped tests';
# check the plan
can_ok $parser, 'plan';
is $parser->plan, '1..7', '... and we should have the correct plan';
is $parser->tests_planned, 7, '... and the correct number of tests';
# "Unexpectedly succeeded"
can_ok $parser, 'todo_passed';
is scalar $parser->todo_passed, 1,
'... and it should report the number of tests which unexpectedly succeeded';
is_deeply [ $parser->todo_passed ], [6],
'... or *which* tests unexpectedly succeeded';
#
# Bug report from Torsten Schoenfeld
# Makes sure parser can handle blank lines
#
$tap = <<'END_TAP';
1..2
ok 1 - input file opened
ok 2 - read the rest of the file
END_TAP
my $aref = [ split /\n/ => $tap ];
can_ok $PARSER, 'new';
$parser
= $PARSER->new( { iterator => TAP::Parser::Iterator::Array->new($aref) } );
isa_ok $parser, $PARSER, '... and calling it should succeed';
# results() is sane?
ok @results = _get_results($parser), 'The parser should return results';
is scalar @results, 5, '... and there should be one for each line';
# check the test plan
$result = shift @results;
isa_ok $result, $PLAN;
can_ok $result, 'type';
is $result->type, 'plan', '... and it should report the correct type';
ok $result->is_plan, '... and it should identify itself as a plan';
is $result->plan, '1..2', '... and identify the plan';
is $result->as_string, '1..2',
'... and have the correct string representation';
is $result->raw, '1..2', '... and raw() should return the original line';
# a normal, passing test
$test = shift @results;
isa_ok $test, $TEST;
is $test->type, 'test', '... and it should report the correct type';
ok $test->is_test, '... and it should identify itself as a test';
is $test->ok, 'ok', '... and it should have the correct ok()';
ok $test->is_ok, '... and the correct boolean version of is_ok()';
ok $test->is_actual_ok,
'... and the correct boolean version of is_actual_ok()';
is $test->number, 1, '... and have the correct test number';
is $test->description, '- input file opened',
'... and the correct description';
ok !$test->directive, '... and not have a directive';
ok !$test->explanation, '... or a directive explanation';
ok !$test->has_skip, '... and it is not a SKIPped test';
ok !$test->has_todo, '... nor a TODO test';
is $test->as_string, 'ok 1 - input file opened',
'... and its string representation should be correct';
is $test->raw, 'ok 1 - input file opened',
'... and raw() should return the original line';
# junk lines should be preserved
$unknown = shift @results;
isa_ok $unknown, $UNKNOWN;
is $unknown->type, 'unknown', '... and it should report the correct type';
ok $unknown->is_unknown, '... and it should identify itself as unknown';
is $unknown->as_string, '',
'... and its string representation should be returned verbatim';
is $unknown->raw, '', '... and raw() should return the original line';
# ... and the second empty line
$unknown = shift @results;
isa_ok $unknown, $UNKNOWN;
is $unknown->type, 'unknown', '... and it should report the correct type';
ok $unknown->is_unknown, '... and it should identify itself as unknown';
is $unknown->as_string, '',
'... and its string representation should be returned verbatim';
is $unknown->raw, '', '... and raw() should return the original line';
# a passing test
$test = shift @results;
isa_ok $test, $TEST;
is $test->type, 'test', '... and it should report the correct type';
ok $test->is_test, '... and it should identify itself as a test';
is $test->ok, 'ok', '... and it should have the correct ok()';
ok $test->is_ok, '... and the correct boolean version of is_ok()';
ok $test->is_actual_ok,
'... and the correct boolean version of is_actual_ok()';
is $test->number, 2, '... and have the correct test number';
is $test->description, '- read the rest of the file',
'... and the correct description';
ok !$test->directive, '... and not have a directive';
ok !$test->explanation, '... or a directive explanation';
ok !$test->has_skip, '... and it is not a SKIPped test';
ok !$test->has_todo, '... nor a TODO test';
is $test->as_string, 'ok 2 - read the rest of the file',
'... and its string representation should be correct';
is $test->raw, 'ok 2 - read the rest of the file',
'... and raw() should return the original line';
is scalar $parser->passed, 2,
'Empty junk lines should not affect the correct number of tests passed';
# Check source => "tap content"
can_ok $PARSER, 'new';
$parser = $PARSER->new( { source => "1..1\nok 1\n" } );
isa_ok $parser, $PARSER, '... and calling it should succeed';
ok @results = _get_results($parser), 'The parser should return results';
is( scalar @results, 2, "Got two lines of TAP" );
# Check source => [array]
can_ok $PARSER, 'new';
$parser = $PARSER->new( { source => [ "1..1", "ok 1" ] } );
isa_ok $parser, $PARSER, '... and calling it should succeed';
ok @results = _get_results($parser), 'The parser should return results';
is( scalar @results, 2, "Got two lines of TAP" );
# Check source => $filehandle
can_ok $PARSER, 'new';
open my $fh, 't/data/catme.1';
$parser = $PARSER->new( { source => $fh } );
isa_ok $parser, $PARSER, '... and calling it should succeed';
ok @results = _get_results($parser), 'The parser should return results';
is( scalar @results, 2, "Got two lines of TAP" );
{
# set a spool to write to
tie local *SPOOL, 'IO::c55Capture';
my $tap = <<'END_TAP';
TAP version 13
1..7
ok 1 - input file opened
... this is junk
not ok first line of the input valid # todo some data
# this is a comment
ok 3 - read the rest of the file
not ok 4 - this is a real failure
--- YAML!
...
ok 5 # skip we have no description
ok 6 - you shall not pass! # TODO should have failed
not ok 7 - Gandalf wins. Game over. # TODO 'bout time!
END_TAP
{
my $parser = $PARSER->new(
{ tap => $tap,
spool => \*SPOOL,
}
);
_get_results($parser);
my @spooled = tied(*SPOOL)->dump();
is @spooled, 24, 'coverage testing for spool attribute of parser';
is join( '', @spooled ), $tap, "spooled tap matches";
}
{
my $parser = $PARSER->new(
{ tap => $tap,
spool => \*SPOOL,
}
);
$parser->callback( 'ALL', sub { } );
_get_results($parser);
my @spooled = tied(*SPOOL)->dump();
is @spooled, 24, 'coverage testing for spool attribute of parser';
is join( '', @spooled ), $tap, "spooled tap matches";
}
}
{
# _initialize coverage
my $x = bless [], 'kjsfhkjsdhf';
my @die;
eval {
local $SIG{__DIE__} = sub { push @die, @_ };
$PARSER->new();
};
is @die, 1, 'coverage testing for _initialize';
like pop @die, qr/PANIC:\s+could not determine iterator for input\s*at/,
'...and it failed as expected';
@die = ();
eval {
local $SIG{__DIE__} = sub { push @die, @_ };
$PARSER->new(
{ iterator => 'iterator',
tap => 'tap',
source => 'source', # only one of these is allowed
}
);
};
is @die, 1, 'coverage testing for _initialize';
like pop @die,
qr/You may only choose one of 'exec', 'tap', 'source' or 'iterator'/,
'...and it failed as expected';
}
{
# coverage of todo_failed
my $tap = <<'END_TAP';
TAP version 13
1..7
ok 1 - input file opened
... this is junk
not ok first line of the input valid # todo some data
# this is a comment
ok 3 - read the rest of the file
not ok 4 - this is a real failure
--- YAML!
...
ok 5 # skip we have no description
ok 6 - you shall not pass! # TODO should have failed
not ok 7 - Gandalf wins. Game over. # TODO 'bout time!
END_TAP
my $parser = $PARSER->new( { tap => $tap } );
_get_results($parser);
my @warn;
eval {
local $SIG{__WARN__} = sub { push @warn, @_ };
$parser->todo_failed;
};
is @warn, 1, 'coverage testing of todo_failed';
like pop @warn,
qr/"todo_failed" is deprecated. Please use "todo_passed". See the docs[.]/,
'..and failed as expected'
}
{
# coverage testing for T::P::_initialize
# coverage of the source argument paths
# ref argument to source
my $parser = TAP::Parser->new( { source => [ split /$/, $tap ] } );
isa_ok $parser, 'TAP::Parser';
isa_ok $parser->_iterator, 'TAP::Parser::Iterator::Array';
SKIP: {
skip 'Segfaults Perl 5.6.0' => 2 if $] <= 5.006000;
# uncategorisable argument to source
my @die;
eval {
local $SIG{__DIE__} = sub { push @die, @_ };
$parser = TAP::Parser->new( { source => 'nosuchfile' } );
};
is @die, 1, 'uncategorisable source';
like pop @die, qr/Cannot detect source of 'nosuchfile'/,
'... and we died as expected';
}
}
{
# coverage test of perl source with switches
my $parser = TAP::Parser->new(
{ source => File::Spec->catfile(
't',
'sample-tests',
'simple'
),
}
);
isa_ok $parser, 'TAP::Parser';
isa_ok $parser->_iterator, 'TAP::Parser::Iterator::Process';
# Workaround for Mac OS X problem wrt closing the iterator without
# reading from it.
$parser->next;
}
{
# coverage testing for TAP::Parser::has_problems
# we're going to need to test lots of fragments of tap
# to cover all the different boolean tests
# currently covered are no problems and failed, so let's next test
# todo_passed
my $tap = <<'END_TAP';
TAP version 13
1..2
ok 1 - input file opened
ok 2 - Gandalf wins. Game over. # TODO 'bout time!
END_TAP
my $parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
ok !$parser->failed, 'parser didnt fail';
ok $parser->todo_passed, '... and todo_passed is true';
ok !$parser->has_problems, '... and has_problems is false';
# now parse_errors
$tap = <<'END_TAP';
TAP version 13
1..2
SMACK
END_TAP
$parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
ok !$parser->failed, 'parser didnt fail';
ok !$parser->todo_passed, '... and todo_passed is false';
ok $parser->parse_errors, '... and parse_errors is true';
ok $parser->has_problems, '... and has_problems';
# Now wait and exit are hard to do in an OS platform-independent way, so
# we won't even bother
$tap = <<'END_TAP';
TAP version 13
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
$parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
$parser->wait(1);
ok !$parser->failed, 'parser didnt fail';
ok !$parser->todo_passed, '... and todo_passed is false';
ok !$parser->parse_errors, '... and parse_errors is false';
ok $parser->wait, '... and wait is set';
ok $parser->has_problems, '... and has_problems';
# and use the same for exit
$parser->wait(0);
$parser->exit(1);
ok !$parser->failed, 'parser didnt fail';
ok !$parser->todo_passed, '... and todo_passed is false';
ok !$parser->parse_errors, '... and parse_errors is false';
ok !$parser->wait, '... and wait is not set';
ok $parser->exit, '... and exit is set';
ok $parser->has_problems, '... and has_problems';
}
{
# coverage testing of the version states
my $tap = <<'END_TAP';
TAP version 12
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
my $parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
my @errors = $parser->parse_errors;
is @errors, 1, 'test too low version number';
like pop @errors,
qr/Explicit TAP version must be at least 13. Got version 12/,
'... and trapped expected version error';
# now too high a version
$tap = <<'END_TAP';
TAP version 14
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
$parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
@errors = $parser->parse_errors;
is @errors, 1, 'test too high version number';
like pop @errors,
qr/TAP specified version 14 but we don't know about versions later than 13/,
'... and trapped expected version error';
}
{
# coverage testing of TAP version in the wrong place
my $tap = <<'END_TAP';
1..2
ok 1 - input file opened
TAP version 12
ok 2 - Gandalf wins
END_TAP
my $parser = TAP::Parser->new( { tap => $tap } );
_get_results($parser);
my @errors = $parser->parse_errors;
is @errors, 1, 'test TAP version number in wrong place';
like pop @errors,
qr/If TAP version is present it must be the first line of output/,
'... and trapped expected version error';
}
{
# we're going to bash the internals a bit (but using the API as
# much as possible) to force grammar->tokenise() to fail
# firstly we'll create a iterator that dies when its next_raw method is called
package TAP::Parser::Iterator::Dies;
use strict;
use vars qw(@ISA);
@ISA = qw(TAP::Parser::Iterator);
sub next_raw {
die 'this is the dying iterator';
}
# required as part of the TPI interface
sub exit { }
sub wait { }
package main;
# now build a standard parser
my $tap = <<'END_TAP';
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
{
my $parser = TAP::Parser->new( { tap => $tap } );
# build a dying iterator
my $iterator = TAP::Parser::Iterator::Dies->new;
# now replace the iterator - we're forced to us an T::P intenal
# method for this
$parser->_iterator($iterator);
# build a new grammar
my $grammar = TAP::Parser::Grammar->new(
{ iterator => $iterator,
parser => $parser
}
);
# replace our grammar with this new one
$parser->_grammar($grammar);
# now call next on the parser, and the grammar should die
my $result = $parser->next; # will die in iterator
is $result, undef, 'iterator dies';
my @errors = $parser->parse_errors;
is @errors, 2, '...and caught expected errrors';
like shift @errors, qr/this is the dying iterator/,
'...and it was what we expected';
}
# Do it all again with callbacks to exercise the other code path in
# the unrolled iterator
{
my $parser = TAP::Parser->new( { tap => $tap } );
$parser->callback( 'ALL', sub { } );
# build a dying iterator
my $iterator = TAP::Parser::Iterator::Dies->new;
# now replace the iterator - we're forced to us an T::P intenal
# method for this
$parser->_iterator($iterator);
# build a new grammar
my $grammar = TAP::Parser::Grammar->new(
{ iterator => $iterator,
parser => $parser
}
);
# replace our grammar with this new one
$parser->_grammar($grammar);
# now call next on the parser, and the grammar should die
my $result = $parser->next; # will die in iterator
is $result, undef, 'iterator dies';
my @errors = $parser->parse_errors;
is @errors, 2, '...and caught expected errrors';
like shift @errors, qr/this is the dying iterator/,
'...and it was what we expected';
}
}
{
# coverage testing of TAP::Parser::_next_state
package TAP::Parser::WithBrokenState;
use vars qw(@ISA);
@ISA = qw( TAP::Parser );
sub _make_state_table {
return { INIT => { plan => { goto => 'FOO' } } };
}
package main;
my $tap = <<'END_TAP';
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
my $parser = TAP::Parser::WithBrokenState->new( { tap => $tap } );
my @die;
eval {
local $SIG{__DIE__} = sub { push @die, @_ };
$parser->next;
$parser->next;
};
is @die, 1, 'detect broken state machine';
like pop @die, qr/Illegal state: FOO/,
'...and the message is as we expect';
}
{
# coverage testing of TAP::Parser::_iter
package TAP::Parser::WithBrokenIter;
use vars qw(@ISA);
@ISA = qw( TAP::Parser );
sub _iter {return}
package main;
my $tap = <<'END_TAP';
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
my $parser = TAP::Parser::WithBrokenIter->new( { tap => $tap } );
my @die;
eval {
local $SIG{__WARN__} = sub { };
local $SIG{__DIE__} = sub { push @die, @_ };
$parser->next;
};
is @die, 1, 'detect broken iter';
like pop @die, qr/Can't use/, '...and the message is as we expect';
}
SKIP: {
# http://markmail.org/message/rkxbo6ft7yorgnzb
skip "Crashes on older Perls", 2 if $] <= 5.008004 || $] == 5.009;
# coverage testing of TAP::Parser::_finish
my $tap = <<'END_TAP';
1..2
ok 1 - input file opened
ok 2 - Gandalf wins
END_TAP
my $parser = TAP::Parser->new( { tap => $tap } );
$parser->tests_run(999);
my @die;
eval {
local $SIG{__DIE__} = sub { push @die, @_ };
_get_results $parser;
};
is @die, 1, 'detect broken test counts';
like pop @die,
qr/Panic: planned test count [(]1001[)] did not equal sum of passed [(]0[)] and failed [(]2[)] tests!/,
'...and the message is as we expect';
}
{
# Sanity check on state table
my $parser = TAP::Parser->new( { tap => "1..1\nok 1\n" } );
my $state_table = $parser->_make_state_table;
my @states = sort keys %$state_table;
my @expect = sort qw(
bailout comment plan pragma test unknown version yaml
);
my %reachable = ( INIT => 1 );
for my $name (@states) {
my $state = $state_table->{$name};
my @can_handle = sort keys %$state;
is_deeply \@can_handle, \@expect, "token types handled in $name";
for my $type (@can_handle) {
$reachable{$_}++
for grep {defined}
map { $state->{$type}->{$_} } qw(goto continue);
}
}
is_deeply [ sort keys %reachable ], [@states], "all states reachable";
}
{
# exit, wait, ignore_exit interactions
my @truth = (
[ 0, 0, 0, 0 ],
[ 0, 0, 1, 0 ],
[ 1, 0, 0, 1 ],
[ 1, 0, 1, 0 ],
[ 1, 1, 0, 1 ],
[ 1, 1, 1, 0 ],
[ 0, 1, 0, 1 ],
[ 0, 1, 1, 0 ],
);
for my $t (@truth) {
my ( $wait, $exit, $ignore_exit, $has_problems ) = @$t;
my $test_parser = sub {
my $parser = shift;
$parser->wait($wait);
$parser->exit($exit);
ok $has_problems ? $parser->has_problems : !$parser->has_problems,
"exit=$exit, wait=$wait, ignore=$ignore_exit";
};
my $parser = TAP::Parser->new( { tap => "1..1\nok 1\n" } );
$parser->ignore_exit($ignore_exit);
$test_parser->($parser);
$test_parser->(
TAP::Parser->new(
{ tap => "1..1\nok 1\n", ignore_exit => $ignore_exit }
)
);
}
}