diff options
author | Nicholas Clark <nick@ccl4.org> | 2008-07-31 21:27:36 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2008-07-31 21:27:36 +0000 |
commit | f7c69158501ed4705d71f069f23211f56bd55a2e (patch) | |
tree | f2387107086e230c5d3bf132a7ebfbf3e39dd5c3 /lib/Test | |
parent | b78dccfb97f2a41b9be93ea6888a12b7bef9a4b2 (diff) | |
download | perl-f7c69158501ed4705d71f069f23211f56bd55a2e.tar.gz |
Upgrade to Test::Harness 3.13
p4raw-id: //depot/perl@34169
Diffstat (limited to 'lib/Test')
33 files changed, 828 insertions, 255 deletions
diff --git a/lib/Test/Harness.pm b/lib/Test/Harness.pm index 17e891653b..4f0164eee3 100644 --- a/lib/Test/Harness.pm +++ b/lib/Test/Harness.pm @@ -28,6 +28,7 @@ use vars qw( $Timer $Strap $has_time_hires + $IgnoreExit ); # $ML $Last_ML_Print @@ -43,11 +44,11 @@ Test::Harness - Run Perl standard test scripts with statistics =head1 VERSION -Version 3.10 +Version 3.13 =cut -$VERSION = '3.10'; +$VERSION = '3.13'; # Backwards compatibility for exportable variable names. *verbose = *Verbose; @@ -73,8 +74,9 @@ $Debug = $ENV{HARNESS_DEBUG} || 0; $Switches = '-w'; $Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80; $Columns--; # Some shells have trouble with a full line of text. -$Timer = $ENV{HARNESS_TIMER} || 0; -$Color = $ENV{HARNESS_COLOR} || 0; +$Timer = $ENV{HARNESS_TIMER} || 0; +$Color = $ENV{HARNESS_COLOR} || 0; +$IgnoreExit = $ENV{HARNESS_IGNORE_EXIT} || 0; =head1 SYNOPSIS @@ -225,9 +227,7 @@ sub _new_harness { my $sub_args = shift || {}; my ( @lib, @switches ); - for my $opt ( - split_shell( $Switches, $ENV{HARNESS_PERL_SWITCHES} ) ) - { + for my $opt ( split_shell( $Switches, $ENV{HARNESS_PERL_SWITCHES} ) ) { if ( $opt =~ /^ -I (.*) $ /x ) { push @lib, $1; } @@ -243,12 +243,13 @@ sub _new_harness { my $verbosity = ( $Verbose ? ( $Verbose !~ /\d/ ) ? 1 : $Verbose : 0 ); my $args = { - timer => $Timer, - directives => $Directives, - lib => \@lib, - switches => \@switches, - color => $Color, - verbosity => $verbosity, + timer => $Timer, + directives => $Directives, + lib => \@lib, + switches => \@switches, + color => $Color, + verbosity => $verbosity, + ignore_exit => $IgnoreExit, }; $args->{stdout} = $sub_args->{out} diff --git a/lib/Test/Harness/Changes b/lib/Test/Harness/Changes index ff7eee0482..2051eab790 100644 --- a/lib/Test/Harness/Changes +++ b/lib/Test/Harness/Changes @@ -1,6 +1,65 @@ Revision history for Test-Harness -3.07 2008-01-13 +3.13 2008-07-27 + - fixed various closure related leaks + - made prove honour HARNESS_TIMER + - Applied patches supplied by Alex Vandiver + - add 'rules' switch to prove: allows parallel execution rules + to be specified on the command line. + - allow '**' (any path) wildcard in parallel rules + - fix bug report address + - make tprove_gtk example work again. + +3.12 2008-06-22 + - applied Steve Purkis' huge refactoring patch which adds + configurable factories for most of the major internal classes. + - applied David Wheeler's patch to allow exec to be a code + reference. + - made tests more robust in the presence of -MFoo in PERL5OPT. + +3.11 2008-06-09 + - applied Jim Keenan's patch that makes App::Prove::run return a + rather than exit (#33609) + - prove -r now recurses cwd rather than 't' by default (#33007) + - restored --ext switch to prove (#33848) + - added ignore_exit option to TAP::Parser and corresponding + interfaces to TAP::Harness and Test::Harness. Requested for + Parrot. + - Implemented rule based parallel scheduler. + - Moved filename -> display name mapping out of formatter. This + prevents the formatter's strip-extensions logic from stripping + extensions from supplied descriptions. + - Only strip extensions from test names if all tests have the + same extension. Previously we stripped extensions if all names + had /any/ extension making it impossible to distinguish tests + whose name differed only in the extension. + - Removed privacy test that made it impossible to subclass + TAP::Parser. + - Delayed initialisation of grammar making it easier to replace + the TAP::Parser stream after instantiation. + - Make it possible to supply import parameters to a replacement + harness with prove. + - Make it possible to replace either _grammar /or/ _stream + before reading from a TAP::Parser. + +3.10 2008-02-26 + - fix undefined value warnings with bleadperl. + - added pragma support. + - fault unknown TAP tokens under strict pragma. + +3.09 2008-02-10 + - support for HARNESS_PERL_SWITCHES containing things like + '-e "system(shift)"'. + - set HARNESS_IS_VERBOSE during verbose testing. + - documentation fixes. + +3.08 2008-02-08 + - added support for 'out' option to + Test::Harness::execute_tests. See #32476. Thanks RENEEB. + - Fixed YAMLish handling of non-alphanumeric hash keys. + - Added --dry option to prove for 2.64 compatibility. + +3.07 2008-01-13 - prove now supports HARNESS_PERL_SWITCHES. - restored TEST_VERBOSE to prove. diff --git a/lib/Test/Harness/bin/prove b/lib/Test/Harness/bin/prove index acd845a48c..ee31df8832 100644 --- a/lib/Test/Harness/bin/prove +++ b/lib/Test/Harness/bin/prove @@ -5,7 +5,7 @@ use App::Prove; my $app = App::Prove->new; $app->process_args(@ARGV); -$app->run; +exit( $app->run ? 0 : 1 ); __END__ @@ -23,13 +23,15 @@ Boolean options: -v, --verbose Print all test lines. -l, --lib Add 'lib' to the path for your tests (-Ilib). - -b, --blib Add 'blib/lib' to the path for your tests (-Iblib/lib). + -b, --blib Add 'blib/lib' and 'blib/arch' to the path for your tests -s, --shuffle Run the tests in random order. -c, --color Colored test output (default). --nocolor Do not color test output. -D --dry Dry run. Show test that would have run. + --ext Set the extension for tests (default '.t') -f, --failures Only show failed tests. - --fork Fork to run harness in multiple processes + --fork Fork to run harness in multiple processes. + --ignore-exit Ignore exit status from test scripts. -m, --merge Merge test scripts' STDERR with their STDOUT. -r, --recurse Recursively descend into directories. --reverse Run the tests in reverse order. diff --git a/lib/Test/Harness/t/000-load.t b/lib/Test/Harness/t/000-load.t index 5c952a7f27..c6d6a92531 100644 --- a/lib/Test/Harness/t/000-load.t +++ b/lib/Test/Harness/t/000-load.t @@ -3,7 +3,7 @@ use strict; use lib 't/lib'; -use Test::More tests => 62; +use Test::More tests => 74; BEGIN { @@ -20,11 +20,14 @@ BEGIN { TAP::Harness TAP::Parser::Aggregator TAP::Parser::Grammar + TAP::Parser::Iterator TAP::Parser::Iterator::Array TAP::Parser::Iterator::Process TAP::Parser::Iterator::Stream - TAP::Parser::Iterator + TAP::Parser::IteratorFactory TAP::Parser::Multiplexer + TAP::Parser::Result + TAP::Parser::ResultFactory TAP::Parser::Result::Bailout TAP::Parser::Result::Comment TAP::Parser::Result::Plan @@ -34,6 +37,9 @@ BEGIN { TAP::Parser::Result::Version TAP::Parser::Result::YAML TAP::Parser::Result + TAP::Parser::Scheduler + TAP::Parser::Scheduler::Job + TAP::Parser::Scheduler::Spinner TAP::Parser::Source::Perl TAP::Parser::Source TAP::Parser::YAMLish::Reader diff --git a/lib/Test/Harness/t/aggregator.t b/lib/Test/Harness/t/aggregator.t index 441e2ba47c..b3aff2a21f 100644 --- a/lib/Test/Harness/t/aggregator.t +++ b/lib/Test/Harness/t/aggregator.t @@ -1,13 +1,12 @@ #!/usr/bin/perl -wT - use strict; use lib 't/lib'; use Test::More tests => 79; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; use TAP::Parser::Aggregator; my $tap = <<'END_TAP'; @@ -21,7 +20,8 @@ not ok 4 - this is a real failure ok 5 # skip we have no description END_TAP -my $stream = TAP::Parser::Iterator->new( [ split /\n/ => $tap ] ); +my $factory = TAP::Parser::IteratorFactory->new; +my $stream = $factory->make_iterator( [ split /\n/ => $tap ] ); isa_ok $stream, 'TAP::Parser::Iterator'; my $parser1 = TAP::Parser->new( { stream => $stream } ); @@ -207,12 +207,9 @@ is $agg->todo_passed, 1, '... and the correct number of unexpectedly succeeded tests'; ok $agg->has_problems, '... and it should report true that there are problems'; -is $agg->get_status, 'PASS', - '... and the status should be passing'; -ok !$agg->has_errors, - '.... but it should not report any errors'; -ok $agg->all_passed, - '... bonus tests should be passing tests, too'; +is $agg->get_status, 'PASS', '... and the status should be passing'; +ok !$agg->has_errors, '.... but it should not report any errors'; +ok $agg->all_passed, '... bonus tests should be passing tests, too'; # 2. !failed && !todo_passed && parse_errors diff --git a/lib/Test/Harness/t/base.t b/lib/Test/Harness/t/base.t index 25197f6f76..4fee54844e 100644 --- a/lib/Test/Harness/t/base.t +++ b/lib/Test/Harness/t/base.t @@ -89,8 +89,8 @@ package main; ok( !$@, 'callbacks installed OK' ); my $nice_cbs = $base->_callback_for('nice_event'); - is( ref $nice_cbs, 'ARRAY', 'callbacks type ok' ); - is( scalar @$nice_cbs, 1, 'right number of callbacks' ); + is( ref $nice_cbs, 'ARRAY', 'callbacks type ok' ); + is( scalar @$nice_cbs, 1, 'right number of callbacks' ); my $nice_cb = $nice_cbs->[0]; ok( ref $nice_cb eq 'CODE', 'callback for nice_event returned' ); my $got = $nice_cb->('Is '); @@ -98,16 +98,16 @@ package main; cmp_ok( $nice, '==', 1, 'callback calls the right sub' ); my $other_cbs = $base->_callback_for('other_event'); - is( ref $other_cbs, 'ARRAY', 'callbacks type ok' ); - is( scalar @$other_cbs, 1, 'right number of callbacks' ); + is( ref $other_cbs, 'ARRAY', 'callbacks type ok' ); + is( scalar @$other_cbs, 1, 'right number of callbacks' ); my $other_cb = $other_cbs->[0]; ok( ref $other_cb eq 'CODE', 'callback for other_event returned' ); $other_cb->(); cmp_ok( $other, '==', -1, 'callback calls the right sub' ); my @got = $base->_make_callback( 'nice_event', 'I am ' ); - is( scalar @got, 1, 'right number of results' ); - is( $got[0], 'I am OK', 'callback via _make_callback works' ); + is( scalar @got, 1, 'right number of results' ); + is( $got[0], 'I am OK', 'callback via _make_callback works' ); } { @@ -139,16 +139,16 @@ package main; ok( !$@, 'callback installed OK' ); my $nice_cbs = $base->_callback_for('nice_event'); - is( ref $nice_cbs, 'ARRAY', 'callbacks type ok' ); - is( scalar @$nice_cbs, 1, 'right number of callbacks' ); + is( ref $nice_cbs, 'ARRAY', 'callbacks type ok' ); + is( scalar @$nice_cbs, 1, 'right number of callbacks' ); my $nice_cb = $nice_cbs->[0]; ok( ref $nice_cb eq 'CODE', 'callback for nice_event returned' ); $nice_cb->(); cmp_ok( $nice, '==', 1, 'callback calls the right sub' ); my $other_cbs = $base->_callback_for('other_event'); - is( ref $other_cbs, 'ARRAY', 'callbacks type ok' ); - is( scalar @$other_cbs, 1, 'right number of callbacks' ); + is( ref $other_cbs, 'ARRAY', 'callbacks type ok' ); + is( scalar @$other_cbs, 1, 'right number of callbacks' ); my $other_cb = $other_cbs->[0]; ok( ref $other_cb eq 'CODE', 'callback for other_event returned' ); $other_cb->(); @@ -164,8 +164,8 @@ package main; $base->callback( other_event => sub { $status = 'OK'; return 'Aye' } ); my $new_cbs = $base->_callback_for('other_event'); - is( ref $new_cbs, 'ARRAY', 'callbacks type ok' ); - is( scalar @$new_cbs, 2, 'right number of callbacks' ); + is( ref $new_cbs, 'ARRAY', 'callbacks type ok' ); + is( scalar @$new_cbs, 2, 'right number of callbacks' ); my $new_cb = $new_cbs->[1]; ok( ref $new_cb eq 'CODE', 'callback for new_event returned' ); my @got = $new_cb->(); diff --git a/lib/Test/Harness/t/callbacks.t b/lib/Test/Harness/t/callbacks.t index b23762102c..9d0cae46c5 100644 --- a/lib/Test/Harness/t/callbacks.t +++ b/lib/Test/Harness/t/callbacks.t @@ -6,7 +6,7 @@ use lib 't/lib'; use Test::More tests => 10; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; my $tap = <<'END_TAP'; 1..5 @@ -36,8 +36,9 @@ my %callbacks = ( } ); -my $stream = TAP::Parser::Iterator->new( [ split /\n/ => $tap ] ); -my $parser = TAP::Parser->new( +my $factory = TAP::Parser::IteratorFactory->new; +my $stream = $factory->make_iterator( [ split /\n/ => $tap ] ); +my $parser = TAP::Parser->new( { stream => $stream, callbacks => \%callbacks, } @@ -77,7 +78,7 @@ my $end = 0; }, ); -$stream = TAP::Parser::Iterator->new( [ split /\n/ => $tap ] ); +$stream = $factory->make_iterator( [ split /\n/ => $tap ] ); $parser = TAP::Parser->new( { stream => $stream, callbacks => \%callbacks, @@ -102,7 +103,7 @@ is $end, 1, 'EOF callback correctly called'; ELSES => sub { }, ); -$stream = TAP::Parser::Iterator->new( [ split /\n/ => $tap ] ); +$stream = $factory->make_iterator( [ split /\n/ => $tap ] ); eval { $parser = TAP::Parser->new( { stream => $stream, diff --git a/lib/Test/Harness/t/compat/inc-propagation.t b/lib/Test/Harness/t/compat/inc-propagation.t index 564297c737..ffa53700a1 100644 --- a/lib/Test/Harness/t/compat/inc-propagation.t +++ b/lib/Test/Harness/t/compat/inc-propagation.t @@ -22,60 +22,28 @@ use Test::More ( : ( tests => 2 ) ); -use Data::Dumper; use Test::Harness; # Change @INC so we ensure it's preserved. use lib 'wibble'; -# TODO: Disabled until we find out why it's breaking on Windows. It's -# not strictly a TODO because it seems pretty likely that it's a Windows -# problem rather than a problem with Test::Harness. - -# Put a stock directory near the beginning. -# use lib $INC[$#INC-2]; - -my $inc = Data::Dumper->new( [ \@INC ] )->Terse(1)->Purity(1)->Dump; -my $taint_inc - = Data::Dumper->new( [ [ grep { $_ ne '.' } @INC ] ] )->Terse(1)->Purity(1) - ->Dump; - -# The tail of @INC is munged during core testing. We're only *really* -# interested in whether 'wibble' makes it anyway. -my $cmp_slice = $ENV{PERL_CORE} ? '[0..1]' : ''; - my $test_template = <<'END'; #!/usr/bin/perl %s use Test::More tests => 2; -sub _strip_dups { - my %%dups; - # Drop '.' which sneaks in on some platforms - my @r = grep { $_ ne '.' } grep { !$dups{$_}++ } @_; - return @r%s; -} - # Make sure we did something sensible with PERL5LIB like $ENV{PERL5LIB}, qr{wibble}; +ok grep { $_ eq 'wibble' } @INC; -is_deeply( - [_strip_dups(@INC)], - [_strip_dups(@{%s})], - '@INC propagated to test' -) or do { - diag join ",\n", _strip_dups(@INC); - diag '-----------------'; - diag join ",\n", _strip_dups(@{%s}); -}; END open TEST, ">inc_check.t.tmp"; -printf TEST $test_template, '', $cmp_slice, $inc, $inc; +printf TEST $test_template, ''; close TEST; open TEST, ">inc_check_taint.t.tmp"; -printf TEST $test_template, '-T', $cmp_slice, $taint_inc, $taint_inc; +printf TEST $test_template, '-T'; close TEST; END { 1 while unlink 'inc_check_taint.t.tmp', 'inc_check.t.tmp'; } diff --git a/lib/Test/Harness/t/compat/inc_taint.t b/lib/Test/Harness/t/compat/inc_taint.t index f0101c396f..06a8e237bd 100644 --- a/lib/Test/Harness/t/compat/inc_taint.t +++ b/lib/Test/Harness/t/compat/inc_taint.t @@ -1,12 +1,12 @@ #!/usr/bin/perl -w BEGIN { - if( $ENV{PERL_CORE} ) { + if ( $ENV{PERL_CORE} ) { chdir 't'; - @INC = ('../lib', 'lib'); + @INC = ( '../lib', 'lib' ); } else { - use lib 't/lib'; + use lib 't/lib'; } } diff --git a/lib/Test/Harness/t/compat/regression.t b/lib/Test/Harness/t/compat/regression.t index d8105c9f7f..1d848f9174 100644 --- a/lib/Test/Harness/t/compat/regression.t +++ b/lib/Test/Harness/t/compat/regression.t @@ -7,6 +7,7 @@ use Test::More tests => 1; use Test::Harness; { + #28567 unshift @INC, 'wibble'; my @before = Test::Harness::_filtered_inc(); diff --git a/lib/Test/Harness/t/compat/test-harness-compat.t b/lib/Test/Harness/t/compat/test-harness-compat.t index 5709d7a185..480d6d8d70 100644 --- a/lib/Test/Harness/t/compat/test-harness-compat.t +++ b/lib/Test/Harness/t/compat/test-harness-compat.t @@ -9,6 +9,7 @@ BEGIN { } use strict; + use lib 't/lib'; use Test::More; @@ -52,7 +53,7 @@ local $ENV{HARNESS_PERL_SWITCHES}; head_end head_fail inc_taint junk_before_plan lone_not_bug no_nums no_output schwern sequence_misparse shbang_misparse simple simple_fail skip skip_nomsg skipall skipall_nomsg - stdout_stderr switches taint todo_inline + stdout_stderr taint todo_inline todo_misparse too_many vms_nit ) ) => { @@ -129,14 +130,6 @@ local $ENV{HARNESS_PERL_SWITCHES}; 'name' => 't/sample-tests/simple_fail', 'wstat' => '' }, - 't/sample-tests/switches' => { - 'canon' => 1, - 'estat' => '', - 'failed' => 1, - 'max' => 1, - 'name' => 't/sample-tests/switches', - 'wstat' => '' - }, 't/sample-tests/todo_misparse' => { 'canon' => 1, 'estat' => '', @@ -173,15 +166,15 @@ local $ENV{HARNESS_PERL_SWITCHES}; } }, 'totals' => { - 'bad' => 13, + 'bad' => 12, 'bonus' => 1, - 'files' => 28, + 'files' => 27, 'good' => 15, - 'max' => 77, + 'max' => 76, 'ok' => 78, 'skipped' => 2, 'sub_skipped' => 2, - 'tests' => 28, + 'tests' => 27, 'todo' => 2 } }, @@ -603,6 +596,9 @@ local $ENV{HARNESS_PERL_SWITCHES}; } }, 'switches' => { + 'skip_if' => sub { + ( $ENV{PERL5OPT} || '' ) =~ m{(?:^|\s)-[dM]}; + }, 'failed' => { 't/sample-tests/switches' => { 'canon' => 1, @@ -814,6 +810,13 @@ local $ENV{HARNESS_PERL_SWITCHES}; if ( $result->{require} && $] < $result->{require} ) { skip "Test requires Perl $result->{require}, we have $]", 4; } + + if ( my $skip_if = $result->{skip_if} ) { + skip + "Test '$test_key' can't run properly in this environment", 4 + if $skip_if->(); + } + my @test_names = split( /,/, $test_key ); my @test_files = map { File::Spec->catfile( $TEST_DIR, $_ ) } @test_names; diff --git a/lib/Test/Harness/t/grammar.t b/lib/Test/Harness/t/grammar.t index 6d572f9082..f1521ede5e 100644 --- a/lib/Test/Harness/t/grammar.t +++ b/lib/Test/Harness/t/grammar.t @@ -1,10 +1,20 @@ #!/usr/bin/perl -w use strict; -use lib 't/lib'; + +BEGIN { + if ( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ( '../lib', 'lib' ); + } + else { + unshift @INC, 't/lib'; + } +} use Test::More tests => 94; +use EmptyParser; use TAP::Parser::Grammar; use TAP::Parser::Iterator::Array; @@ -33,8 +43,9 @@ sub handle_unicode { } package main; my $stream = SS->new; +my $parser = EmptyParser->new; can_ok $GRAMMAR, 'new'; -my $grammar = $GRAMMAR->new($stream); +my $grammar = $GRAMMAR->new( { stream => $stream, parser => $parser } ); isa_ok $grammar, $GRAMMAR, '... and the object it returns'; # Note: all methods are actually class methods. See the docs for the reason @@ -341,9 +352,9 @@ is_deeply $token, $expected, # tokenize { - my $stream = SS->new; - - my $grammar = $GRAMMAR->new($stream); + my $stream = SS->new; + my $parser = EmptyParser->new; + my $grammar = $GRAMMAR->new( { stream => $stream, parser => $parser } ); my $plan = ''; @@ -357,7 +368,8 @@ is_deeply $token, $expected, # _make_plan_token { - my $grammar = $GRAMMAR->new; + my $parser = EmptyParser->new; + my $grammar = $GRAMMAR->new( { parser => $parser } ); my $plan = '1..1 # SKIP with explanation'; # trigger warning in _make_plan_token @@ -384,9 +396,9 @@ is_deeply $token, $expected, # _make_yaml_token { - my $stream = SS->new; - - my $grammar = $GRAMMAR->new($stream); + my $stream = SS->new; + my $parser = EmptyParser->new; + my $grammar = $GRAMMAR->new( { stream => $stream, parser => $parser } ); $grammar->set_version(13); diff --git a/lib/Test/Harness/t/harness.t b/lib/Test/Harness/t/harness.t index 484f2108b9..70ff42e452 100644 --- a/lib/Test/Harness/t/harness.t +++ b/lib/Test/Harness/t/harness.t @@ -22,7 +22,7 @@ my $HARNESS = 'TAP::Harness'; my $source_tests = $ENV{PERL_CORE} ? 'lib/source_tests' : 't/source_tests'; my $sample_tests = $ENV{PERL_CORE} ? 'lib/sample-tests' : 't/sample-tests'; -plan tests => 106; +plan tests => 113; # note that this test will always pass when run through 'prove' ok $ENV{HARNESS_ACTIVE}, 'HARNESS_ACTIVE env variable should be set'; @@ -536,6 +536,27 @@ SKIP: { is( $answer, "All tests successful.\n", 'cat meows' ); } +# make sure that we can exec with a code ref. +{ + my $capture = IO::c55Capture->new_handle; + my $harness = TAP::Harness->new( + { verbosity => -2, + stdout => $capture, + exec => sub {undef}, + } + ); + + _runtests( $harness, "$source_tests/harness" ); + + my @output = tied($$capture)->dump; + my $status = pop @output; + like $status, qr{^Result: PASS$}, + '... and the status line should be correct'; + pop @output; # get rid of summary line + my $answer = pop @output; + is( $answer, "All tests successful.\n", 'cat meows' ); +} + # catches "exec accumulates arguments" issue (r77) { my $capture = IO::c55Capture->new_handle; @@ -820,3 +841,49 @@ sub _runtests { $source_tests, 'harness' ); } + +{ + + # test name munging + my @cases = ( + { name => 'all the same', + input => [ 'foo.t', 'bar.t', 'fletz.t' ], + output => [ + [ 'foo.t', 'foo' ], [ 'bar.t', 'bar' ], [ 'fletz.t', 'fletz' ] + ], + }, + { name => 'all the same, already cooked', + input => [ 'foo.t', [ 'bar.t', 'brip' ], 'fletz.t' ], + output => [ + [ 'foo.t', 'foo' ], [ 'bar.t', 'brip' ], + [ 'fletz.t', 'fletz' ] + ], + }, + { name => 'different exts', + input => [ 'foo.t', 'bar.u', 'fletz.v' ], + output => [ + [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bar.u' ], + [ 'fletz.v', 'fletz.v' ] + ], + }, + { name => 'different exts, one already cooked', + input => [ 'foo.t', [ 'bar.u', 'bam' ], 'fletz.v' ], + output => [ + [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam' ], + [ 'fletz.v', 'fletz.v' ] + ], + }, + { name => 'different exts, two already cooked', + input => [ 'foo.t', [ 'bar.u', 'bam.q' ], [ 'fletz.v', 'boo' ] ], + output => [ + [ 'foo.t', 'foo.t' ], [ 'bar.u', 'bam.q' ], + [ 'fletz.v', 'boo' ] + ], + }, + ); + + for my $case (@cases) { + is_deeply [ TAP::Harness->_add_descriptions( @{ $case->{input} } ) ], + $case->{output}, '_add_descriptions: ' . $case->{name}; + } +} diff --git a/lib/Test/Harness/t/iterators.t b/lib/Test/Harness/t/iterators.t index 44d2004baf..11b2899b12 100644 --- a/lib/Test/Harness/t/iterators.t +++ b/lib/Test/Harness/t/iterators.t @@ -7,7 +7,7 @@ use Test::More tests => 76; use File::Spec; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; use Config; sub array_ref_from { @@ -41,8 +41,10 @@ my @schedule = ( source => { command => [ $^X, - File::Spec->catfile( ($ENV{PERL_CORE} ? 'lib' : 't'), - 'sample-tests', 'out_err_mix' ) + File::Spec->catfile( + ( $ENV{PERL_CORE} ? 'lib' : 't' ), + 'sample-tests', 'out_err_mix' + ) ], merge => 1, setup => $setup, @@ -79,6 +81,7 @@ sub _can_open3 { return $^O eq 'MSWin32' || $Config{d_fork}; } +my $factory = TAP::Parser::IteratorFactory->new; for my $test (@schedule) { SKIP: { my $name = $test->{name}; @@ -86,9 +89,12 @@ for my $test (@schedule) { skip "No open3", $need_open3 if $need_open3 && !_can_open3(); my $subclass = $test->{subclass}; my $source = $test->{source}; - my $class = $test->{class} || 'TAP::Parser::Iterator'; - ok my $iter = $class->new($source), - "$name: We should be able to create a new iterator"; + my $class = $test->{class}; + my $iter + = $class + ? $class->new($source) + : $factory->make_iterator($source); + ok $iter, "$name: We should be able to create a new iterator"; isa_ok $iter, 'TAP::Parser::Iterator', '... and the object it returns'; isa_ok $iter, $subclass, '... and the object it returns'; @@ -126,7 +132,7 @@ for my $test (@schedule) { # coverage tests for the ctor - my $stream = TAP::Parser::Iterator->new( IO::Handle->new ); + my $stream = $factory->make_iterator( IO::Handle->new ); isa_ok $stream, 'TAP::Parser::Iterator::Stream'; @@ -135,7 +141,7 @@ for my $test (@schedule) { eval { local $SIG{__DIE__} = sub { push @die, @_ }; - TAP::Parser::Iterator->new( \1 ); # a ref to a scalar + $factory->make_iterator( \1 ); # a ref to a scalar }; is @die, 1, 'coverage of error case'; @@ -148,7 +154,7 @@ for my $test (@schedule) { # coverage test for VMS case - my $stream = TAP::Parser::Iterator->new( + my $stream = $factory->make_iterator( [ 'not ', 'ok 1 - I hate VMS', ] @@ -159,7 +165,7 @@ for my $test (@schedule) { # coverage test for VMS case - nothing after 'not' - $stream = TAP::Parser::Iterator->new( + $stream = $factory->make_iterator( [ 'not ', ] ); @@ -177,7 +183,7 @@ SKIP: { eval { local $SIG{__DIE__} = sub { push @die, @_ }; - TAP::Parser::Iterator->new( {} ); + $factory->make_iterator( {} ); }; is @die, 1, 'coverage testing for TPI::Process'; @@ -185,7 +191,7 @@ SKIP: { like pop @die, qr/Must supply a command to execute/, '...and we died as expected'; - my $parser = TAP::Parser::Iterator->new( + my $parser = $factory->make_iterator( { command => [ $^X, File::Spec->catfile( 't', 'sample-tests', 'out_err_mix' ) @@ -194,7 +200,7 @@ SKIP: { } ); - is $parser->{err}, '', 'confirm we set err to empty string'; + is $parser->{err}, '', 'confirm we set err to empty string'; is $parser->{sel}, undef, '...and selector to undef'; # And then we read from the parser to sidestep the Mac OS / open3 diff --git a/lib/Test/Harness/t/multiplexer.t b/lib/Test/Harness/t/multiplexer.t index e74c15cd07..dd988dcee1 100644 --- a/lib/Test/Harness/t/multiplexer.t +++ b/lib/Test/Harness/t/multiplexer.t @@ -56,8 +56,8 @@ my @schedule = ( return [ TAP::Parser->new( { source => File::Spec->catfile( - ($ENV{PERL_CORE} ? 'lib' : 't'), 'sample-tests', - 'simple' + ( $ENV{PERL_CORE} ? 'lib' : 't' ), 'sample-tests', + 'simple' ), } ), @@ -76,8 +76,8 @@ my @schedule = ( return map { [ TAP::Parser->new( { source => File::Spec->catfile( - ($ENV{PERL_CORE} ? 'lib' : 't'), - 'sample-tests', 'simple' + ( $ENV{PERL_CORE} ? 'lib' : 't' ), + 'sample-tests', 'simple' ), } ), @@ -116,8 +116,8 @@ my @schedule = ( ( map { [ TAP::Parser->new( { source => File::Spec->catfile( - ($ENV{PERL_CORE} ? 'lib' : 't'), - 'sample-tests', 'simple' + ( $ENV{PERL_CORE} ? 'lib' : 't' ), + 'sample-tests', 'simple' ), } ), diff --git a/lib/Test/Harness/t/object.t b/lib/Test/Harness/t/object.t new file mode 100644 index 0000000000..b1a4dd0b98 --- /dev/null +++ b/lib/Test/Harness/t/object.t @@ -0,0 +1,37 @@ +#!/usr/bin/perl -wT + +use strict; +use lib 't/lib'; + +use Test::More tests => 7; + +use_ok('TAP::Object'); + +can_ok( 'TAP::Object', 'new' ); +can_ok( 'TAP::Object', '_initialize' ); +can_ok( 'TAP::Object', '_croak' ); + +{ + + package TAP::TestObj; + use vars qw(@ISA); + @ISA = qw(TAP::Object); + + sub _initialize { + my $self = shift; + $self->{init} = 1; + $self->{args} = [@_]; + return $self; + } +} + +# I know these tests are simple, but they're documenting the base API, so +# necessary none-the-less... +my $obj = TAP::TestObj->new( 'foo', { bar => 'baz' } ); +ok( $obj->{init}, '_initialize' ); +is_deeply( $obj->{args}, [ 'foo', { bar => 'baz' } ], '_initialize: args' ); + +eval { $obj->_croak('eek') }; +my $err = $@; +like( $err, qr/^eek/, '_croak' ); + diff --git a/lib/Test/Harness/t/parse.t b/lib/Test/Harness/t/parse.t index a53ad3a746..7118199a51 100755 --- a/lib/Test/Harness/t/parse.t +++ b/lib/Test/Harness/t/parse.t @@ -12,13 +12,13 @@ BEGIN { } } -use Test::More tests => 268; +use Test::More tests => 282; use IO::c55Capture; use File::Spec; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; sub _get_results { my $parser = shift; @@ -41,6 +41,8 @@ my ( $PARSER, $PLAN, $PRAGMA, $TEST, $COMMENT, $BAILOUT, $UNKNOWN, $YAML, $VERSI TAP::Parser::Result::Version ); +my $factory = TAP::Parser::IteratorFactory->new; + my $tap = <<'END_TAP'; TAP version 13 1..7 @@ -220,7 +222,7 @@ 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 teh correct directive'; +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'; @@ -349,7 +351,7 @@ END_TAP my $aref = [ split /\n/ => $tap ]; can_ok $PARSER, 'new'; -$parser = $PARSER->new( { stream => TAP::Parser::Iterator->new($aref) } ); +$parser = $PARSER->new( { stream => $factory->make_iterator($aref) } ); isa_ok $parser, $PARSER, '... and calling it should succeed'; # results() is sane? @@ -436,29 +438,6 @@ is $test->raw, 'ok 2 - read the rest of the file', is scalar $parser->passed, 2, 'Empty junk lines should not affect the correct number of tests passed'; -# coverage tests -{ - - # calling a TAP::Parser internal method with a 'foreign' class - - my $foreigner = bless {}, 'Foreigner'; - - my @die; - - eval { - local $SIG{__DIE__} = sub { push @die, @_ }; - - TAP::Parser::_stream $foreigner, qw(a b c); - }; - - unless ( is @die, 1, 'coverage testing for TAP::Parser accessors' ) { - diag " >>> $_ <<<\n" for @die; - } - - like pop @die, qr/_stream[(][)] may not be set externally/, - '... and we died with expected message'; -} - { # set a spool to write to @@ -662,10 +641,10 @@ END_TAP _get_results($parser); - ok !$parser->failed; - ok $parser->todo_passed; + ok !$parser->failed, 'parser didnt fail'; + ok $parser->todo_passed, '... and todo_passed is true'; - ok !$parser->has_problems, 'and has_problems is false'; + ok !$parser->has_problems, '... and has_problems is false'; # now parse_errors @@ -679,11 +658,11 @@ END_TAP _get_results($parser); - ok !$parser->failed; - ok !$parser->todo_passed; - ok $parser->parse_errors; + 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; + 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 @@ -701,27 +680,27 @@ END_TAP $parser->wait(1); - ok !$parser->failed; - ok !$parser->todo_passed; - ok !$parser->parse_errors; + 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; + ok $parser->wait, '... and wait is set'; - ok $parser->has_problems; + ok $parser->has_problems, '... and has_problems'; # and use the same for exit $parser->wait(0); $parser->exit(1); - ok !$parser->failed; - ok !$parser->todo_passed; - ok !$parser->parse_errors; - ok !$parser->wait; + 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; + ok $parser->exit, '... and exit is set'; - ok $parser->has_problems; + ok $parser->has_problems, '... and has_problems'; } { @@ -807,10 +786,6 @@ END_TAP @ISA = qw(TAP::Parser::Iterator); - sub new { - return bless {}, shift; - } - sub next_raw { die 'this is the dying iterator'; } @@ -840,7 +815,11 @@ END_TAP $parser->_stream($stream); # build a new grammar - my $grammar = TAP::Parser::Grammar->new($stream); + my $grammar = TAP::Parser::Grammar->new( + { stream => $stream, + parser => $parser + } + ); # replace our grammar with this new one $parser->_grammar($grammar); @@ -872,7 +851,11 @@ END_TAP $parser->_stream($stream); # build a new grammar - my $grammar = TAP::Parser::Grammar->new($stream); + my $grammar = TAP::Parser::Grammar->new( + { stream => $stream, + parser => $parser + } + ); # replace our grammar with this new one $parser->_grammar($grammar); @@ -1018,3 +1001,40 @@ END_TAP 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 } + ) + ); + } +} diff --git a/lib/Test/Harness/t/parser-config.t b/lib/Test/Harness/t/parser-config.t new file mode 100644 index 0000000000..cf0a246a03 --- /dev/null +++ b/lib/Test/Harness/t/parser-config.t @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +BEGIN { + if ( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ( '../lib', 'lib' ); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use vars qw(%INIT %CUSTOM); + +use Test::More tests => 11; +use File::Spec::Functions qw( catfile ); +use TAP::Parser; + +use_ok('MySource'); +use_ok('MyPerlSource'); +use_ok('MyGrammar'); +use_ok('MyIteratorFactory'); +use_ok('MyResultFactory'); + +my $t_dir = $ENV{PERL_CORE} ? 'lib' : 't'; +my $source = catfile( $t_dir, 'source_tests', 'source' ); +my %customize = ( + source_class => 'MySource', + perl_source_class => 'MyPerlSource', + grammar_class => 'MyGrammar', + iterator_factory_class => 'MyIteratorFactory', + result_factory_class => 'MyResultFactory', +); +my $p = TAP::Parser->new( + { source => $source, + %customize, + } +); +ok( $p, 'new customized parser' ); + +foreach my $key ( keys %customize ) { + is( $p->$key(), $customize{$key}, "customized $key" ); +} + +# TODO: make sure these things are propogated down through the parser... diff --git a/lib/Test/Harness/t/parser-subclass.t b/lib/Test/Harness/t/parser-subclass.t new file mode 100644 index 0000000000..f522f89aff --- /dev/null +++ b/lib/Test/Harness/t/parser-subclass.t @@ -0,0 +1,88 @@ +#!/usr/bin/perl -w + +BEGIN { + if ( $ENV{PERL_CORE} ) { + chdir 't'; + @INC = ( '../lib', 'lib' ); + } + else { + unshift @INC, 't/lib'; + } +} + +use strict; +use vars qw(%INIT %CUSTOM); + +use Test::More tests => 24; +use File::Spec::Functions qw( catfile ); + +use_ok('TAP::Parser::SubclassTest'); + +# TODO: foreach my $source ( ... ) +my $t_dir = $ENV{PERL_CORE} ? 'lib' : 't'; + +{ # perl source + %INIT = %CUSTOM = (); + my $source = catfile( $t_dir, 'subclass_tests', 'perl_source' ); + my $p = TAP::Parser::SubclassTest->new( { source => $source } ); + + # The grammar is lazily constructed so we need to ask for it to + # trigger it's creation. + my $grammer = $p->_grammar; + + ok( $p->{initialized}, 'new subclassed parser' ); + + is( $p->source_class => 'MySource', 'source_class' ); + is( $p->perl_source_class => 'MyPerlSource', 'perl_source_class' ); + is( $p->grammar_class => 'MyGrammar', 'grammar_class' ); + is( $p->iterator_factory_class => 'MyIteratorFactory', + 'iterator_factory_class' + ); + is( $p->result_factory_class => 'MyResultFactory', + 'result_factory_class' + ); + + is( $INIT{MyPerlSource}, 1, 'initialized MyPerlSource' ); + is( $CUSTOM{MyPerlSource}, 1, '... and it was customized' ); + is( $INIT{MyGrammar}, 1, 'initialized MyGrammar' ); + is( $CUSTOM{MyGrammar}, 1, '... and it was customized' ); + + # make sure overrided make_* methods work... + %CUSTOM = (); + $p->make_source; + is( $CUSTOM{MySource}, 1, 'make custom source' ); + $p->make_perl_source; + is( $CUSTOM{MyPerlSource}, 1, 'make custom perl source' ); + $p->make_grammar; + is( $CUSTOM{MyGrammar}, 1, 'make custom grammar' ); + $p->make_iterator; + is( $CUSTOM{MyIterator}, 1, 'make custom iterator' ); + $p->make_result; + is( $CUSTOM{MyResult}, 1, 'make custom result' ); + + # make sure parser helpers use overrided classes too (the parser should + # be the central source of configuration/overriding functionality) + # The source is already tested above (parser doesn't keep a copy of the + # source currently). So only one to check is the Grammar: + %INIT = %CUSTOM = (); + my $r = $p->_grammar->tokenize; + isa_ok( $r, 'MyResult', 'i has results' ); + is( $INIT{MyResult}, 1, 'initialized MyResult' ); + is( $CUSTOM{MyResult}, 1, '... and it was customized' ); + is( $INIT{MyResultFactory}, 1, '"initialized" MyResultFactory' ); +} + +SKIP: { # non-perl source + %INIT = %CUSTOM = (); + my $cat = '/bin/cat'; + unless ( -e $cat ) { + skip "no '$cat'", 4; + } + my $file = catfile( $t_dir, 'data', 'catme.1' ); + my $p = TAP::Parser::SubclassTest->new( { exec => [ $cat => $file ] } ); + + is( $INIT{MySource}, 1, 'initialized MySource subclass' ); + is( $CUSTOM{MySource}, 1, '... and it was customized' ); + is( $INIT{MyIterator}, 1, 'initialized MyIterator subclass' ); + is( $CUSTOM{MyIterator}, 1, '... and it was customized' ); +} diff --git a/lib/Test/Harness/t/premature-bailout.t b/lib/Test/Harness/t/premature-bailout.t index d38e6d189a..9226a44064 100644 --- a/lib/Test/Harness/t/premature-bailout.t +++ b/lib/Test/Harness/t/premature-bailout.t @@ -6,7 +6,7 @@ use lib 't/lib'; use Test::More tests => 14; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; sub tap_to_lines { my $string = shift; @@ -26,8 +26,9 @@ Bail out! We ran out of foobar. not ok 5 END_TAP -my $parser = TAP::Parser->new( - { stream => TAP::Parser::Iterator->new( tap_to_lines($tap) ), +my $factory = TAP::Parser::IteratorFactory->new; +my $parser = TAP::Parser->new( + { stream => $factory->make_iterator( tap_to_lines($tap) ), } ); @@ -105,7 +106,7 @@ is( $bailout->explanation, 'We ran out of foobar.', my $more_tap = "1..1\nok 1 - input file opened\n"; my $second_parser = TAP::Parser->new( - { stream => TAP::Parser::Iterator->new( [ split( /\n/, $more_tap ) ] ), + { stream => $factory->make_iterator( [ split( /\n/, $more_tap ) ] ), } ); diff --git a/lib/Test/Harness/t/process.t b/lib/Test/Harness/t/process.t index e4d585e261..5adddc9017 100644 --- a/lib/Test/Harness/t/process.t +++ b/lib/Test/Harness/t/process.t @@ -9,9 +9,11 @@ BEGIN { $hires = eval 'use Time::HiRes qw(sleep); 1'; } -use Test::More ( $^O eq 'VMS' ? ( skip_all => 'VMS' ) - : $hires ? ( tests => 9 * 3 ) - : ( skip_all => 'Need Time::HiRes' ) ); +use Test::More ( + $^O eq 'VMS' ? ( skip_all => 'VMS' ) + : $hires ? ( tests => 9 * 3 ) + : ( skip_all => 'Need Time::HiRes' ) +); use File::Spec; use TAP::Parser::Iterator::Process; @@ -25,8 +27,10 @@ my @expect = ( 'ok 5 00000', ); -my $source = File::Spec->catfile( ($ENV{PERL_CORE} ? 'lib' : 't'), - 'sample-tests', 'delayed' ); +my $source = File::Spec->catfile( + ( $ENV{PERL_CORE} ? 'lib' : 't' ), + 'sample-tests', 'delayed' +); for my $chunk_size ( 1, 4, 65536 ) { for my $where ( 0 .. 8 ) { diff --git a/lib/Test/Harness/t/prove.t b/lib/Test/Harness/t/prove.t index 02d2e31202..38b9b85097 100644 --- a/lib/Test/Harness/t/prove.t +++ b/lib/Test/Harness/t/prove.t @@ -75,9 +75,10 @@ BEGIN { # START PLAN # list of attributes @ATTR = qw( - archive argv blib color directives exec failures formatter harness - includes lib merge parse quiet really_quiet recurse backwards - shuffle taint_fail taint_warn verbose warnings_fail warnings_warn + archive argv blib color directives exec extension failures + formatter harness includes lib merge parse quiet really_quiet + recurse backwards shuffle taint_fail taint_warn verbose + warnings_fail warnings_warn ); # what we expect if the 'expect' hash does not define it diff --git a/lib/Test/Harness/t/proveenv.t b/lib/Test/Harness/t/proveenv.t new file mode 100644 index 0000000000..be9942a043 --- /dev/null +++ b/lib/Test/Harness/t/proveenv.t @@ -0,0 +1,17 @@ +#!perl +use strict; +use lib 't/lib'; +use Test::More tests => 2; +use App::Prove; + +{ + local $ENV{HARNESS_TIMER} = 0; + my $prv = App::Prove->new; + ok !$prv->timer, 'timer set via HARNESS_TIMER'; +} + +{ + local $ENV{HARNESS_TIMER} = 1; + my $prv = App::Prove->new; + ok $prv->timer, 'timer set via HARNESS_TIMER'; +} diff --git a/lib/Test/Harness/t/proverun.t b/lib/Test/Harness/t/proverun.t index 6cda6c4532..b40d56362d 100644 --- a/lib/Test/Harness/t/proverun.t +++ b/lib/Test/Harness/t/proverun.t @@ -44,7 +44,7 @@ BEGIN { }, ); - plan tests => @SCHEDULE * 2; + plan tests => @SCHEDULE * 3; } # Waaaaay too much boilerplate @@ -61,12 +61,6 @@ sub new { return $self; } -sub _exit { - my $self = shift; - push @{ $self->{_log} }, [ '_exit', @_ ]; - die "Exited"; -} - sub get_log { my $self = shift; my @log = @{ $self->{_log} }; @@ -85,14 +79,17 @@ package main; local $^W; # no warnings - my $orig_new = \&TAP::Parser::Iterator::Process::new; - *TAP::Parser::Iterator::Process::new = sub { + my $orig_new = TAP::Parser::Iterator::Process->can('new'); + + # Avoid "used only once" warning + *TAP::Parser::Iterator::Process::new + = *TAP::Parser::Iterator::Process::new = sub { push @call_log, [ 'new', @_ ]; # And then new turns round and tramples on our args... $_[1] = { %{ $_[1] } }; $orig_new->(@_); - }; + }; # Patch TAP::Formatter::Console; my $orig_output = \&TAP::Formatter::Console::_output; @@ -143,8 +140,8 @@ for my $test (@SCHEDULE) { # Why does this make the output from the test spew out of # our STDOUT? - eval { $app->run }; - like $@, qr{Exited}, "$name: exited via _exit()"; + ok eval { $app->run }, 'run returned true'; + ok !$@, 'no errors'; my @log = get_log(); diff --git a/lib/Test/Harness/t/regression.t b/lib/Test/Harness/t/regression.t index 5398580c7b..c029a050a9 100644 --- a/lib/Test/Harness/t/regression.t +++ b/lib/Test/Harness/t/regression.t @@ -2198,7 +2198,7 @@ my %samples = ( passed => TRUE, is_ok => TRUE, directive => 'SKIP', - explanation => 'rope' + explanation => '' }, ], plan => '1..0', @@ -2217,7 +2217,7 @@ my %samples = ( 'exit' => 0, wait => 0, version => 12, - skip_all => 'rope', + skip_all => '(no reason given)', }, skipall_v13 => { results => [ diff --git a/lib/Test/Harness/t/results.t b/lib/Test/Harness/t/results.t index 431bb7dc71..0522dd6299 100644 --- a/lib/Test/Harness/t/results.t +++ b/lib/Test/Harness/t/results.t @@ -3,8 +3,9 @@ use strict; use lib 't/lib'; -use Test::More tests => 222; +use Test::More tests => 227; +use TAP::Parser::ResultFactory; use TAP::Parser::Result; use constant RESULT => 'TAP::Parser::Result'; @@ -22,6 +23,7 @@ $SIG{__WARN__} = sub { $warning = shift }; # found in the regression tests. # +my $factory = TAP::Parser::ResultFactory->new; my %inherited_methods = ( is_plan => '', is_test => '', @@ -46,11 +48,32 @@ like $warning, qr/^\Qpassed() is deprecated. Please use "is_ok()"/, '... but it should emit a deprecation warning'; can_ok RESULT, 'new'; -eval { RESULT->new( { type => 'no_such_type' } ) }; + +can_ok $factory, 'make_result'; +eval { $factory->make_result( { type => 'no_such_type' } ) }; ok my $error = $@, '... and calling it with an unknown class should fail'; like $error, qr/^Could not determine class for.*no_such_type/s, '... with an appropriate error message'; +# register new Result types: +can_ok $factory, 'class_for'; +can_ok $factory, 'register_type'; +{ + + package MyResult; + use strict; + use vars qw($VERSION @ISA); + @ISA = 'TAP::Parser::Result'; + TAP::Parser::ResultFactory->register_type( 'my_type' => __PACKAGE__ ); +} + +{ + my $r = eval { $factory->make_result( { type => 'my_type' } ) }; + my $error = $@; + isa_ok( $r, 'MyResult', 'register custom type' ); + ok( !$error, '... and no error' ); +} + # # test unknown tokens # @@ -246,7 +269,7 @@ sub run_tests { sub instantiate { my $instantiated = shift; my $class = $instantiated->{class}; - ok my $result = RESULT->new( $instantiated->{data} ), + ok my $result = $factory->make_result( $instantiated->{data} ), 'Creating $class results should succeed'; isa_ok $result, $class, '.. and the object it returns'; return $result; diff --git a/lib/Test/Harness/t/scheduler.t b/lib/Test/Harness/t/scheduler.t new file mode 100644 index 0000000000..b2742078b1 --- /dev/null +++ b/lib/Test/Harness/t/scheduler.t @@ -0,0 +1,225 @@ +#!/usr/bin/perl -w + +use strict; +use lib 't/lib'; + +use Test::More; +use TAP::Parser::Scheduler; + +my $perl_rules = { + par => [ + { seq => '../ext/DB_File/t/*' }, + { seq => '../ext/IO_Compress_Zlib/t/*' }, + { seq => '../lib/CPANPLUS/*' }, + { seq => '../lib/ExtUtils/t/*' }, + '*' + ] +}; + +my $incomplete_rules = { par => [ { seq => [ '*A', '*D' ] } ] }; + +my $some_tests = [ + '../ext/DB_File/t/A', + 'foo', + '../ext/DB_File/t/B', + '../ext/DB_File/t/C', + '../lib/CPANPLUS/D', + '../lib/CPANPLUS/E', + 'bar', + '../lib/CPANPLUS/F', + '../ext/DB_File/t/D', + '../ext/DB_File/t/E', + '../ext/DB_File/t/F', +]; + +my @schedule = ( + { name => 'Sequential, no rules', + tests => $some_tests, + jobs => 1, + }, + { name => 'Sequential, Perl rules', + rules => $perl_rules, + tests => $some_tests, + jobs => 1, + }, + { name => 'Two in parallel, Perl rules', + rules => $perl_rules, + tests => $some_tests, + jobs => 2, + }, + { name => 'Massively parallel, Perl rules', + rules => $perl_rules, + tests => $some_tests, + jobs => 1000, + }, + { name => 'Massively parallel, no rules', + tests => $some_tests, + jobs => 1000, + }, + { name => 'Sequential, incomplete rules', + rules => $incomplete_rules, + tests => $some_tests, + jobs => 1, + }, + { name => 'Two in parallel, incomplete rules', + rules => $incomplete_rules, + tests => $some_tests, + jobs => 2, + }, + { name => 'Massively parallel, incomplete rules', + rules => $incomplete_rules, + tests => $some_tests, + jobs => 1000, + }, +); + +plan tests => @schedule * 2 + 266; + +for my $test (@schedule) { + test_scheduler( + $test->{name}, + $test->{tests}, + $test->{rules}, + $test->{jobs} + ); +} + +# An ad-hoc test + +{ + my @tests = qw( + A1 A2 A3 B1 C1 C8 C5 C7 C4 C6 C3 C2 C9 D1 D2 D3 E3 E2 E1 + ); + + my $rules = { + par => [ + { seq => 'A*' }, + { par => 'B*' }, + { seq => [ 'C1', 'C2' ] }, + { par => [ + { seq => [ 'C3', 'C4', 'C5' ] }, + { seq => [ 'C6', 'C7', 'C8' ] } + ] + }, + { seq => [ + { par => ['D*'] }, + { par => ['E*'] } + ] + }, + ] + }; + + my $scheduler = TAP::Parser::Scheduler->new( + tests => \@tests, + rules => $rules + ); + + # diag $scheduler->as_string; + + my $A1 = ok_job( $scheduler, 'A1' ); + my $B1 = ok_job( $scheduler, 'B1' ); + finish($A1); + my $A2 = ok_job( $scheduler, 'A2' ); + my $C1 = ok_job( $scheduler, 'C1' ); + finish( $A2, $C1 ); + my $A3 = ok_job( $scheduler, 'A3' ); + my $C2 = ok_job( $scheduler, 'C2' ); + finish( $A3, $C2 ); + my $C3 = ok_job( $scheduler, 'C3' ); + my $C6 = ok_job( $scheduler, 'C6' ); + my $D1 = ok_job( $scheduler, 'D1' ); + my $D2 = ok_job( $scheduler, 'D2' ); + finish($C6); + my $C7 = ok_job( $scheduler, 'C7' ); + my $D3 = ok_job( $scheduler, 'D3' ); + ok_job( $scheduler, '#' ); + ok_job( $scheduler, '#' ); + finish( $D3, $C3, $D1, $B1 ); + my $C4 = ok_job( $scheduler, 'C4' ); + finish( $C4, $C7 ); + my $C5 = ok_job( $scheduler, 'C5' ); + my $C8 = ok_job( $scheduler, 'C8' ); + ok_job( $scheduler, '#' ); + finish($D2); + my $E3 = ok_job( $scheduler, 'E3' ); + my $E2 = ok_job( $scheduler, 'E2' ); + my $E1 = ok_job( $scheduler, 'E1' ); + finish( $E1, $E2, $E3, $C5, $C8 ); + my $C9 = ok_job( $scheduler, 'C9' ); + ok_job( $scheduler, undef ); +} + +{ + my @tests = (); + for my $t ( 'A' .. 'Z' ) { + push @tests, map {"$t$_"} 1 .. 9; + } + my $rules = { par => [ map { { seq => "$_*" } } 'A' .. 'Z' ] }; + + my $scheduler = TAP::Parser::Scheduler->new( + tests => \@tests, + rules => $rules + ); + + # diag $scheduler->as_string; + + for my $n ( 1 .. 9 ) { + my @got = (); + push @got, ok_job( $scheduler, "$_$n" ) for 'A' .. 'Z'; + ok_job( $scheduler, $n == 9 ? undef : '#' ); + finish(@got); + } +} + +sub finish { $_->finish for @_ } + +sub ok_job { + my ( $scheduler, $want ) = @_; + my $job = $scheduler->get_job; + if ( !defined $want ) { + ok !defined $job, 'undef'; + } + elsif ( $want eq '#' ) { + ok $job->is_spinner, 'spinner'; + } + else { + is $job->filename, $want, $want; + } + return $job; +} + +sub test_scheduler { + my ( $name, $tests, $rules, $jobs ) = @_; + + ok my $scheduler = TAP::Parser::Scheduler->new( + tests => $tests, + defined $rules ? ( rules => $rules ) : (), + ), + "$name: new"; + + # diag $scheduler->as_string; + + my @pipeline = (); + my @got = (); + + while ( defined( my $job = $scheduler->get_job ) ) { + + # diag $scheduler->as_string; + if ( $job->is_spinner || @pipeline >= $jobs ) { + die "Oops! Spinner!" unless @pipeline; + my $done = shift @pipeline; + $done->finish; + + # diag "Completed ", $done->filename; + } + next if $job->is_spinner; + + # diag " Got ", $job->filename; + push @pipeline, $job; + + push @got, $job->filename; + } + + is_deeply [ sort @got ], [ sort @$tests ], "$name: got all tests"; +} + diff --git a/lib/Test/Harness/t/source.t b/lib/Test/Harness/t/source.t index cfdf751f72..8f7e60f2e3 100644 --- a/lib/Test/Harness/t/source.t +++ b/lib/Test/Harness/t/source.t @@ -12,14 +12,16 @@ BEGIN { use strict; -use Test::More tests => 30; +use Test::More tests => 26; use File::Spec; +use EmptyParser; use TAP::Parser::Source; use TAP::Parser::Source::Perl; -my $test = File::Spec->catfile( +my $parser = EmptyParser->new; +my $test = File::Spec->catfile( ( $ENV{PERL_CORE} ? 'lib' : 't' ), 'source_tests', 'source' ); @@ -39,7 +41,7 @@ ok $source->source( [ $perl, '-It/lib', '-T', $test ] ), '... and calling it with valid args should succeed'; can_ok $source, 'get_stream'; -my $stream = $source->get_stream; +my $stream = $source->get_stream($parser); isa_ok $stream, 'TAP::Parser::Iterator::Process', 'get_stream returns the right object'; @@ -57,7 +59,7 @@ ok $source->source( [$test] ), '... and calling it with valid args should succeed'; can_ok $source, 'get_stream'; -$stream = $source->get_stream; +$stream = $source->get_stream($parser); isa_ok $stream, 'TAP::Parser::Iterator::Process', '... and the object it returns'; @@ -79,7 +81,7 @@ ok( grep( $_ =~ /^['"]?-T['"]?$/, $source->_switches ), # coverage for method get_steam - my $source = TAP::Parser::Source->new(); + my $source = TAP::Parser::Source->new( { parser => $parser } ); my @die; @@ -94,36 +96,3 @@ ok( grep( $_ =~ /^['"]?-T['"]?$/, $source->_switches ), like pop @die, qr/No command found!/, '...and it failed as expect'; } -{ - - # coverage testing for error - - my $source = TAP::Parser::Source->new(); - - my $error = $source->error; - - is $error, undef, 'coverage testing for error()'; - - $source->error('save me'); - - $error = $source->error; - - is $error, 'save me', '...and we got the expected message'; -} - -{ - - # coverage testing for exit - - my $source = TAP::Parser::Source->new(); - - my $exit = $source->exit; - - is $exit, undef, 'coverage testing for exit()'; - - $source->exit('save me'); - - $exit = $source->exit; - - is $exit, 'save me', '...and we got the expected message'; -} diff --git a/lib/Test/Harness/t/spool.t b/lib/Test/Harness/t/spool.t index 428423ac02..deb1a0205f 100644 --- a/lib/Test/Harness/t/spool.t +++ b/lib/Test/Harness/t/spool.t @@ -117,8 +117,9 @@ ok 1 - input file opened END_TAP my $parser = TAP::Parser->new( - { spool => $spoolHandle, - stream => TAP::Parser::Iterator->new( [ split /\n/ => $tap ] ) + { spool => $spoolHandle, + stream => + TAP::Parser::IteratorFactory->new( [ split /\n/ => $tap ] ) } ); diff --git a/lib/Test/Harness/t/streams.t b/lib/Test/Harness/t/streams.t index fba0591b3e..b312ae8367 100755 --- a/lib/Test/Harness/t/streams.t +++ b/lib/Test/Harness/t/streams.t @@ -6,13 +6,15 @@ use lib 't/lib'; use Test::More tests => 47; use TAP::Parser; -use TAP::Parser::Iterator; +use TAP::Parser::IteratorFactory; -my ( $STREAMED, $ITER ) = ( 'TAP::Parser', 'TAP::Parser::Iterator' ); +my $STREAMED = 'TAP::Parser'; +my $ITER = 'TAP::Parser::Iterator'; my $ITER_FH = "${ITER}::Stream"; my $ITER_ARRAY = "${ITER}::Array"; -my $stream = TAP::Parser::Iterator->new( \*DATA ); +my $factory = TAP::Parser::IteratorFactory->new; +my $stream = $factory->make_iterator( \*DATA ); isa_ok $stream, 'TAP::Parser::Iterator'; my $parser = TAP::Parser->new( { stream => $stream } ); isa_ok $parser, 'TAP::Parser', @@ -55,7 +57,7 @@ ok 5 # skip we have no description 1..5 END_TAP -$stream = $ITER->new( [ split /\n/ => $tap ] ); +$stream = $factory->make_iterator( [ split /\n/ => $tap ] ); ok $parser = TAP::Parser->new( { stream => $stream } ), 'Now we create a parser with the plan at the end'; isa_ok $parser->_stream, $ITER_ARRAY, @@ -93,7 +95,7 @@ not ok 4 - this is a real failure ok 5 # skip we have no description END_TAP -$stream = $ITER->new( [ split /\n/ => $tap ] ); +$stream = $factory->make_iterator( [ split /\n/ => $tap ] ); ok $parser = TAP::Parser->new( { stream => $stream } ), 'Now we create a parser with a plan as the second line'; @@ -131,7 +133,7 @@ not ok 4 - this is a real failure ok 5 # skip we have no description END_TAP -$stream = $ITER->new( [ split /\n/ => $tap ] ); +$stream = $factory->make_iterator( [ split /\n/ => $tap ] ); ok $parser = TAP::Parser->new( { stream => $stream } ), 'Now we create a parser with the plan as the second to last line'; diff --git a/lib/Test/Harness/t/testargs.t b/lib/Test/Harness/t/testargs.t index 76ee9a5bb6..9160c5909b 100644 --- a/lib/Test/Harness/t/testargs.t +++ b/lib/Test/Harness/t/testargs.t @@ -13,8 +13,10 @@ use TAP::Parser; use TAP::Harness; use App::Prove; -my $test = File::Spec->catfile( ($ENV{PERL_CORE} ? 'lib' : 't'), - 'sample-tests', 'echo' ); +my $test = File::Spec->catfile( + ( $ENV{PERL_CORE} ? 'lib' : 't' ), + 'sample-tests', 'echo' +); diag( "\n\n", bigness( join ' ', @ARGV ), "\n\n" ) if @ARGV; diff --git a/lib/Test/Harness/t/unicode.t b/lib/Test/Harness/t/unicode.t index de52689ea0..88d32081ba 100644 --- a/lib/Test/Harness/t/unicode.t +++ b/lib/Test/Harness/t/unicode.t @@ -9,6 +9,7 @@ my @schedule; my %make_test; BEGIN { + # TODO: Investigate failure on 5.8.0 plan skip_all => "unicode on Perl <= 5.8.0" unless $] > 5.008; diff --git a/lib/Test/Harness/t/yamlish.t b/lib/Test/Harness/t/yamlish.t index 3cdaf541df..76ba7982b4 100644 --- a/lib/Test/Harness/t/yamlish.t +++ b/lib/Test/Harness/t/yamlish.t @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!perl -w use strict; use lib 't/lib'; @@ -48,6 +48,15 @@ BEGIN { ], out => "Hello, World\n", }, + { name => 'Hello World Block', + in => [ + '--- |', + ' Hello,', + ' World', + '...', + ], + out => "Hello,\n World\n", + }, { name => 'Hello World 5', in => [ '--- >', @@ -128,7 +137,10 @@ BEGIN { six => '6' }, }, - + { name => 'Space after colon', + in => [ '---', 'spog: ', ' - 1', ' - 2', '...' ], + out => { spog => [ 1, 2 ] }, + }, { name => 'Original YAML::Tiny test', in => [ '---', @@ -471,6 +483,10 @@ BEGIN { "\n\t" => 'newline, tab', }, }, + { name => 'Empty', + in => [], + out => undef, + }, ); plan tests => @SCHEDULE * 5; |