summaryrefslogtreecommitdiff
path: root/cpan/Test-Harness/t
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2009-10-02 15:57:26 +0100
committerNicholas Clark <nick@ccl4.org>2009-10-02 15:57:26 +0100
commitb8a2040150d386de90994afd87f9d01bd861104a (patch)
tree9418ac04b77045e3bb187954c5fbf873557f7474 /cpan/Test-Harness/t
parent8d4ff56f76907d1619ddc5fd7040d3823057ec47 (diff)
downloadperl-b8a2040150d386de90994afd87f9d01bd861104a.tar.gz
Move Test::Harness from ext/ to cpan/
Diffstat (limited to 'cpan/Test-Harness/t')
-rw-r--r--cpan/Test-Harness/t/000-load.t61
-rw-r--r--cpan/Test-Harness/t/aggregator.t305
-rw-r--r--cpan/Test-Harness/t/bailout.t114
-rw-r--r--cpan/Test-Harness/t/base.t173
-rw-r--r--cpan/Test-Harness/t/callbacks.t116
-rw-r--r--cpan/Test-Harness/t/compat/env.t39
-rw-r--r--cpan/Test-Harness/t/compat/failure.t56
-rw-r--r--cpan/Test-Harness/t/compat/inc-propagation.t57
-rw-r--r--cpan/Test-Harness/t/compat/inc_taint.t33
-rw-r--r--cpan/Test-Harness/t/compat/nonumbers.t14
-rw-r--r--cpan/Test-Harness/t/compat/regression.t19
-rw-r--r--cpan/Test-Harness/t/compat/switches.t17
-rw-r--r--cpan/Test-Harness/t/compat/test-harness-compat.t851
-rw-r--r--cpan/Test-Harness/t/compat/version.t11
-rw-r--r--cpan/Test-Harness/t/console.t47
-rw-r--r--cpan/Test-Harness/t/data/catme.12
-rw-r--r--cpan/Test-Harness/t/data/proverc7
-rw-r--r--cpan/Test-Harness/t/data/sample.yml29
-rw-r--r--cpan/Test-Harness/t/errors.t183
-rw-r--r--cpan/Test-Harness/t/file.t475
-rw-r--r--cpan/Test-Harness/t/glob-to-regexp.t44
-rw-r--r--cpan/Test-Harness/t/grammar.t455
-rw-r--r--cpan/Test-Harness/t/harness-bailout.t54
-rw-r--r--cpan/Test-Harness/t/harness-subclass.t65
-rw-r--r--cpan/Test-Harness/t/harness.t982
-rw-r--r--cpan/Test-Harness/t/iterators.t215
-rw-r--r--cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy.pm9
-rw-r--r--cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy2.pm13
-rw-r--r--cpan/Test-Harness/t/lib/Dev/Null.pm18
-rw-r--r--cpan/Test-Harness/t/lib/EmptyParser.pm30
-rw-r--r--cpan/Test-Harness/t/lib/IO/c55Capture.pm120
-rw-r--r--cpan/Test-Harness/t/lib/MyCustom.pm12
-rw-r--r--cpan/Test-Harness/t/lib/MyGrammar.pm21
-rw-r--r--cpan/Test-Harness/t/lib/MyIterator.pm26
-rw-r--r--cpan/Test-Harness/t/lib/MyIteratorFactory.pm19
-rw-r--r--cpan/Test-Harness/t/lib/MyPerlSource.pm27
-rw-r--r--cpan/Test-Harness/t/lib/MyResult.pm21
-rw-r--r--cpan/Test-Harness/t/lib/MyResultFactory.pm23
-rw-r--r--cpan/Test-Harness/t/lib/MySource.pm34
-rw-r--r--cpan/Test-Harness/t/lib/NOP.pm7
-rw-r--r--cpan/Test-Harness/t/lib/NoFork.pm21
-rw-r--r--cpan/Test-Harness/t/lib/TAP/Parser/SubclassTest.pm39
-rw-r--r--cpan/Test-Harness/t/multiplexer.t170
-rw-r--r--cpan/Test-Harness/t/nofork-mux.t10
-rw-r--r--cpan/Test-Harness/t/nofork.t59
-rw-r--r--cpan/Test-Harness/t/object.t37
-rw-r--r--cpan/Test-Harness/t/parse.t1058
-rw-r--r--cpan/Test-Harness/t/parser-config.t39
-rw-r--r--cpan/Test-Harness/t/parser-subclass.t80
-rw-r--r--cpan/Test-Harness/t/perl5lib.t51
-rw-r--r--cpan/Test-Harness/t/premature-bailout.t125
-rw-r--r--cpan/Test-Harness/t/process.t53
-rw-r--r--cpan/Test-Harness/t/prove.t1525
-rw-r--r--cpan/Test-Harness/t/proveenv.t17
-rw-r--r--cpan/Test-Harness/t/proverc.t23
-rw-r--r--cpan/Test-Harness/t/proverc/emptyexec2
-rw-r--r--cpan/Test-Harness/t/proverun.t176
-rw-r--r--cpan/Test-Harness/t/regression.t3264
-rw-r--r--cpan/Test-Harness/t/results.t295
-rw-r--r--cpan/Test-Harness/t/sample-tests/bailout11
-rw-r--r--cpan/Test-Harness/t/sample-tests/bignum7
-rw-r--r--cpan/Test-Harness/t/sample-tests/bignum_many14
-rw-r--r--cpan/Test-Harness/t/sample-tests/combined13
-rw-r--r--cpan/Test-Harness/t/sample-tests/combined_compat13
-rw-r--r--cpan/Test-Harness/t/sample-tests/delayed26
-rw-r--r--cpan/Test-Harness/t/sample-tests/descriptive8
-rw-r--r--cpan/Test-Harness/t/sample-tests/descriptive_trailing8
-rw-r--r--cpan/Test-Harness/t/sample-tests/die2
-rw-r--r--cpan/Test-Harness/t/sample-tests/die_head_end9
-rw-r--r--cpan/Test-Harness/t/sample-tests/die_last_minute10
-rw-r--r--cpan/Test-Harness/t/sample-tests/die_unfinished9
-rw-r--r--cpan/Test-Harness/t/sample-tests/duplicates14
-rw-r--r--cpan/Test-Harness/t/sample-tests/echo2
-rw-r--r--cpan/Test-Harness/t/sample-tests/empty2
-rw-r--r--cpan/Test-Harness/t/sample-tests/escape_eol5
-rw-r--r--cpan/Test-Harness/t/sample-tests/escape_hash6
-rw-r--r--cpan/Test-Harness/t/sample-tests/head_end11
-rw-r--r--cpan/Test-Harness/t/sample-tests/head_fail11
-rw-r--r--cpan/Test-Harness/t/sample-tests/inc_taint6
-rw-r--r--cpan/Test-Harness/t/sample-tests/junk_before_plan6
-rw-r--r--cpan/Test-Harness/t/sample-tests/lone_not_bug9
-rw-r--r--cpan/Test-Harness/t/sample-tests/no_nums8
-rw-r--r--cpan/Test-Harness/t/sample-tests/no_output3
-rw-r--r--cpan/Test-Harness/t/sample-tests/out_err_mix13
-rw-r--r--cpan/Test-Harness/t/sample-tests/out_of_order22
-rw-r--r--cpan/Test-Harness/t/sample-tests/schwern3
-rw-r--r--cpan/Test-Harness/t/sample-tests/schwern-todo-quiet13
-rw-r--r--cpan/Test-Harness/t/sample-tests/segfault5
-rw-r--r--cpan/Test-Harness/t/sample-tests/sequence_misparse14
-rw-r--r--cpan/Test-Harness/t/sample-tests/shbang_misparse12
-rw-r--r--cpan/Test-Harness/t/sample-tests/simple8
-rw-r--r--cpan/Test-Harness/t/sample-tests/simple_fail8
-rw-r--r--cpan/Test-Harness/t/sample-tests/simple_yaml27
-rw-r--r--cpan/Test-Harness/t/sample-tests/skip8
-rw-r--r--cpan/Test-Harness/t/sample-tests/skip_nomsg4
-rw-r--r--cpan/Test-Harness/t/sample-tests/skipall3
-rw-r--r--cpan/Test-Harness/t/sample-tests/skipall_nomsg2
-rw-r--r--cpan/Test-Harness/t/sample-tests/skipall_v134
-rw-r--r--cpan/Test-Harness/t/sample-tests/space_after_plan3
-rw-r--r--cpan/Test-Harness/t/sample-tests/stdout_stderr9
-rw-r--r--cpan/Test-Harness/t/sample-tests/strict9
-rw-r--r--cpan/Test-Harness/t/sample-tests/switches2
-rw-r--r--cpan/Test-Harness/t/sample-tests/taint7
-rw-r--r--cpan/Test-Harness/t/sample-tests/taint_warn11
-rw-r--r--cpan/Test-Harness/t/sample-tests/todo8
-rw-r--r--cpan/Test-Harness/t/sample-tests/todo_inline6
-rw-r--r--cpan/Test-Harness/t/sample-tests/todo_misparse5
-rw-r--r--cpan/Test-Harness/t/sample-tests/too_many14
-rw-r--r--cpan/Test-Harness/t/sample-tests/version_good9
-rw-r--r--cpan/Test-Harness/t/sample-tests/version_late9
-rw-r--r--cpan/Test-Harness/t/sample-tests/version_old9
-rw-r--r--cpan/Test-Harness/t/sample-tests/vms_nit6
-rw-r--r--cpan/Test-Harness/t/sample-tests/with_comments14
-rw-r--r--cpan/Test-Harness/t/sample-tests/zero_valid8
-rw-r--r--cpan/Test-Harness/t/scheduler.t225
-rw-r--r--cpan/Test-Harness/t/source.t93
-rw-r--r--cpan/Test-Harness/t/source_tests/harness6
-rw-r--r--cpan/Test-Harness/t/source_tests/harness_badtap8
-rw-r--r--cpan/Test-Harness/t/source_tests/harness_complain7
-rw-r--r--cpan/Test-Harness/t/source_tests/harness_directives8
-rw-r--r--cpan/Test-Harness/t/source_tests/harness_failure11
-rw-r--r--cpan/Test-Harness/t/source_tests/source14
-rw-r--r--cpan/Test-Harness/t/spool.t139
-rw-r--r--cpan/Test-Harness/t/state.t251
-rw-r--r--cpan/Test-Harness/t/state_results.t148
-rw-r--r--cpan/Test-Harness/t/streams.t171
-rw-r--r--cpan/Test-Harness/t/subclass_tests/non_perl_source3
-rw-r--r--cpan/Test-Harness/t/subclass_tests/perl_source6
-rw-r--r--cpan/Test-Harness/t/taint.t49
-rw-r--r--cpan/Test-Harness/t/testargs.t128
-rw-r--r--cpan/Test-Harness/t/unicode.t125
-rw-r--r--cpan/Test-Harness/t/utils.t61
-rw-r--r--cpan/Test-Harness/t/yamlish-output.t100
-rw-r--r--cpan/Test-Harness/t/yamlish-writer.t274
-rw-r--r--cpan/Test-Harness/t/yamlish.t529
135 files changed, 14692 insertions, 0 deletions
diff --git a/cpan/Test-Harness/t/000-load.t b/cpan/Test-Harness/t/000-load.t
new file mode 100644
index 0000000000..58d41bfeeb
--- /dev/null
+++ b/cpan/Test-Harness/t/000-load.t
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 78;
+
+BEGIN {
+
+ # TAP::Parser must come first
+ my @classes = qw(
+ TAP::Parser
+ App::Prove
+ App::Prove::State
+ App::Prove::State::Result
+ App::Prove::State::Result::Test
+ TAP::Base
+ TAP::Formatter::Color
+ TAP::Formatter::Console::ParallelSession
+ TAP::Formatter::Console::Session
+ TAP::Formatter::Console
+ 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::IteratorFactory
+ TAP::Parser::Multiplexer
+ TAP::Parser::Result
+ TAP::Parser::ResultFactory
+ TAP::Parser::Result::Bailout
+ TAP::Parser::Result::Comment
+ TAP::Parser::Result::Plan
+ TAP::Parser::Result::Pragma
+ TAP::Parser::Result::Test
+ TAP::Parser::Result::Unknown
+ 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
+ TAP::Parser::YAMLish::Writer
+ TAP::Parser::Utils
+ Test::Harness
+ );
+
+ foreach my $class (@classes) {
+ use_ok $class or BAIL_OUT("Could not load $class");
+ is $class->VERSION, TAP::Parser->VERSION,
+ "... and $class should have the correct version";
+ }
+
+ diag("Testing Test::Harness $Test::Harness::VERSION, Perl $], $^X")
+ unless $ENV{PERL_CORE};
+}
diff --git a/cpan/Test-Harness/t/aggregator.t b/cpan/Test-Harness/t/aggregator.t
new file mode 100644
index 0000000000..c8e32a1c93
--- /dev/null
+++ b/cpan/Test-Harness/t/aggregator.t
@@ -0,0 +1,305 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 81;
+
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+use TAP::Parser::Aggregator;
+
+my $tap = <<'END_TAP';
+1..5
+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
+ok 5 # skip we have no description
+END_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 } );
+isa_ok $parser1, 'TAP::Parser';
+
+$parser1->run;
+
+$tap = <<'END_TAP';
+1..7
+ok 1 - gentlemen, start your engines
+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
+ok 5
+ok 6 - you shall not pass! # TODO should have failed
+not ok 7 - Gandalf wins. Game over. # TODO 'bout time!
+END_TAP
+
+my $parser2 = TAP::Parser->new( { tap => $tap } );
+isa_ok $parser2, 'TAP::Parser';
+$parser2->run;
+
+can_ok 'TAP::Parser::Aggregator', 'new';
+my $agg = TAP::Parser::Aggregator->new;
+isa_ok $agg, 'TAP::Parser::Aggregator';
+
+can_ok $agg, 'add';
+ok $agg->add( 'tap1', $parser1 ), '... and calling it should succeed';
+ok $agg->add( 'tap2', $parser2 ), '... even if we add more than one parser';
+eval { $agg->add( 'tap1', $parser1 ) };
+like $@, qr/^You already have a parser for \Q(tap1)/,
+ '... but trying to reuse a description should be fatal';
+
+can_ok $agg, 'parsers';
+is scalar $agg->parsers, 2,
+ '... and it should report how many parsers it has';
+is_deeply [ $agg->parsers ], [ $parser1, $parser2 ],
+ '... or which parsers it has';
+is_deeply $agg->parsers('tap2'), $parser2, '... or reporting a single parser';
+is_deeply [ $agg->parsers(qw(tap2 tap1)) ], [ $parser2, $parser1 ],
+ '... or a group';
+
+# test aggregate results
+
+can_ok $agg, 'passed';
+is $agg->passed, 10,
+ '... and we should have the correct number of passed tests';
+is_deeply [ $agg->passed ], [qw(tap1 tap2)],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'failed';
+is $agg->failed, 2,
+ '... and we should have the correct number of failed tests';
+is_deeply [ $agg->failed ], [qw(tap1 tap2)],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'todo';
+is $agg->todo, 4, '... and we should have the correct number of todo tests';
+is_deeply [ $agg->todo ], [qw(tap1 tap2)],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'skipped';
+is $agg->skipped, 1,
+ '... and we should have the correct number of skipped tests';
+is_deeply [ $agg->skipped ], [qw(tap1)],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'parse_errors';
+is $agg->parse_errors, 0, '... and the correct number of parse errors';
+is_deeply [ $agg->parse_errors ], [],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'todo_passed';
+is $agg->todo_passed, 1,
+ '... and the correct number of unexpectedly succeeded tests';
+is_deeply [ $agg->todo_passed ], [qw(tap2)],
+ '... and be able to get their descriptions';
+
+can_ok $agg, 'total';
+is $agg->total, $agg->passed + $agg->failed,
+ '... and we should have the correct number of total tests';
+
+can_ok $agg, 'planned';
+is $agg->planned, $agg->passed + $agg->failed,
+ '... and we should have the correct number of planned tests';
+
+can_ok $agg, 'has_problems';
+ok $agg->has_problems, '... and it should report true if there are problems';
+
+can_ok $agg, 'has_errors';
+ok $agg->has_errors, '... and it should report true if there are errors';
+
+can_ok $agg, 'get_status';
+is $agg->get_status, 'FAIL', '... and it should tell us the tests failed';
+
+can_ok $agg, 'all_passed';
+ok !$agg->all_passed, '... and it should tell us not all tests passed';
+
+# coverage testing
+
+# _get_parsers
+# bad descriptions
+# currently the $agg object has descriptions tap1 and tap2
+# call _get_parsers with another description.
+# $agg will call its _croak method
+my @die;
+
+eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $agg->_get_parsers('no_such_parser_for');
+};
+
+is @die, 1,
+ 'coverage tests for missing parsers... and we caught just one death message';
+like pop(@die),
+ qr/^A parser for \(no_such_parser_for\) could not be found at /,
+ '... and it was the expected death message';
+
+# _get_parsers in scalar context
+
+my $gp = $agg->_get_parsers(qw(tap1 tap2))
+ ; # should return ref to array containing parsers for tap1 and tap2
+
+is @$gp, 2,
+ 'coverage tests for _get_parser in scalar context... and we got the right number of parsers';
+isa_ok( $_, 'TAP::Parser' ) foreach (@$gp);
+
+# _get_parsers
+# todo_failed - this is a deprecated method, so it (and these tests)
+# can be removed eventually. However, it is showing up in the coverage
+# as never tested.
+my @warn;
+
+eval {
+ local $SIG{__WARN__} = sub { push @warn, @_ };
+
+ $agg->todo_failed();
+};
+
+# check the warning, making sure to capture the fullstops correctly (not
+# as "any char" matches)
+is @warn, 1,
+ 'coverage tests for deprecated todo_failed... and just one warning caught';
+like pop(@warn),
+ qr/^"todo_failed" is deprecated[.] Please use "todo_passed"[.] See the docs[.] at/,
+ '... and it was the expected warning';
+
+# has_problems
+# this has a large number of conditions 'OR'd together, so the tests get
+# a little complicated here
+
+# currently, we have covered the cases of failed() being true and none
+# of the summary methods failing
+
+# we need to set up test cases for
+# 1. !failed && todo_passed
+# 2. !failed && !todo_passed && parse_errors
+# 3. !failed && !todo_passed && !parse_errors && exit
+# 4. !failed && !todo_passed && !parse_errors && !exit && wait
+
+# note there is nothing wrong per se with the has_problems logic, these
+# are simply coverage tests
+
+# 1. !failed && todo_passed
+
+$agg = TAP::Parser::Aggregator->new();
+isa_ok $agg, 'TAP::Parser::Aggregator';
+
+$tap = <<'END_TAP';
+1..1
+ok 1 - you shall not pass! # TODO should have failed
+END_TAP
+
+my $parser3 = TAP::Parser->new( { tap => $tap } );
+isa_ok $parser3, 'TAP::Parser';
+$parser3->run;
+
+$agg->add( 'tap3', $parser3 );
+
+is $agg->passed, 1,
+ 'coverage tests for !failed && todo_passed... and we should have the correct number of passed tests';
+is $agg->failed, 0,
+ '... and we should have the correct number of failed tests';
+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';
+
+# 2. !failed && !todo_passed && parse_errors
+
+$agg = TAP::Parser::Aggregator->new();
+
+$tap = <<'END_TAP';
+1..-1
+END_TAP
+
+my $parser4 = TAP::Parser->new( { tap => $tap } );
+isa_ok $parser4, 'TAP::Parser';
+$parser4->run;
+
+$agg->add( 'tap4', $parser4 );
+
+is $agg->passed, 0,
+ 'coverage tests for !failed && !todo_passed && parse_errors... and we should have the correct number of passed tests';
+is $agg->failed, 0,
+ '... and we should have the correct number of failed tests';
+is $agg->todo_passed, 0,
+ '... and the correct number of unexpectedly succeeded tests';
+is $agg->parse_errors, 1, '... and the correct number of parse errors';
+ok $agg->has_problems,
+ '... and it should report true that there are problems';
+
+# 3. !failed && !todo_passed && !parse_errors && exit
+# now this is a little harder to emulate cleanly through creating tap
+# fragments and parsing, as exit and wait collect OS-status codes.
+# so we'll get a little funky with $agg and push exit and wait descriptions
+# in it - not very friendly to internal rep changes.
+
+$agg = TAP::Parser::Aggregator->new();
+
+$tap = <<'END_TAP';
+1..1
+ok 1 - you shall not pass!
+END_TAP
+
+my $parser5 = TAP::Parser->new( { tap => $tap } );
+$parser5->run;
+
+$agg->add( 'tap', $parser5 );
+
+push @{ $agg->{descriptions_for_exit} }, 'one possible reason';
+$agg->{exit}++;
+
+is $agg->passed, 1,
+ 'coverage tests for !failed && !todo_passed && !parse_errors... and we should have the correct number of passed tests';
+is $agg->failed, 0,
+ '... and we should have the correct number of failed tests';
+is $agg->todo_passed, 0,
+ '... and the correct number of unexpectedly succeeded tests';
+is $agg->parse_errors, 0, '... and the correct number of parse errors';
+
+my @exits = $agg->exit;
+
+is @exits, 1, '... and the correct number of exits';
+is pop(@exits), 'one possible reason',
+ '... and we collected the right exit reason';
+
+ok $agg->has_problems,
+ '... and it should report true that there are problems';
+
+# 4. !failed && !todo_passed && !parse_errors && !exit && wait
+
+$agg = TAP::Parser::Aggregator->new();
+
+$agg->add( 'tap', $parser5 );
+
+push @{ $agg->{descriptions_for_wait} }, 'another possible reason';
+$agg->{wait}++;
+
+is $agg->passed, 1,
+ 'coverage tests for !failed && !todo_passed && !parse_errors && !exit... and we should have the correct number of passed tests';
+is $agg->failed, 0,
+ '... and we should have the correct number of failed tests';
+is $agg->todo_passed, 0,
+ '... and the correct number of unexpectedly succeeded tests';
+is $agg->parse_errors, 0, '... and the correct number of parse errors';
+is $agg->exit, 0, '... and the correct number of exits';
+
+my @waits = $agg->wait;
+
+is @waits, 1, '... and the correct number of waits';
+is pop(@waits), 'another possible reason',
+ '... and we collected the right wait reason';
+
+ok $agg->has_problems,
+ '... and it should report true that there are problems';
diff --git a/cpan/Test-Harness/t/bailout.t b/cpan/Test-Harness/t/bailout.t
new file mode 100644
index 0000000000..e10b133e0f
--- /dev/null
+++ b/cpan/Test-Harness/t/bailout.t
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 33;
+
+use TAP::Parser;
+
+my $tap = <<'END_TAP';
+1..4
+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
+Bail out! We ran out of foobar.
+END_TAP
+my $parser = TAP::Parser->new( { tap => $tap } );
+isa_ok $parser, 'TAP::Parser',
+ '... we should be able to parse bailed out tests';
+
+my @results;
+while ( my $result = $parser->next ) {
+ push @results => $result;
+}
+
+can_ok $parser, 'passed';
+is $parser->passed, 3,
+ '... and we shold have the correct number of passed tests';
+is_deeply [ $parser->passed ], [ 1, 2, 3 ],
+ '... 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, 2,
+ '... and we shold have the correct number of actually passed tests';
+is_deeply [ $parser->actual_passed ], [ 1, 3 ],
+ '... and get a list of the actually passed tests';
+
+can_ok $parser, 'actual_failed';
+is $parser->actual_failed, 2,
+ '... and the correct number of actually failed tests';
+is_deeply [ $parser->actual_failed ], [ 2, 4 ],
+ '... or get a list of the actually failed tests';
+
+can_ok $parser, 'todo';
+is $parser->todo, 1,
+ '... and we should have the correct number of TODO tests';
+is_deeply [ $parser->todo ], [2], '... and get a list of the TODO tests';
+
+ok !$parser->skipped,
+ '... and we should have the correct number of skipped tests';
+
+# check the plan
+
+can_ok $parser, 'plan';
+is $parser->plan, '1..4', '... and we should have the correct plan';
+is $parser->tests_planned, 4, '... and the correct number of tests';
+
+# results() is sane?
+
+ok @results, 'The parser should return results';
+is scalar @results, 8, '... and there should be one for each line';
+
+# check the test plan
+
+my $result = shift @results;
+ok $result->is_plan, 'We should have a plan';
+
+# a normal, passing test
+
+my $test = shift @results;
+ok $test->is_test, '... and a test';
+
+# junk lines should be preserved
+
+my $unknown = shift @results;
+ok $unknown->is_unknown, '... and an unknown line';
+
+# a failing test, which also happens to have a directive
+
+my $failed = shift @results;
+ok $failed->is_test, '... and another test';
+
+# comments
+
+my $comment = shift @results;
+ok $comment->is_comment, '... and a comment';
+
+# another normal, passing test
+
+$test = shift @results;
+ok $test->is_test, '... and another test';
+
+# a failing test
+
+$failed = shift @results;
+ok $failed->is_test, '... and yet another test';
+
+# ok 5 # skip we have no description
+# skipped test
+my $bailout = shift @results;
+ok $bailout->is_bailout, 'And finally we should have a bailout';
+is $bailout->as_string, 'We ran out of foobar.',
+ '... and as_string() should return the explanation';
+is $bailout->raw, 'Bail out! We ran out of foobar.',
+ '... and raw() should return the explanation';
+is $bailout->explanation, 'We ran out of foobar.',
+ '... and it should have the correct explanation';
diff --git a/cpan/Test-Harness/t/base.t b/cpan/Test-Harness/t/base.t
new file mode 100644
index 0000000000..4fee54844e
--- /dev/null
+++ b/cpan/Test-Harness/t/base.t
@@ -0,0 +1,173 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 38;
+
+use TAP::Base;
+
+{
+
+ # No callbacks allowed
+ can_ok 'TAP::Base', 'new';
+ my $base = TAP::Base->new();
+ isa_ok $base, 'TAP::Base', 'object of correct type';
+ foreach my $method (qw(callback _croak _callback_for _initialize)) {
+ can_ok $base, $method;
+ }
+
+ eval {
+ $base->callback(
+ some_event => sub {
+
+ # do nothing
+ }
+ );
+ };
+ like( $@, qr/No callbacks/, 'no callbacks allowed croaks OK' );
+ my $cb = $base->_callback_for('some_event');
+ ok( !$cb, 'no callback installed' );
+}
+
+{
+
+ # No callbacks allowed, constructor should croak
+ eval {
+ my $base = TAP::Base->new(
+ { callbacks => {
+ some_event => sub {
+
+ # do nothing
+ }
+ }
+ }
+ );
+ };
+ like(
+ $@, qr/No callbacks/,
+ 'no callbacks in constructor croaks OK'
+ );
+}
+
+package CallbackOK;
+
+use TAP::Base;
+use vars qw(@ISA);
+@ISA = 'TAP::Base';
+
+sub _initialize {
+ my $self = shift;
+ my $args = shift;
+ $self->SUPER::_initialize( $args, [qw( nice_event other_event )] );
+ return $self;
+}
+
+package main;
+{
+ my $base = CallbackOK->new();
+ isa_ok $base, 'TAP::Base';
+
+ eval {
+ $base->callback(
+ some_event => sub {
+
+ # do nothing
+ }
+ );
+ };
+ like( $@, qr/Callback some_event/, 'illegal callback croaks OK' );
+
+ my ( $nice, $other ) = ( 0, 0 );
+
+ eval {
+ $base->callback( other_event => sub { $other-- } );
+ $base->callback( nice_event => sub { $nice++; return shift() . 'OK' }
+ );
+ };
+
+ 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' );
+ my $nice_cb = $nice_cbs->[0];
+ ok( ref $nice_cb eq 'CODE', 'callback for nice_event returned' );
+ my $got = $nice_cb->('Is ');
+ is( $got, 'Is OK', 'args passed to callback' );
+ 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' );
+ 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' );
+}
+
+{
+ my ( $nice, $other ) = ( 0, 0 );
+
+ my $base = CallbackOK->new(
+ { callbacks => {
+ nice_event => sub { $nice++ }
+ }
+ }
+ );
+
+ isa_ok $base, 'TAP::Base', 'object creation with callback succeeds';
+
+ eval {
+ $base->callback(
+ some_event => sub {
+
+ # do nothing
+ }
+ );
+ };
+ like( $@, qr/Callback some_event/, 'illegal callback croaks OK' );
+
+ eval {
+ $base->callback( other_event => sub { $other-- } );
+ };
+
+ 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' );
+ 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' );
+ 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' );
+
+ my $status = undef;
+
+ # Stack another callback
+ $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' );
+ my $new_cb = $new_cbs->[1];
+ ok( ref $new_cb eq 'CODE', 'callback for new_event returned' );
+ my @got = $new_cb->();
+ is( $status, 'OK', 'new callback called OK' );
+}
diff --git a/cpan/Test-Harness/t/callbacks.t b/cpan/Test-Harness/t/callbacks.t
new file mode 100644
index 0000000000..18c6f0d15e
--- /dev/null
+++ b/cpan/Test-Harness/t/callbacks.t
@@ -0,0 +1,116 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 10;
+
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+
+my $tap = <<'END_TAP';
+1..5
+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
+ok 5 # skip we have no description
+END_TAP
+
+my @tests;
+my $plan_output;
+my $todo = 0;
+my $skip = 0;
+my %callbacks = (
+ test => sub {
+ my $test = shift;
+ push @tests => $test;
+ $todo++ if $test->has_todo;
+ $skip++ if $test->has_skip;
+ },
+ plan => sub {
+ my $plan = shift;
+ $plan_output = $plan->as_string;
+ }
+);
+
+my $factory = TAP::Parser::IteratorFactory->new;
+my $stream = $factory->make_iterator( [ split /\n/ => $tap ] );
+my $parser = TAP::Parser->new(
+ { stream => $stream,
+ callbacks => \%callbacks,
+ }
+);
+
+can_ok $parser, 'run';
+$parser->run;
+is $plan_output, '1..5', 'Plan callbacks should succeed';
+is scalar @tests, $parser->tests_run, '... as should the test callbacks';
+
+@tests = ();
+$plan_output = '';
+$todo = 0;
+$skip = 0;
+my $else = 0;
+my $all = 0;
+my $end = 0;
+%callbacks = (
+ test => sub {
+ my $test = shift;
+ push @tests => $test;
+ $todo++ if $test->has_todo;
+ $skip++ if $test->has_skip;
+ },
+ plan => sub {
+ my $plan = shift;
+ $plan_output = $plan->as_string;
+ },
+ EOF => sub {
+ my $p = shift;
+ $end = 1 if $all == 8 and $p->isa('TAP::Parser');
+ },
+ ELSE => sub {
+ $else++;
+ },
+ ALL => sub {
+ $all++;
+ },
+);
+
+$stream = $factory->make_iterator( [ split /\n/ => $tap ] );
+$parser = TAP::Parser->new(
+ { stream => $stream,
+ callbacks => \%callbacks,
+ }
+);
+
+can_ok $parser, 'run';
+$parser->run;
+is $plan_output, '1..5', 'Plan callbacks should succeed';
+is scalar @tests, $parser->tests_run, '... as should the test callbacks';
+is $else, 2, '... and the correct number of "ELSE" lines should be seen';
+is $all, 8, '... and the correct total number of lines should be seen';
+is $end, 1, 'EOF callback correctly called';
+
+# Check callback name policing
+
+%callbacks = (
+ sometest => sub { },
+ plan => sub { },
+ random => sub { },
+ ALL => sub { },
+ ELSES => sub { },
+);
+
+$stream = $factory->make_iterator( [ split /\n/ => $tap ] );
+eval {
+ $parser = TAP::Parser->new(
+ { stream => $stream,
+ callbacks => \%callbacks,
+ }
+ );
+};
+
+like $@, qr/Callback/, 'Bad callback keys faulted';
diff --git a/cpan/Test-Harness/t/compat/env.t b/cpan/Test-Harness/t/compat/env.t
new file mode 100644
index 0000000000..ac5c096213
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/env.t
@@ -0,0 +1,39 @@
+#!/usr/bin/perl -w
+
+# Test that env vars are honoured.
+
+use strict;
+use lib 't/lib';
+
+use Test::More (
+ $^O eq 'VMS'
+ ? ( skip_all => 'VMS' )
+ : ( tests => 1 )
+);
+
+use Test::Harness;
+
+# HARNESS_PERL_SWITCHES
+
+my $test_template = <<'END';
+#!/usr/bin/perl
+
+use Test::More tests => 1;
+
+is $ENV{HARNESS_PERL_SWITCHES}, '-w';
+END
+
+open TEST, ">env_check_t.tmp";
+print TEST $test_template;
+close TEST;
+
+END { unlink 'env_check_t.tmp'; }
+
+{
+ local $ENV{HARNESS_PERL_SWITCHES} = '-w';
+ my ( $tot, $failed )
+ = Test::Harness::execute_tests( tests => ['env_check_t.tmp'] );
+ is $tot->{bad}, 0;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/compat/failure.t b/cpan/Test-Harness/t/compat/failure.t
new file mode 100644
index 0000000000..2f80e57884
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/failure.t
@@ -0,0 +1,56 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 5;
+
+use File::Spec;
+use Test::Harness;
+
+{
+
+ #todo_skip 'Harness compatibility incomplete', 5;
+ #local $TODO = 'Harness compatibility incomplete';
+ my $died;
+
+ sub prepare_for_death {
+ $died = 0;
+ return sub { $died = 1 }
+ }
+
+ my $curdir = File::Spec->curdir;
+ my $sample_tests = File::Spec->catdir( $curdir, 't', 'sample-tests' );
+
+ {
+ local $SIG{__DIE__} = prepare_for_death();
+ eval { _runtests( File::Spec->catfile( $sample_tests, "simple" ) ); };
+ ok( !$@, "simple lives" );
+ is( $died, 0, "Death never happened" );
+ }
+
+ {
+ local $SIG{__DIE__} = prepare_for_death();
+ eval {
+ _runtests( File::Spec->catfile( $sample_tests, "too_many" ) );
+ };
+ ok( $@, "error OK" );
+ ok( $@ =~ m[Failed 1/1], "too_many dies" );
+ is( $died, 1, "Death happened" );
+ }
+}
+
+sub _runtests {
+ my (@tests) = @_;
+
+ local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
+ local $ENV{HARNESS_VERBOSE} = 0;
+ local $ENV{HARNESS_DEBUG} = 0;
+ local $ENV{HARNESS_TIMER} = 0;
+
+ local $Test::Harness::Verbose = -9;
+
+ runtests(@tests);
+}
+
+# vim:ts=4:sw=4:et:sta
diff --git a/cpan/Test-Harness/t/compat/inc-propagation.t b/cpan/Test-Harness/t/compat/inc-propagation.t
new file mode 100644
index 0000000000..c0d62b0407
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/inc-propagation.t
@@ -0,0 +1,57 @@
+#!/usr/bin/perl -w
+
+# Test that @INC is propogated from the harness process to the test
+# process.
+
+use strict;
+use lib 't/lib';
+use Config;
+
+local
+ $ENV{PERL5OPT}; # avoid any user-provided PERL5OPT from contaminating @INC
+
+sub has_crazy_patch {
+ my $sentinel = 'blirpzoffle';
+ local $ENV{PERL5LIB} = $sentinel;
+ my $command = join ' ',
+ map {qq{"$_"}} ( $^X, '-e', 'print join q(:), @INC' );
+ my $path = `$command`;
+ my @got = ( $path =~ /($sentinel)/g );
+ return @got > 1;
+}
+
+use Test::More (
+ $^O eq 'VMS' ? ( skip_all => 'VMS' )
+ : has_crazy_patch() ? ( skip_all => 'Incompatible @INC patch' )
+ : ( tests => 2 )
+);
+
+use Test::Harness;
+
+# Change @INC so we ensure it's preserved.
+use lib 'wibble';
+
+my $test_template = <<'END';
+#!/usr/bin/perl %s
+
+use Test::More tests => 2;
+
+is $INC[0], "wibble", 'basic order of @INC preserved' or diag "\@INC: @INC";
+like $ENV{PERL5LIB}, qr{wibble};
+
+END
+
+open TEST, ">inc_check.t.tmp";
+printf TEST $test_template, '';
+close TEST;
+
+open TEST, ">inc_check_taint.t.tmp";
+printf TEST $test_template, '-T';
+close TEST;
+END { 1 while unlink 'inc_check_taint.t.tmp', 'inc_check.t.tmp'; }
+
+for my $test ( 'inc_check_taint.t.tmp', 'inc_check.t.tmp' ) {
+ my ( $tot, $failed ) = Test::Harness::execute_tests( tests => [$test] );
+ is $tot->{bad}, 0;
+}
+1;
diff --git a/cpan/Test-Harness/t/compat/inc_taint.t b/cpan/Test-Harness/t/compat/inc_taint.t
new file mode 100644
index 0000000000..3bd86b4108
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/inc_taint.t
@@ -0,0 +1,33 @@
+#!/usr/bin/perl -w
+
+use lib 't/lib';
+
+use strict;
+
+use Test::More tests => 1;
+
+use Dev::Null;
+
+use Test::Harness;
+
+sub _all_ok {
+ my ($tot) = shift;
+ return $tot->{bad} == 0
+ && ( $tot->{max} || $tot->{skipped} ) ? 1 : 0;
+}
+
+{
+ local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
+ local $Test::Harness::Verbose = -9;
+
+ push @INC, 'examples';
+
+ tie *NULL, 'Dev::Null' or die $!;
+ select NULL;
+ my ( $tot, $failed ) = Test::Harness::execute_tests(
+ tests => ['t/sample-tests/inc_taint']
+ );
+ select STDOUT;
+
+ ok( _all_ok($tot), 'tests with taint on preserve @INC' );
+}
diff --git a/cpan/Test-Harness/t/compat/nonumbers.t b/cpan/Test-Harness/t/compat/nonumbers.t
new file mode 100644
index 0000000000..144a7599b2
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/nonumbers.t
@@ -0,0 +1,14 @@
+if ( $ENV{PERL_CORE} && !$ENV{HARNESS_ACTIVE} ) {
+ print "1..0 # Skip: t/TEST needs numbers\n";
+ exit;
+}
+
+print <<END;
+1..6
+ok
+ok
+ok
+ok
+ok
+ok
+END
diff --git a/cpan/Test-Harness/t/compat/regression.t b/cpan/Test-Harness/t/compat/regression.t
new file mode 100644
index 0000000000..50a4d516c8
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/regression.t
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 1;
+use Test::Harness;
+
+# 28567
+my ( @before, @after );
+{
+ local @INC;
+ unshift @INC, 'wibble';
+ @before = Test::Harness::_filtered_inc();
+ unshift @INC, sub {die};
+ @after = Test::Harness::_filtered_inc();
+}
+
+is_deeply \@after, \@before, 'subref removed from @INC';
diff --git a/cpan/Test-Harness/t/compat/switches.t b/cpan/Test-Harness/t/compat/switches.t
new file mode 100644
index 0000000000..42b16c8bd4
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/switches.t
@@ -0,0 +1,17 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More (
+ $^O eq 'VMS'
+ ? ( skip_all => 'VMS' )
+ : ( tests => 4 )
+);
+
+use Test::Harness;
+
+for my $switch ( '-Ifoo', '-I foo' ) {
+ $Test::Harness::Switches = $switch;
+ ok my $harness = Test::Harness::_new_harness, 'made harness';
+ is_deeply [ $harness->lib ], ['-Ifoo'], 'got libs';
+}
+
diff --git a/cpan/Test-Harness/t/compat/test-harness-compat.t b/cpan/Test-Harness/t/compat/test-harness-compat.t
new file mode 100644
index 0000000000..cae9a54333
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/test-harness-compat.t
@@ -0,0 +1,851 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+
+# use lib 't/lib';
+
+use Test::More;
+use File::Spec;
+use Test::Harness qw(execute_tests);
+
+# unset this global when self-testing ('testcover' and etc issue)
+local $ENV{HARNESS_PERL_SWITCHES};
+
+my $TEST_DIR = 't/sample-tests';
+
+{
+
+ # if the harness wants to save the resulting TAP we shouldn't
+ # do it for our internal calls
+ local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
+
+ my $PER_LOOP = 4;
+
+ my $results = {
+ 'descriptive' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 5,
+ 'ok' => 5,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ join(
+ ',', qw(
+ descriptive die die_head_end die_last_minute duplicates
+ 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 taint todo_inline
+ todo_misparse too_many vms_nit
+ )
+ ) => {
+ 'failed' => {
+ "$TEST_DIR/die" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/die",
+ 'wstat' => '256'
+ },
+ "$TEST_DIR/die_head_end" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/die_head_end",
+ 'wstat' => '256'
+ },
+ "$TEST_DIR/die_last_minute" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => 0,
+ 'max' => 4,
+ 'name' => "$TEST_DIR/die_last_minute",
+ 'wstat' => '256'
+ },
+ "$TEST_DIR/duplicates" => {
+ 'canon' => '??',
+ 'estat' => '',
+ 'failed' => '??',
+ 'max' => 10,
+ 'name' => "$TEST_DIR/duplicates",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/head_fail" => {
+ 'canon' => 2,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 4,
+ 'name' => "$TEST_DIR/head_fail",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/inc_taint" => {
+ 'canon' => 1,
+ 'estat' => 1,
+ 'failed' => 1,
+ 'max' => 1,
+ 'name' => "$TEST_DIR/inc_taint",
+ 'wstat' => '256'
+ },
+ "$TEST_DIR/no_nums" => {
+ 'canon' => 3,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 5,
+ 'name' => "$TEST_DIR/no_nums",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/no_output" => {
+ 'canon' => '??',
+ 'estat' => '',
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/no_output",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/simple_fail" => {
+ 'canon' => '2 5',
+ 'estat' => '',
+ 'failed' => 2,
+ 'max' => 5,
+ 'name' => "$TEST_DIR/simple_fail",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/todo_misparse" => {
+ 'canon' => 1,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 1,
+ 'name' => "$TEST_DIR/todo_misparse",
+ 'wstat' => ''
+ },
+ "$TEST_DIR/too_many" => {
+ 'canon' => '4-7',
+ 'estat' => 4,
+ 'failed' => 4,
+ 'max' => 3,
+ 'name' => "$TEST_DIR/too_many",
+ 'wstat' => '1024'
+ },
+ "$TEST_DIR/vms_nit" => {
+ 'canon' => 1,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 2,
+ 'name' => "$TEST_DIR/vms_nit",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {
+ "$TEST_DIR/todo_inline" => {
+ 'canon' => 2,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 2,
+ 'name' => "$TEST_DIR/todo_inline",
+ 'wstat' => ''
+ }
+ },
+ 'totals' => {
+ 'bad' => 12,
+ 'bonus' => 1,
+ 'files' => 27,
+ 'good' => 15,
+ 'max' => 76,
+ 'ok' => 78,
+ 'skipped' => 2,
+ 'sub_skipped' => 2,
+ 'tests' => 27,
+ 'todo' => 2
+ }
+ },
+ 'die' => {
+ 'failed' => {
+ "$TEST_DIR/die" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/die",
+ 'wstat' => '256'
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 0,
+ 'ok' => 0,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'die_head_end' => {
+ 'failed' => {
+ "$TEST_DIR/die_head_end" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/die_head_end",
+ 'wstat' => '256'
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 0,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'die_last_minute' => {
+ 'failed' => {
+ "$TEST_DIR/die_last_minute" => {
+ 'canon' => '??',
+ 'estat' => 1,
+ 'failed' => 0,
+ 'max' => 4,
+ 'name' => "$TEST_DIR/die_last_minute",
+ 'wstat' => '256'
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 4,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'duplicates' => {
+ 'failed' => {
+ "$TEST_DIR/duplicates" => {
+ 'canon' => '??',
+ 'estat' => '',
+ 'failed' => '??',
+ 'max' => 10,
+ 'name' => "$TEST_DIR/duplicates",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 10,
+ 'ok' => 11,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'head_end' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 4,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'head_fail' => {
+ 'failed' => {
+ "$TEST_DIR/head_fail" => {
+ 'canon' => 2,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 4,
+ 'name' => "$TEST_DIR/head_fail",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 4,
+ 'ok' => 3,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'inc_taint' => {
+ 'failed' => {
+ "$TEST_DIR/inc_taint" => {
+ 'canon' => 1,
+ 'estat' => 1,
+ 'failed' => 1,
+ 'max' => 1,
+ 'name' => "$TEST_DIR/inc_taint",
+ 'wstat' => '256'
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 1,
+ 'ok' => 0,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'junk_before_plan' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 1,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'lone_not_bug' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 4,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'no_nums' => {
+ 'failed' => {
+ "$TEST_DIR/no_nums" => {
+ 'canon' => 3,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 5,
+ 'name' => "$TEST_DIR/no_nums",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 5,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'no_output' => {
+ 'failed' => {
+ "$TEST_DIR/no_output" => {
+ 'canon' => '??',
+ 'estat' => '',
+ 'failed' => '??',
+ 'max' => '??',
+ 'name' => "$TEST_DIR/no_output",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 0,
+ 'ok' => 0,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'schwern' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 1,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'sequence_misparse' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 5,
+ 'ok' => 5,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'shbang_misparse' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 2,
+ 'ok' => 2,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'simple' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 5,
+ 'ok' => 5,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'simple_fail' => {
+ 'failed' => {
+ "$TEST_DIR/simple_fail" => {
+ 'canon' => '2 5',
+ 'estat' => '',
+ 'failed' => 2,
+ 'max' => 5,
+ 'name' => "$TEST_DIR/simple_fail",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 5,
+ 'ok' => 3,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'skip' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 5,
+ 'ok' => 5,
+ 'skipped' => 0,
+ 'sub_skipped' => 1,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'skip_nomsg' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 1,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 1,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'skipall' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 0,
+ 'ok' => 0,
+ 'skipped' => 1,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'skipall_nomsg' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 0,
+ 'ok' => 0,
+ 'skipped' => 1,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'stdout_stderr' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 4,
+ 'ok' => 4,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'switches' => {
+ 'skip_if' => sub {
+ ( $ENV{PERL5OPT} || '' ) =~ m{(?:^|\s)-[dM]};
+ },
+ 'failed' => {
+ "$TEST_DIR/switches" => {
+ 'canon' => 1,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 1,
+ 'name' => "$TEST_DIR/switches",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 1,
+ 'ok' => 0,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'taint' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 1,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'taint_warn' => {
+ 'failed' => {},
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 1,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ },
+ 'require' => 5.008001,
+ },
+ 'todo_inline' => {
+ 'failed' => {},
+ 'todo' => {
+ "$TEST_DIR/todo_inline" => {
+ 'canon' => 2,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 2,
+ 'name' => "$TEST_DIR/todo_inline",
+ 'wstat' => ''
+ }
+ },
+ 'totals' => {
+ 'bad' => 0,
+ 'bonus' => 1,
+ 'files' => 1,
+ 'good' => 1,
+ 'max' => 3,
+ 'ok' => 3,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 2
+ }
+ },
+ 'todo_misparse' => {
+ 'failed' => {
+ "$TEST_DIR/todo_misparse" => {
+ 'canon' => 1,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 1,
+ 'name' => "$TEST_DIR/todo_misparse",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 1,
+ 'ok' => 0,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'too_many' => {
+ 'failed' => {
+ "$TEST_DIR/too_many" => {
+ 'canon' => '4-7',
+ 'estat' => 4,
+ 'failed' => 4,
+ 'max' => 3,
+ 'name' => "$TEST_DIR/too_many",
+ 'wstat' => '1024'
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 3,
+ 'ok' => 7,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ },
+ 'vms_nit' => {
+ 'failed' => {
+ "$TEST_DIR/vms_nit" => {
+ 'canon' => 1,
+ 'estat' => '',
+ 'failed' => 1,
+ 'max' => 2,
+ 'name' => "$TEST_DIR/vms_nit",
+ 'wstat' => ''
+ }
+ },
+ 'todo' => {},
+ 'totals' => {
+ 'bad' => 1,
+ 'bonus' => 0,
+ 'files' => 1,
+ 'good' => 0,
+ 'max' => 2,
+ 'ok' => 1,
+ 'skipped' => 0,
+ 'sub_skipped' => 0,
+ 'tests' => 1,
+ 'todo' => 0
+ }
+ }
+ };
+
+ my $num_tests = ( keys %$results ) * $PER_LOOP;
+
+ plan tests => $num_tests;
+
+ sub local_name {
+ my $name = shift;
+ return File::Spec->catfile( split /\//, $name );
+ }
+
+ sub local_result {
+ my $hash = shift;
+ my $new = {};
+
+ while ( my ( $file, $want ) = each %$hash ) {
+ if ( exists $want->{name} ) {
+ $want->{name} = local_name( $want->{name} );
+ }
+ $new->{ local_name($file) } = $want;
+ }
+ return $new;
+ }
+
+ sub vague_status {
+ my $hash = shift;
+ return $hash unless $^O eq 'VMS';
+
+ while ( my ( $file, $want ) = each %$hash ) {
+ for (qw( estat wstat )) {
+ if ( exists $want->{$_} ) {
+ $want->{$_} = $want->{$_} ? 1 : 0;
+ }
+ }
+ }
+ return $hash;
+ }
+
+ {
+ local $^W = 0;
+
+ # Silence harness output
+ *TAP::Formatter::Console::_output = sub {
+
+ # do nothing
+ };
+ }
+
+ for my $test_key ( sort keys %$results ) {
+ my $result = $results->{$test_key};
+ SKIP: {
+ 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;
+
+ # For now we supress STDERR because it crufts up /our/ test
+ # results. Should probably capture and analyse it.
+ local ( *OLDERR, *OLDOUT );
+ open OLDERR, '>&STDERR' or die $!;
+ open OLDOUT, '>&STDOUT' or die $!;
+ my $devnull = File::Spec->devnull;
+ open STDERR, ">$devnull" or die $!;
+ open STDOUT, ">$devnull" or die $!;
+
+ my ( $tot, $fail, $todo, $harness, $aggregate )
+ = execute_tests( tests => \@test_files );
+
+ open STDERR, '>&OLDERR' or die $!;
+ open STDOUT, '>&OLDOUT' or die $!;
+
+ my $bench = delete $tot->{bench};
+ isa_ok $bench, 'Benchmark';
+
+ # Localise filenames in failed, todo
+ my $lfailed = vague_status( local_result( $result->{failed} ) );
+ my $ltodo = vague_status( local_result( $result->{todo} ) );
+
+ # use Data::Dumper;
+ # diag Dumper( [ $lfailed, $ltodo ] );
+
+ is_deeply $tot, $result->{totals}, "totals match for $test_key";
+ is_deeply vague_status($fail), $lfailed,
+ "failure summary matches for $test_key";
+ is_deeply vague_status($todo), $ltodo,
+ "todo summary matches for $test_key";
+ }
+ }
+}
diff --git a/cpan/Test-Harness/t/compat/version.t b/cpan/Test-Harness/t/compat/version.t
new file mode 100644
index 0000000000..08344cbd9c
--- /dev/null
+++ b/cpan/Test-Harness/t/compat/version.t
@@ -0,0 +1,11 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 2;
+use Test::Harness;
+
+my $ver = $ENV{HARNESS_VERSION} or die "HARNESS_VERSION not set";
+ok( $ver =~ /^[23].\d\d(_\d\d)?$/, "Version is proper format" );
+is( $ver, $Test::Harness::VERSION );
diff --git a/cpan/Test-Harness/t/console.t b/cpan/Test-Harness/t/console.t
new file mode 100644
index 0000000000..32f5db62ac
--- /dev/null
+++ b/cpan/Test-Harness/t/console.t
@@ -0,0 +1,47 @@
+use strict;
+use lib 't/lib';
+use Test::More;
+use TAP::Formatter::Console;
+
+my @schedule;
+
+BEGIN {
+ @schedule = (
+ { method => '_range',
+ in => sub {qw/2 7 1 3 10 9/},
+ out => sub {qw/1-3 7 9-10/},
+ name => '... and it should return numbers as ranges'
+ },
+ { method => '_balanced_range',
+ in => sub { 7, qw/2 7 1 3 10 9/ },
+ out => sub { '1-3, 7', '9-10' },
+ name => '... and it should return numbers as ranges'
+ },
+ );
+
+ plan tests => @schedule * 3;
+}
+
+for my $test (@schedule) {
+ my $name = $test->{name};
+ my $cons = TAP::Formatter::Console->new;
+ isa_ok $cons, 'TAP::Formatter::Console';
+ my $method = $test->{method};
+ can_ok $cons, $method;
+ is_deeply [ $cons->$method( $test->{in}->() ) ], [ $test->{out}->() ],
+ $name;
+}
+
+#### Color tests ####
+
+package Colorizer;
+
+sub new { bless {}, shift }
+sub can_color {1}
+
+sub set_color {
+ my ( $self, $output, $color ) = @_;
+ $output->("[[$color]]");
+}
+
+package main;
diff --git a/cpan/Test-Harness/t/data/catme.1 b/cpan/Test-Harness/t/data/catme.1
new file mode 100644
index 0000000000..7ecdd9a102
--- /dev/null
+++ b/cpan/Test-Harness/t/data/catme.1
@@ -0,0 +1,2 @@
+1..1
+ok 1
diff --git a/cpan/Test-Harness/t/data/proverc b/cpan/Test-Harness/t/data/proverc
new file mode 100644
index 0000000000..9d2924145d
--- /dev/null
+++ b/cpan/Test-Harness/t/data/proverc
@@ -0,0 +1,7 @@
+--should be --split correctly # No comment!
+Can "quote things" 'using single or' "double quotes"
+
+# More stuff
+--this
+is
+'OK?'
diff --git a/cpan/Test-Harness/t/data/sample.yml b/cpan/Test-Harness/t/data/sample.yml
new file mode 100644
index 0000000000..6c4b7fbf4a
--- /dev/null
+++ b/cpan/Test-Harness/t/data/sample.yml
@@ -0,0 +1,29 @@
+---
+invoice: 34843
+date : 2001-01-23
+bill-to:
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
+comments: >
+ Late afternoon is best.
+ Backup contact is Nancy
+ Billsmer @ 338-4338
+
diff --git a/cpan/Test-Harness/t/errors.t b/cpan/Test-Harness/t/errors.t
new file mode 100644
index 0000000000..3a54cbe066
--- /dev/null
+++ b/cpan/Test-Harness/t/errors.t
@@ -0,0 +1,183 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 23;
+
+use TAP::Parser;
+
+my $plan_line = 'TAP::Parser::Result::Plan';
+my $test_line = 'TAP::Parser::Result::Test';
+
+sub _parser {
+ my $parser = TAP::Parser->new( { tap => shift } );
+ $parser->run;
+ return $parser;
+}
+
+# validate that plan!
+
+my $parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 - read the rest of the file
+1..3
+# comments are allowed after an ending plan
+END_TAP
+
+can_ok $parser, 'parse_errors';
+ok !$parser->parse_errors,
+ '... comments should be allowed after a terminating plan';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 - read the rest of the file
+1..3
+# yeah, yeah, I know.
+ok
+END_TAP
+
+can_ok $parser, 'parse_errors';
+is scalar $parser->parse_errors, 2, '... and we should have two parse errors';
+
+is [ $parser->parse_errors ]->[0],
+ 'Plan (1..3) must be at the beginning or end of the TAP output',
+ '... telling us that our plan was misplaced';
+is [ $parser->parse_errors ]->[1],
+ 'Bad plan. You planned 3 tests but ran 4.',
+ '... and telling us we ran the wrong number of tests.';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 - read the rest of the file
+#1..3
+# yo quiero tests!
+1..3
+END_TAP
+ok !$parser->parse_errors, '... but test plan-like data can be in a comment';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 - read the rest of the file 1..5
+# yo quiero tests!
+1..3
+END_TAP
+ok !$parser->parse_errors, '... or a description';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo 1..4
+ok 3 - read the rest of the file
+# yo quiero tests!
+1..3
+END_TAP
+ok !$parser->parse_errors, '... or a directive';
+
+# test numbers included?
+
+$parser = _parser(<<'END_TAP');
+1..3
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok read the rest of the file
+# this is ...
+END_TAP
+eval { $parser->run };
+ok !$@, 'We can mix and match the presence of test numbers';
+
+$parser = _parser(<<'END_TAP');
+1..3
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 2 read the rest of the file
+END_TAP
+
+is + ( $parser->parse_errors )[0],
+ 'Tests out of sequence. Found (2) but expected (3)',
+ '... and if the numbers are there, they cannot be out of sequence';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 2 read the rest of the file
+END_TAP
+
+is $parser->parse_errors, 2,
+ 'Having two errors in the TAP should result in two errors (duh)';
+my $expected = [
+ 'Tests out of sequence. Found (2) but expected (3)',
+ 'No plan found in TAP output'
+];
+is_deeply [ $parser->parse_errors ], $expected,
+ '... and they should be the correct errors';
+
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 read the rest of the file
+END_TAP
+
+is $parser->parse_errors, 1, 'Having no plan should cause an error';
+is + ( $parser->parse_errors )[0], 'No plan found in TAP output',
+ '... with a correct error message';
+
+$parser = _parser(<<'END_TAP');
+1..3
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 read the rest of the file
+1..3
+END_TAP
+
+is $parser->parse_errors, 1,
+ 'Having more than one plan should cause an error';
+is + ( $parser->parse_errors )[0], 'More than one plan found in TAP output',
+ '... with a correct error message';
+
+can_ok $parser, 'is_good_plan';
+$parser = _parser(<<'END_TAP');
+1..2
+ok 1 - input file opened
+not ok 2 - first line of the input valid # todo some data
+ok 3 read the rest of the file
+END_TAP
+
+is $parser->parse_errors, 1,
+ 'Having the wrong number of planned tests is a parse error';
+is + ( $parser->parse_errors )[0],
+ 'Bad plan. You planned 2 tests but ran 3.',
+ '... with a correct error message';
+
+# XXX internals: plan will not set to true if defined
+$parser->is_good_plan(undef);
+$parser = _parser(<<'END_TAP');
+ok 1 - input file opened
+1..1
+END_TAP
+
+ok $parser->is_good_plan,
+ '... and it should return true if the plan is correct';
+
+# TAP::Parser coverage tests
+{
+
+ # good_plan coverage
+
+ my @warn;
+
+ eval {
+ local $SIG{__WARN__} = sub { push @warn, @_ };
+
+ $parser->good_plan;
+ };
+
+ is @warn, 1, 'coverage testing of good_plan';
+
+ like pop @warn,
+ qr/good_plan[(][)] is deprecated. Please use "is_good_plan[(][)]"/,
+ '...and it fell-back like we expected';
+}
diff --git a/cpan/Test-Harness/t/file.t b/cpan/Test-Harness/t/file.t
new file mode 100644
index 0000000000..f97d1aadd0
--- /dev/null
+++ b/cpan/Test-Harness/t/file.t
@@ -0,0 +1,475 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+
+use Test::More;
+
+use TAP::Harness;
+
+my $HARNESS = 'TAP::Harness';
+
+my $source_tests = 't/source_tests';
+my $sample_tests = 't/sample-tests';
+
+plan tests => 56;
+
+# note that this test will always pass when run through 'prove'
+ok $ENV{HARNESS_ACTIVE}, 'HARNESS_ACTIVE env variable should be set';
+ok $ENV{HARNESS_VERSION}, 'HARNESS_VERSION env variable should be set';
+
+{
+ my @output;
+ local $^W;
+ require TAP::Formatter::Base;
+ local *TAP::Formatter::Base::_output = sub {
+ my $self = shift;
+ push @output => grep { $_ ne '' }
+ map {
+ local $_ = $_;
+ chomp;
+ trim($_)
+ } map { split /\n/ } @_;
+ };
+
+ # Make sure verbosity 1 overrides failures and comments.
+ my $harness = TAP::Harness->new(
+ { verbosity => 1,
+ failures => 1,
+ comments => 1,
+ }
+ );
+ my $harness_whisper = TAP::Harness->new( { verbosity => -1 } );
+ my $harness_mute = TAP::Harness->new( { verbosity => -2 } );
+ my $harness_directives = TAP::Harness->new( { directives => 1 } );
+ my $harness_failures = TAP::Harness->new( { failures => 1 } );
+ my $harness_comments = TAP::Harness->new( { comments => 1 } );
+ my $harness_fandc = TAP::Harness->new(
+ { failures => 1,
+ comments => 1
+ }
+ );
+
+ can_ok $harness, 'runtests';
+
+ # normal tests in verbose mode
+
+ ok my $aggregate = _runtests( $harness, "$source_tests/harness" ),
+ '... runtests returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ my @expected = (
+ "$source_tests/harness ..",
+ '1..1',
+ 'ok 1 - this is a test',
+ 'ok',
+ 'All tests successful.',
+ );
+ my $status = pop @output;
+ my $expected_status = qr{^Result: PASS$};
+ my $summary = pop @output;
+ my $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # use an alias for test name
+
+ @output = ();
+ ok $aggregate
+ = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ] ),
+ 'runtests returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ @expected = (
+ 'My Nice Test ..',
+ '1..1',
+ 'ok 1 - this is a test',
+ 'ok',
+ 'All tests successful.',
+ );
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # run same test twice
+
+ @output = ();
+ ok $aggregate = _runtests(
+ $harness, [ "$source_tests/harness", 'My Nice Test' ],
+ [ "$source_tests/harness", 'My Nice Test Again' ]
+ ),
+ 'runtests labels returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ @expected = (
+ 'My Nice Test ........',
+ '1..1',
+ 'ok 1 - this is a test',
+ 'ok',
+ 'My Nice Test Again ..',
+ '1..1',
+ 'ok 1 - this is a test',
+ 'ok',
+ 'All tests successful.',
+ );
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr{^Files=2, Tests=2, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests in quiet mode
+
+ @output = ();
+ ok _runtests( $harness_whisper, "$source_tests/harness" ),
+ 'Run tests with whisper';
+
+ chomp(@output);
+ @expected = (
+ "$source_tests/harness .. ok",
+ 'All tests successful.',
+ );
+
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests in really_quiet mode
+
+ @output = ();
+ ok _runtests( $harness_mute, "$source_tests/harness" ), 'Run tests mute';
+
+ chomp(@output);
+ @expected = (
+ 'All tests successful.',
+ );
+
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests with failures
+
+ @output = ();
+ ok _runtests( $harness, "$source_tests/harness_failure" ),
+ 'Run tests with failures';
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+
+ my @summary = @output[ 9 .. $#output ];
+ @output = @output[ 0 .. 8 ];
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ '1..2',
+ 'ok 1 - this is a test',
+ 'not ok 2 - this is another test',
+ q{# Failed test 'this is another test'},
+ '# in harness_failure.t at line 5.',
+ q{# got: 'waffle'},
+ q{# expected: 'yarblokos'},
+ 'Failed 1/2 subtests',
+ );
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ my @expected_summary = (
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ is_deeply \@summary, \@expected_summary,
+ '... and the failure summary should also be correct';
+
+ # quiet tests with failures
+
+ @output = ();
+ ok _runtests( $harness_whisper, "$source_tests/harness_failure" ),
+ 'Run whisper tests with failures';
+
+ $status = pop @output;
+ $summary = pop @output;
+ @expected = (
+ "$source_tests/harness_failure ..",
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ # really quiet tests with failures
+
+ @output = ();
+ ok _runtests( $harness_mute, "$source_tests/harness_failure" ),
+ 'Run mute tests with failures';
+
+ $status = pop @output;
+ $summary = pop @output;
+ @expected = (
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ # only show directives
+
+ @output = ();
+ ok _runtests(
+ $harness_directives,
+ "$source_tests/harness_directives"
+ ),
+ 'Run tests with directives';
+
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_directives ..",
+ 'not ok 2 - we have a something # TODO some output',
+ "ok 3 houston, we don't have liftoff # SKIP no funding",
+ 'ok',
+ 'All tests successful.',
+
+ # ~TODO {{{ this should be an option
+ #'Test Summary Report',
+ #'-------------------',
+ #"$source_tests/harness_directives (Wstat: 0 Tests: 3 Failed: 0)",
+ #'Tests skipped:',
+ #'3',
+ # }}}
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=3, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... the output should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ like $status, qr{^Result: PASS$},
+ '... and the status line should be correct';
+
+ # normal tests with bad tap
+
+ @output = ();
+ ok _runtests( $harness, "$source_tests/harness_badtap" ),
+ 'Run tests with bad TAP';
+ chomp(@output);
+
+ @output = map { trim($_) } @output;
+ $status = pop @output;
+ @summary = @output[ 6 .. ( $#output - 1 ) ];
+ @output = @output[ 0 .. 5 ];
+ @expected = (
+ "$source_tests/harness_badtap ..",
+ '1..2',
+ 'ok 1 - this is a test',
+ 'not ok 2 - this is another test',
+ '1..2',
+ 'Failed 1/2 subtests',
+ );
+ is_deeply \@output, \@expected,
+ '... failing test output should be correct';
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+ @expected_summary = (
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_badtap (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ 'Parse errors: More than one plan found in TAP output',
+ );
+ is_deeply \@summary, \@expected_summary,
+ '... and the badtap summary should also be correct';
+
+ # coverage testing for _should_show_failures
+ # only show failures
+
+ @output = ();
+ ok _runtests( $harness_failures, "$source_tests/harness_failure" ),
+ 'Run tests with failures only';
+
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ 'not ok 2 - this is another test',
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ # check the status output for no tests
+
+ @output = ();
+ ok _runtests( $harness_failures, "$sample_tests/no_output" ),
+ 'Run tests with failures';
+
+ chomp(@output);
+
+ @expected = (
+ "$sample_tests/no_output ..",
+ 'No subtests run',
+ 'Test Summary Report',
+ '-------------------',
+ "$sample_tests/no_output (Wstat: 0 Tests: 0 Failed: 0)",
+ 'Parse errors: No plan found in TAP output',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ # coverage testing for _should_show_comments
+ # only show comments
+
+ @output = ();
+ ok _runtests( $harness_comments, "$source_tests/harness_failure" ),
+ 'Run tests with comments';
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ q{# Failed test 'this is another test'},
+ '# in harness_failure.t at line 5.',
+ q{# got: 'waffle'},
+ q{# expected: 'yarblokos'},
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ # coverage testing for _should_show_comments and _should_show_failures
+ # only show comments and failures
+
+ @output = ();
+ $ENV{FOO} = 1;
+ ok _runtests( $harness_fandc, "$source_tests/harness_failure" ),
+ 'Run tests with failures and comments';
+ delete $ENV{FOO};
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ 'not ok 2 - this is another test',
+ q{# Failed test 'this is another test'},
+ '# in harness_failure.t at line 5.',
+ q{# got: 'waffle'},
+ q{# expected: 'yarblokos'},
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$}, '... the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ #XXXX
+}
+
+sub trim {
+ $_[0] =~ s/^\s+|\s+$//g;
+ return $_[0];
+}
+
+sub _runtests {
+ my ( $harness, @tests ) = @_;
+ local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
+ my $aggregate = $harness->runtests(@tests);
+ return $aggregate;
+}
+
diff --git a/cpan/Test-Harness/t/glob-to-regexp.t b/cpan/Test-Harness/t/glob-to-regexp.t
new file mode 100644
index 0000000000..493daab307
--- /dev/null
+++ b/cpan/Test-Harness/t/glob-to-regexp.t
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Test::More;
+
+require TAP::Parser::Scheduler;
+
+my @tests;
+while (<DATA>) {
+ my ( $glob, $pattern, $name ) = /^(\S+)\t+(\S+)(?:\t+(.*))?$/;
+ die "'$_'" unless $pattern;
+ push @tests, [ $glob, $pattern, $name ];
+}
+
+plan tests => scalar @tests;
+
+foreach (@tests) {
+ my ( $glob, $pattern, $name ) = @$_;
+ is( TAP::Parser::Scheduler->_glob_to_regexp($glob), $pattern,
+ defined $name ? "$glob -- $name" : $glob
+ );
+}
+__DATA__
+Pie Pie
+*.t [^/]*\.t
+**.t .*?\.t
+A?B A[^/]B
+*/*.t [^/]*\/[^/]*\.t
+A,B A\,B , outside {} not special
+{A,B} (?:A|B)
+A{B}C A(?:B)C
+A{B,C}D A(?:B|C)D
+A{B,C,D}E{F,G,H}I,J A(?:B|C|D)E(?:F|G|H)I\,J
+{Perl,Rules} (?:Perl|Rules)
+A}B A\}B Bare } corner case
+A{B,C}D}E A(?:B|C)D\}E
+},A{B,C}D},E \}\,A(?:B|C)D\}\,E
+{A{1,2},D{3,4}} (?:A(?:1|2)|D(?:3|4))
+{A,{B,C},D} (?:A|(?:B|C)|D)
+A{B,C\}D,E\,F}G A(?:B|C\}D|E\,F)G
+A\\B A\\B
+A(B)C A\(B\)C
+1{A(B)C,D|E}2 1(?:A\(B\)C|D\|E)2
diff --git a/cpan/Test-Harness/t/grammar.t b/cpan/Test-Harness/t/grammar.t
new file mode 100644
index 0000000000..b74fc8ba65
--- /dev/null
+++ b/cpan/Test-Harness/t/grammar.t
@@ -0,0 +1,455 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use Test::More tests => 94;
+
+use EmptyParser;
+use TAP::Parser::Grammar;
+use TAP::Parser::Iterator::Array;
+
+my $GRAMMAR = 'TAP::Parser::Grammar';
+
+# Array based stream that we can push items in to
+package SS;
+
+sub new {
+ my $class = shift;
+ return bless [], $class;
+}
+
+sub next {
+ my $self = shift;
+ return shift @$self;
+}
+
+sub put {
+ my $self = shift;
+ unshift @$self, @_;
+}
+
+sub handle_unicode { }
+
+package main;
+
+my $stream = SS->new;
+my $parser = EmptyParser->new;
+can_ok $GRAMMAR, 'new';
+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
+# why. We'll still use the instance because that should be forward
+# compatible.
+
+my @V12 = sort qw(bailout comment plan simple_test test version);
+my @V13 = sort ( @V12, 'pragma', 'yaml' );
+
+can_ok $grammar, 'token_types';
+ok my @types = sort( $grammar->token_types ),
+ '... and calling it should succeed (v12)';
+is_deeply \@types, \@V12, '... and return the correct token types (v12)';
+
+$grammar->set_version(13);
+ok @types = sort( $grammar->token_types ),
+ '... and calling it should succeed (v13)';
+is_deeply \@types, \@V13, '... and return the correct token types (v13)';
+
+can_ok $grammar, 'syntax_for';
+can_ok $grammar, 'handler_for';
+
+my ( %syntax_for, %handler_for );
+foreach my $type (@types) {
+ ok $syntax_for{$type} = $grammar->syntax_for($type),
+ '... and calling syntax_for() with a type name should succeed';
+ cmp_ok ref $syntax_for{$type}, 'eq', 'Regexp',
+ '... and it should return a regex';
+
+ ok $handler_for{$type} = $grammar->handler_for($type),
+ '... and calling handler_for() with a type name should succeed';
+ cmp_ok ref $handler_for{$type}, 'eq', 'CODE',
+ '... and it should return a code reference';
+}
+
+# Test the plan. Gotta have a plan.
+my $plan = '1..1';
+like $plan, $syntax_for{'plan'}, 'A basic plan should match its syntax';
+
+my $method = $handler_for{'plan'};
+$plan =~ $syntax_for{'plan'};
+ok my $plan_token = $grammar->$method($plan),
+ '... and the handler should return a token';
+
+my $expected = {
+ 'explanation' => '',
+ 'directive' => '',
+ 'type' => 'plan',
+ 'tests_planned' => 1,
+ 'raw' => '1..1',
+ 'todo_list' => [],
+};
+is_deeply $plan_token, $expected,
+ '... and it should contain the correct data';
+
+can_ok $grammar, 'tokenize';
+$stream->put($plan);
+ok my $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# a plan with a skip directive
+
+$plan = '1..0 # SKIP why not?';
+like $plan, $syntax_for{'plan'}, 'a basic plan should match its syntax';
+
+$plan =~ $syntax_for{'plan'};
+ok $plan_token = $grammar->$method($plan),
+ '... and the handler should return a token';
+
+$expected = {
+ 'explanation' => 'why not?',
+ 'directive' => 'SKIP',
+ 'type' => 'plan',
+ 'tests_planned' => 0,
+ 'raw' => '1..0 # SKIP why not?',
+ 'todo_list' => [],
+};
+is_deeply $plan_token, $expected,
+ '... and it should contain the correct data';
+
+$stream->put($plan);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# implied skip
+
+$plan = '1..0';
+like $plan, $syntax_for{'plan'},
+ 'A plan with an implied "skip all" should match its syntax';
+
+$plan =~ $syntax_for{'plan'};
+ok $plan_token = $grammar->$method($plan),
+ '... and the handler should return a token';
+
+$expected = {
+ 'explanation' => '',
+ 'directive' => 'SKIP',
+ 'type' => 'plan',
+ 'tests_planned' => 0,
+ 'raw' => '1..0',
+ 'todo_list' => [],
+};
+is_deeply $plan_token, $expected,
+ '... and it should contain the correct data';
+
+$stream->put($plan);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# bad plan
+
+$plan = '1..0 # TODO 3,4,5'; # old syntax. No longer supported
+unlike $plan, $syntax_for{'plan'},
+ 'Bad plans should not match the plan syntax';
+
+# Bail out!
+
+my $bailout = 'Bail out!';
+like $bailout, $syntax_for{'bailout'},
+ 'Bail out! should match a bailout syntax';
+
+$stream->put($bailout);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+$expected = {
+ 'bailout' => '',
+ 'type' => 'bailout',
+ 'raw' => 'Bail out!'
+};
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+$bailout = 'Bail out! some explanation';
+like $bailout, $syntax_for{'bailout'},
+ 'Bail out! should match a bailout syntax';
+
+$stream->put($bailout);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+$expected = {
+ 'bailout' => 'some explanation',
+ 'type' => 'bailout',
+ 'raw' => 'Bail out! some explanation'
+};
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# test comment
+
+my $comment = '# this is a comment';
+like $comment, $syntax_for{'comment'},
+ 'Comments should match the comment syntax';
+
+$stream->put($comment);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+$expected = {
+ 'comment' => 'this is a comment',
+ 'type' => 'comment',
+ 'raw' => '# this is a comment'
+};
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# test tests :/
+
+my $test = 'ok 1 this is a test';
+like $test, $syntax_for{'test'}, 'Tests should match the test syntax';
+
+$stream->put($test);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'ok' => 'ok',
+ 'explanation' => '',
+ 'type' => 'test',
+ 'directive' => '',
+ 'description' => 'this is a test',
+ 'test_num' => '1',
+ 'raw' => 'ok 1 this is a test'
+};
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# TODO tests
+
+$test = 'not ok 2 this is a test # TODO whee!';
+like $test, $syntax_for{'test'}, 'Tests should match the test syntax';
+
+$stream->put($test);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'ok' => 'not ok',
+ 'explanation' => 'whee!',
+ 'type' => 'test',
+ 'directive' => 'TODO',
+ 'description' => 'this is a test',
+ 'test_num' => '2',
+ 'raw' => 'not ok 2 this is a test # TODO whee!'
+};
+is_deeply $token, $expected, '... and the TODO should be parsed';
+
+# false TODO tests
+
+# escaping that hash mark ('#') means this should *not* be a TODO test
+$test = 'ok 22 this is a test \# TODO whee!';
+like $test, $syntax_for{'test'}, 'Tests should match the test syntax';
+
+$stream->put($test);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'ok' => 'ok',
+ 'explanation' => '',
+ 'type' => 'test',
+ 'directive' => '',
+ 'description' => 'this is a test \# TODO whee!',
+ 'test_num' => '22',
+ 'raw' => 'ok 22 this is a test \# TODO whee!'
+};
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# pragmas
+
+my $pragma = 'pragma +strict';
+like $pragma, $syntax_for{'pragma'}, 'Pragmas should match the pragma syntax';
+
+$stream->put($pragma);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'type' => 'pragma',
+ 'raw' => $pragma,
+ 'pragmas' => ['+strict'],
+};
+
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+$pragma = 'pragma +strict,-foo';
+like $pragma, $syntax_for{'pragma'}, 'Pragmas should match the pragma syntax';
+
+$stream->put($pragma);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'type' => 'pragma',
+ 'raw' => $pragma,
+ 'pragmas' => [ '+strict', '-foo' ],
+};
+
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+$pragma = 'pragma +strict , -foo ';
+like $pragma, $syntax_for{'pragma'}, 'Pragmas should match the pragma syntax';
+
+$stream->put($pragma);
+ok $token = $grammar->tokenize,
+ '... and calling it with data should return a token';
+
+$expected = {
+ 'type' => 'pragma',
+ 'raw' => $pragma,
+ 'pragmas' => [ '+strict', '-foo' ],
+};
+
+is_deeply $token, $expected,
+ '... and the token should contain the correct data';
+
+# coverage tests
+
+# set_version
+
+{
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $grammar->set_version('no_such_version');
+ };
+
+ unless ( is @die, 1, 'set_version with bad version' ) {
+ diag " >>> $_ <<<\n" for @die;
+ }
+
+ like pop @die, qr/^Unsupported syntax version: no_such_version at /,
+ '... and got expected message';
+}
+
+# tokenize
+{
+ my $stream = SS->new;
+ my $parser = EmptyParser->new;
+ my $grammar = $GRAMMAR->new( { stream => $stream, parser => $parser } );
+
+ my $plan = '';
+
+ $stream->put($plan);
+
+ my $result = $grammar->tokenize();
+
+ isa_ok $result, 'TAP::Parser::Result::Unknown';
+}
+
+# _make_plan_token
+
+{
+ my $parser = EmptyParser->new;
+ my $grammar = $GRAMMAR->new( { parser => $parser } );
+
+ my $plan
+ = '1..1 # SKIP with explanation'; # trigger warning in _make_plan_token
+
+ my $method = $handler_for{'plan'};
+
+ $plan =~ $syntax_for{'plan'}; # perform regex to populate $1, $2
+
+ my @warn;
+
+ eval {
+ local $SIG{__WARN__} = sub { push @warn, @_ };
+
+ $grammar->$method($plan);
+ };
+
+ is @warn, 1, 'catch warning on inconsistent plan';
+
+ like pop @warn,
+ qr/^Specified SKIP directive in plan but more than 0 tests [(]1\.\.1 # SKIP with explanation[)]/,
+ '... and its what we expect';
+}
+
+# _make_yaml_token
+
+{
+ my $stream = SS->new;
+ my $parser = EmptyParser->new;
+ my $grammar = $GRAMMAR->new( { stream => $stream, parser => $parser } );
+
+ $grammar->set_version(13);
+
+ # now this is badly formed YAML that is missing the
+ # leader padding - this is done for coverage testing
+ # the $reader code sub in _make_yaml_token, that is
+ # passed as the yaml consumer to T::P::YAMLish::Reader.
+
+ # because it isnt valid yaml, the yaml document is
+ # not done, and the _peek in the YAMLish::Reader
+ # code doesnt find the terminating '...' pattern.
+ # but we dont care as this is coverage testing, so
+ # if thats what we have to do to exercise that code,
+ # so be it.
+ my $yaml = [ ' ... ', '- 2', ' --- ', ];
+
+ sub iter {
+ my $ar = shift;
+ return sub {
+ return shift @$ar;
+ };
+ }
+
+ my $iter = iter($yaml);
+
+ while ( my $line = $iter->() ) {
+ $stream->put($line);
+ }
+
+ # pad == ' ', marker == '--- '
+ # length $pad == 3
+ # strip == pad
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+ $grammar->tokenize;
+ };
+
+ is @die, 1, 'checking badly formed yaml for coverage testing';
+
+ like pop @die, qr/^Missing '[.][.][.]' at end of YAMLish/,
+ '...and it died like we expect';
+}
+
+{
+
+ # coverage testing for TAP::Parser::Iterator::Array
+
+ my $source = [qw( a b c )];
+
+ my $aiter = TAP::Parser::Iterator::Array->new($source);
+
+ my $first = $aiter->next_raw;
+
+ is $first, 'a', 'access raw iterator';
+
+ is $aiter->exit, undef, '... and note we didnt exhaust the source';
+}
diff --git a/cpan/Test-Harness/t/harness-bailout.t b/cpan/Test-Harness/t/harness-bailout.t
new file mode 100644
index 0000000000..fd1dc35669
--- /dev/null
+++ b/cpan/Test-Harness/t/harness-bailout.t
@@ -0,0 +1,54 @@
+#!perl
+
+use strict;
+use File::Spec;
+
+BEGIN {
+ *CORE::GLOBAL::exit = sub { die '!exit called!' };
+}
+
+use TAP::Harness;
+use Test::More;
+
+my @jobs = (
+ { name => 'sequential',
+ args => { verbosity => -9 },
+ },
+ { name => 'parallel',
+ args => { verbosity => -9, jobs => 2 },
+ },
+);
+
+plan tests => @jobs * 2;
+
+for my $test (@jobs) {
+ my $name = $test->{name};
+ my $args = $test->{args};
+ my $harness = TAP::Harness->new($args);
+ eval {
+ local ( *OLDERR, *OLDOUT );
+ open OLDERR, '>&STDERR' or die $!;
+ open OLDOUT, '>&STDOUT' or die $!;
+ my $devnull = File::Spec->devnull;
+ open STDERR, ">$devnull" or die $!;
+ open STDOUT, ">$devnull" or die $!;
+
+ $harness->runtests(
+ File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'bailout'
+ )
+ );
+
+ open STDERR, '>&OLDERR' or die $!;
+ open STDOUT, '>&OLDOUT' or die $!;
+ };
+ my $err = $@;
+ unlike $err, qr{!exit called!}, "$name: didn't exit";
+ like $err, qr{FAILED--Further testing stopped: GERONIMMMOOOOOO!!!},
+ "$name: bailout message";
+}
+
+# vim:ts=2:sw=2:et:ft=perl
+
diff --git a/cpan/Test-Harness/t/harness-subclass.t b/cpan/Test-Harness/t/harness-subclass.t
new file mode 100644
index 0000000000..c6b46daa21
--- /dev/null
+++ b/cpan/Test-Harness/t/harness-subclass.t
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use TAP::Harness;
+use Test::More tests => 13;
+
+my %class_map = (
+ aggregator_class => 'My::TAP::Parser::Aggregator',
+ formatter_class => 'My::TAP::Formatter::Console',
+ multiplexer_class => 'My::TAP::Parser::Multiplexer',
+ parser_class => 'My::TAP::Parser',
+ scheduler_class => 'My::TAP::Parser::Scheduler',
+);
+
+my %loaded = ();
+
+# Synthesize our subclasses
+for my $class ( values %class_map ) {
+ ( my $base_class = $class ) =~ s/^My:://;
+ use_ok($base_class);
+
+ no strict 'refs';
+ @{"${class}::ISA"} = ($base_class);
+ *{"${class}::new"} = sub {
+ my $pkg = shift;
+ $loaded{$pkg} = 1;
+
+ # Can't use SUPER outside a package
+ return $base_class->can('new')->( $pkg, @_ );
+ };
+}
+
+{
+ ok my $harness = TAP::Harness->new( { %class_map, verbosity => -9 } ),
+ 'created harness';
+ isa_ok $harness, 'TAP::Harness';
+
+ # Test dynamic loading
+ ok !$INC{'NOP.pm'}, 'NOP not loaded';
+ ok my $nop = $harness->_construct('NOP'), 'loaded and created';
+ isa_ok $nop, 'NOP';
+ ok $INC{'NOP.pm'}, 'NOP loaded';
+
+ my $aggregate = $harness->runtests(
+ File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'simple'
+ )
+ );
+
+ isa_ok $aggregate, 'My::TAP::Parser::Aggregator';
+
+ is_deeply \%loaded,
+ { 'My::TAP::Parser::Aggregator' => 1,
+ 'My::TAP::Formatter::Console' => 1,
+ 'My::TAP::Parser' => 1,
+ 'My::TAP::Parser::Scheduler' => 1,
+ },
+ 'loaded our classes';
+}
diff --git a/cpan/Test-Harness/t/harness.t b/cpan/Test-Harness/t/harness.t
new file mode 100644
index 0000000000..3643f576f3
--- /dev/null
+++ b/cpan/Test-Harness/t/harness.t
@@ -0,0 +1,982 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+
+use Test::More;
+use IO::c55Capture;
+
+use TAP::Harness;
+
+my $HARNESS = 'TAP::Harness';
+
+my $source_tests = 't/source_tests';
+my $sample_tests = 't/sample-tests';
+
+plan tests => 119;
+
+# note that this test will always pass when run through 'prove'
+ok $ENV{HARNESS_ACTIVE}, 'HARNESS_ACTIVE env variable should be set';
+ok $ENV{HARNESS_VERSION}, 'HARNESS_VERSION env variable should be set';
+
+#### For color tests ####
+
+package Colorizer;
+
+sub new { bless {}, shift }
+sub can_color {1}
+
+sub set_color {
+ my ( $self, $output, $color ) = @_;
+ $output->("[[$color]]");
+}
+
+package main;
+
+sub colorize {
+ my $harness = shift;
+ $harness->formatter->_colorizer( Colorizer->new );
+}
+
+can_ok $HARNESS, 'new';
+
+eval { $HARNESS->new( { no_such_key => 1 } ) };
+like $@, qr/\QUnknown arguments to TAP::Harness::new (no_such_key)/,
+ '... and calling it with bad keys should fail';
+
+eval { $HARNESS->new( { lib => 'aint_no_such_lib' } ) };
+is $@, '', '... and calling it with a non-existent lib is fine';
+
+eval { $HARNESS->new( { lib => [qw/bad_lib_1 bad_lib_2/] } ) };
+is $@, '', '... and calling it with non-existent libs is fine';
+
+ok my $harness = $HARNESS->new,
+ 'Calling new() without arguments should succeed';
+
+foreach my $test_args ( get_arg_sets() ) {
+ my %args = %$test_args;
+ foreach my $key ( sort keys %args ) {
+ $args{$key} = $args{$key}{in};
+ }
+ ok my $harness = $HARNESS->new( {%args} ),
+ 'Calling new() with valid arguments should succeed';
+ isa_ok $harness, $HARNESS, '... and the object it returns';
+
+ while ( my ( $property, $test ) = each %$test_args ) {
+ my $value = $test->{out};
+ can_ok $harness, $property;
+ is_deeply scalar $harness->$property(), $value, $test->{test_name};
+ }
+}
+
+{
+ my @output;
+ local $^W;
+ local *TAP::Formatter::Base::_output = sub {
+ my $self = shift;
+ push @output => grep { $_ ne '' }
+ map {
+ local $_ = $_;
+ chomp;
+ trim($_)
+ } @_;
+ };
+ my $harness = TAP::Harness->new(
+ { verbosity => 1, formatter_class => "TAP::Formatter::Console" } );
+ my $harness_whisper = TAP::Harness->new(
+ { verbosity => -1, formatter_class => "TAP::Formatter::Console" } );
+ my $harness_mute = TAP::Harness->new(
+ { verbosity => -2, formatter_class => "TAP::Formatter::Console" } );
+ my $harness_directives = TAP::Harness->new(
+ { directives => 1, formatter_class => "TAP::Formatter::Console" } );
+ my $harness_failures = TAP::Harness->new(
+ { failures => 1, formatter_class => "TAP::Formatter::Console" } );
+
+ colorize($harness);
+
+ can_ok $harness, 'runtests';
+
+ # normal tests in verbose mode
+
+ ok my $aggregate = _runtests( $harness, "$source_tests/harness" ),
+ '... runtests returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ my @expected = (
+ "$source_tests/harness ..",
+ '1..1',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ 'ok',
+ '[[green]]',
+ 'All tests successful.',
+ '[[reset]]',
+ );
+ my $status = pop @output;
+ my $expected_status = qr{^Result: PASS$};
+ my $summary = pop @output;
+ my $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # use an alias for test name
+
+ @output = ();
+ ok $aggregate
+ = _runtests( $harness, [ "$source_tests/harness", 'My Nice Test' ] ),
+ '... runtests returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ @expected = (
+ 'My Nice Test ..',
+ '1..1',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ 'ok',
+ '[[green]]',
+ 'All tests successful.',
+ '[[reset]]',
+ );
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr{^Files=1, Tests=1, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # run same test twice
+
+ @output = ();
+ ok $aggregate = _runtests(
+ $harness, [ "$source_tests/harness", 'My Nice Test' ],
+ [ "$source_tests/harness", 'My Nice Test Again' ]
+ ),
+ '... runtests returns the aggregate';
+
+ isa_ok $aggregate, 'TAP::Parser::Aggregator';
+
+ chomp(@output);
+
+ @expected = (
+ 'My Nice Test ........',
+ '1..1',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ 'ok',
+ 'My Nice Test Again ..',
+ '1..1',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ 'ok',
+ '[[green]]',
+ 'All tests successful.',
+ '[[reset]]',
+ );
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr{^Files=2, Tests=2, \d+ wallclock secs};
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests in quiet mode
+
+ @output = ();
+ _runtests( $harness_whisper, "$source_tests/harness" );
+
+ chomp(@output);
+ @expected = (
+ "$source_tests/harness ..",
+ 'ok',
+ 'All tests successful.',
+ );
+
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests in really_quiet mode
+
+ @output = ();
+ _runtests( $harness_mute, "$source_tests/harness" );
+
+ chomp(@output);
+ @expected = (
+ 'All tests successful.',
+ );
+
+ $status = pop @output;
+ $expected_status = qr{^Result: PASS$};
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=1, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $status, $expected_status,
+ '... and the status line should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ # normal tests with failures
+
+ @output = ();
+ _runtests( $harness, "$source_tests/harness_failure" );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+
+ my @summary = @output[ 18 .. $#output ];
+ @output = @output[ 0 .. 17 ];
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ '1..2',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ '[[red]]',
+ 'not ok 2 - this is another test',
+ '[[reset]]',
+ q{# Failed test 'this is another test'},
+ '[[reset]]',
+ '# in harness_failure.t at line 5.',
+ '[[reset]]',
+ q{# got: 'waffle'},
+ '[[reset]]',
+ q{# expected: 'yarblokos'},
+ '[[reset]]',
+ '[[red]]',
+ 'Failed 1/2 subtests',
+ );
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ my @expected_summary = (
+ '[[reset]]',
+ 'Test Summary Report',
+ '-------------------',
+ '[[red]]',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ '[[reset]]',
+ '[[red]]',
+ 'Failed test:',
+ '[[reset]]',
+ '[[red]]',
+ '2',
+ '[[reset]]',
+ );
+
+ is_deeply \@summary, \@expected_summary,
+ '... and the failure summary should also be correct';
+
+ # quiet tests with failures
+
+ @output = ();
+ _runtests( $harness_whisper, "$source_tests/harness_failure" );
+
+ $status = pop @output;
+ $summary = pop @output;
+ @expected = (
+ "$source_tests/harness_failure ..",
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ # really quiet tests with failures
+
+ @output = ();
+ _runtests( $harness_mute, "$source_tests/harness_failure" );
+
+ $status = pop @output;
+ $summary = pop @output;
+ @expected = (
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+
+ # only show directives
+
+ @output = ();
+ _runtests(
+ $harness_directives,
+ "$source_tests/harness_directives"
+ );
+
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_directives ..",
+ 'not ok 2 - we have a something # TODO some output',
+ "ok 3 houston, we don't have liftoff # SKIP no funding",
+ 'ok',
+ 'All tests successful.',
+
+ # ~TODO {{{ this should be an option
+ #'Test Summary Report',
+ #'-------------------',
+ #"$source_tests/harness_directives (Wstat: 0 Tests: 3 Failed: 0)",
+ #'Tests skipped:',
+ #'3',
+ # }}}
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+ $expected_summary = qr/^Files=1, Tests=3, \d+ wallclock secs/;
+
+ is_deeply \@output, \@expected, '... and the output should be correct';
+ like $summary, $expected_summary,
+ '... and the report summary should look correct';
+
+ like $status, qr{^Result: PASS$},
+ '... and the status line should be correct';
+
+ # normal tests with bad tap
+
+ # install callback handler
+ my $parser;
+ my $callback_count = 0;
+
+ my @callback_log = ();
+
+ for my $evt (qw(parser_args made_parser before_runtests after_runtests)) {
+ $harness->callback(
+ $evt => sub {
+ push @callback_log, $evt;
+ }
+ );
+ }
+
+ $harness->callback(
+ made_parser => sub {
+ $parser = shift;
+ $callback_count++;
+ }
+ );
+
+ @output = ();
+ _runtests( $harness, "$source_tests/harness_badtap" );
+ chomp(@output);
+
+ @output = map { trim($_) } @output;
+ $status = pop @output;
+ @summary = @output[ 12 .. ( $#output - 1 ) ];
+ @output = @output[ 0 .. 11 ];
+ @expected = (
+ "$source_tests/harness_badtap ..",
+ '1..2',
+ '[[reset]]',
+ 'ok 1 - this is a test',
+ '[[reset]]',
+ '[[red]]',
+ 'not ok 2 - this is another test',
+ '[[reset]]',
+ '1..2',
+ '[[reset]]',
+ '[[red]]',
+ 'Failed 1/2 subtests',
+ );
+ is_deeply \@output, \@expected,
+ '... and failing test output should be correct';
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+ @expected_summary = (
+ '[[reset]]',
+ 'Test Summary Report',
+ '-------------------',
+ '[[red]]',
+ "$source_tests/harness_badtap (Wstat: 0 Tests: 2 Failed: 1)",
+ '[[reset]]',
+ '[[red]]',
+ 'Failed test:',
+ '[[reset]]',
+ '[[red]]',
+ '2',
+ '[[reset]]',
+ '[[red]]',
+ 'Parse errors: More than one plan found in TAP output',
+ '[[reset]]',
+ );
+ is_deeply \@summary, \@expected_summary,
+ '... and the badtap summary should also be correct';
+
+ cmp_ok( $callback_count, '==', 1, 'callback called once' );
+ is_deeply(
+ \@callback_log,
+ [ 'before_runtests', 'parser_args', 'made_parser', 'after_runtests' ],
+ 'callback log matches'
+ );
+ isa_ok $parser, 'TAP::Parser';
+
+ # coverage testing for _should_show_failures
+ # only show failures
+
+ @output = ();
+ _runtests( $harness_failures, "$source_tests/harness_failure" );
+
+ chomp(@output);
+
+ @expected = (
+ "$source_tests/harness_failure ..",
+ 'not ok 2 - this is another test',
+ 'Failed 1/2 subtests',
+ 'Test Summary Report',
+ '-------------------',
+ "$source_tests/harness_failure (Wstat: 0 Tests: 2 Failed: 1)",
+ 'Failed test:',
+ '2',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ # check the status output for no tests
+
+ @output = ();
+ _runtests( $harness_failures, "$sample_tests/no_output" );
+
+ chomp(@output);
+
+ @expected = (
+ "$sample_tests/no_output ..",
+ 'No subtests run',
+ 'Test Summary Report',
+ '-------------------',
+ "$sample_tests/no_output (Wstat: 0 Tests: 0 Failed: 0)",
+ 'Parse errors: No plan found in TAP output',
+ );
+
+ $status = pop @output;
+ $summary = pop @output;
+
+ like $status, qr{^Result: FAIL$},
+ '... and the status line should be correct';
+ $expected_summary = qr/^Files=1, Tests=2, \d+ wallclock secs/;
+ is_deeply \@output, \@expected, '... and the output should be correct';
+
+ #XXXX
+}
+
+# make sure we can exec something ... anything!
+SKIP: {
+
+ my $cat = '/bin/cat';
+ unless ( -e $cat ) {
+ skip "no '$cat'", 2;
+ }
+
+ my $capture = IO::c55Capture->new_handle;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ stdout => $capture,
+ exec => [$cat],
+ }
+ );
+
+ eval {
+ _runtests(
+ $harness,
+ 't/data/catme.1'
+ );
+ };
+
+ 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' );
+}
+
+# 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' );
+}
+
+# Exec with a coderef that returns an arrayref
+SKIP: {
+ my $cat = '/bin/cat';
+ unless ( -e $cat ) {
+ skip "no '$cat'", 2;
+ }
+
+ my $capture = IO::c55Capture->new_handle;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ stdout => $capture,
+ exec => sub {
+ return [
+ $cat,
+ 't/data/catme.1'
+ ];
+ },
+ }
+ );
+
+ _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' );
+}
+
+# Exec with a coderef that returns raw TAP
+{
+ my $capture = IO::c55Capture->new_handle;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ stdout => $capture,
+ exec => sub {
+ return "1..1\nok 1 - raw TAP\n";
+ },
+ }
+ );
+
+ _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' );
+}
+
+# Exec with a coderef that returns a filehandle
+{
+ my $capture = IO::c55Capture->new_handle;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ stdout => $capture,
+ exec => sub {
+ open my $fh, 't/data/catme.1';
+ return $fh;
+ },
+ }
+ );
+
+ _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;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ stdout => $capture,
+ exec => [$^X]
+ }
+ );
+
+ _runtests(
+ $harness,
+ "$source_tests/harness_complain"
+ , # will get mad if run with args
+ "$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
+ is( $output[-1], "All tests successful.\n",
+ 'No exec accumulation'
+ );
+}
+
+sub trim {
+ $_[0] =~ s/^\s+|\s+$//g;
+ return $_[0];
+}
+
+sub liblist {
+ return [ map {"-I$_"} @_ ];
+}
+
+sub get_arg_sets {
+
+ # keys are keys to new()
+ return {
+ lib => {
+ in => 'lib',
+ out => liblist('lib'),
+ test_name => '... a single lib switch should be correct'
+ },
+ verbosity => {
+ in => 1,
+ out => 1,
+ test_name => '... and we should be able to set verbosity to 1'
+ },
+
+ # verbose => {
+ # in => 1,
+ # out => 1,
+ # test_name => '... and we should be able to set verbose to true'
+ # },
+ },
+ { lib => {
+ in => [ 'lib', 't' ],
+ out => liblist( 'lib', 't' ),
+ test_name => '... multiple lib dirs should be correct'
+ },
+ verbosity => {
+ in => 0,
+ out => 0,
+ test_name => '... and we should be able to set verbosity to 0'
+ },
+
+ # verbose => {
+ # in => 0,
+ # out => 0,
+ # test_name => '... and we should be able to set verbose to false'
+ # },
+ },
+ { switches => {
+ in => [ '-T', '-w', '-T' ],
+ out => [ '-T', '-w', '-T' ],
+ test_name => '... duplicate switches should remain',
+ },
+ failures => {
+ in => 1,
+ out => 1,
+ test_name =>
+ '... and we should be able to set failures to true',
+ },
+ verbosity => {
+ in => -1,
+ out => -1,
+ test_name => '... and we should be able to set verbosity to -1'
+ },
+
+ # quiet => {
+ # in => 1,
+ # out => 1,
+ # test_name => '... and we should be able to set quiet to false'
+ # },
+ },
+
+ { verbosity => {
+ in => -2,
+ out => -2,
+ test_name => '... and we should be able to set verbosity to -2'
+ },
+
+ # really_quiet => {
+ # in => 1,
+ # out => 1,
+ # test_name =>
+ # '... and we should be able to set really_quiet to true',
+ # },
+ exec => {
+ in => $^X,
+ out => $^X,
+ test_name =>
+ '... and we should be able to set the executable',
+ },
+ },
+ { switches => {
+ in => 'T',
+ out => ['T'],
+ test_name =>
+ '... leading dashes (-) on switches are not optional',
+ },
+ },
+ { switches => {
+ in => '-T',
+ out => ['-T'],
+ test_name => '... we should be able to set switches',
+ },
+ failures => {
+ in => 1,
+ out => 1,
+ test_name => '... and we should be able to set failures to true'
+ },
+ };
+}
+
+sub _runtests {
+ my ( $harness, @tests ) = @_;
+ local $ENV{PERL_TEST_HARNESS_DUMP_TAP} = 0;
+ my $aggregate = $harness->runtests(@tests);
+ return $aggregate;
+}
+
+{
+
+ # coverage tests for ctor
+
+ my $harness = TAP::Harness->new(
+ { timer => 0,
+ errors => 1,
+ merge => 2,
+
+ # formatter => 3,
+ }
+ );
+
+ is $harness->timer(), 0, 'timer getter';
+ is $harness->timer(10), 10, 'timer setter';
+ is $harness->errors(), 1, 'errors getter';
+ is $harness->errors(10), 10, 'errors setter';
+ is $harness->merge(), 2, 'merge getter';
+ is $harness->merge(10), 10, 'merge setter';
+
+ # jobs accessor
+ is $harness->jobs(), 1, 'jobs';
+}
+
+{
+
+# coverage tests for the stdout key of VALIDATON_FOR, used by _initialize() in the ctor
+
+ # the coverage tests are
+ # 1. ref $ref => false
+ # 2. ref => ! GLOB and ref->can(print)
+ # 3. ref $ref => GLOB
+
+ # case 1
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ my $harness = TAP::Harness->new(
+ { stdout => bless {}, '0', # how evil is THAT !!!
+ }
+ );
+ };
+
+ is @die, 1, 'bad filehandle to stdout';
+ like pop @die, qr/option 'stdout' needs a filehandle/,
+ '... and we died as expected';
+
+ # case 2
+
+ @die = ();
+
+ package Printable;
+
+ sub new { return bless {}, shift }
+
+ sub print {return}
+
+ package main;
+
+ my $harness = TAP::Harness->new(
+ { stdout => Printable->new(),
+ }
+ );
+
+ isa_ok $harness, 'TAP::Harness';
+
+ # case 3
+
+ @die = ();
+
+ $harness = TAP::Harness->new(
+ { stdout => bless {}, 'GLOB', # again with the evil
+ }
+ );
+
+ isa_ok $harness, 'TAP::Harness';
+}
+
+{
+
+ # coverage testing of lib/switches accessor
+ my $harness = TAP::Harness->new;
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $harness->switches(qw( too many arguments));
+ };
+
+ is @die, 1, 'too many arguments to accessor';
+
+ like pop @die, qr/Too many arguments to method 'switches'/,
+ '...and we died as expected';
+
+ $harness->switches('simple scalar');
+
+ my $arrref = $harness->switches;
+ is_deeply $arrref, ['simple scalar'], 'scalar wrapped in arr ref';
+}
+
+{
+
+ # coverage tests for the basically untested T::H::_open_spool
+
+ my @spool = (
+ ( 't', 'spool' )
+ );
+ $ENV{PERL_TEST_HARNESS_DUMP_TAP} = File::Spec->catfile(@spool);
+
+# now given that we're going to be writing stuff to the file system, make sure we have
+# a cleanup hook
+
+ END {
+ use File::Path;
+
+ # remove the tree if we made it this far
+ rmtree( $ENV{PERL_TEST_HARNESS_DUMP_TAP} )
+ if $ENV{PERL_TEST_HARNESS_DUMP_TAP};
+ }
+
+ my $harness = TAP::Harness->new( { verbosity => -2 } );
+
+ can_ok $harness, 'runtests';
+
+ # normal tests in verbose mode
+
+ my $parser
+ = $harness->runtests( File::Spec->catfile( $source_tests, 'harness' ) );
+
+ isa_ok $parser, 'TAP::Parser::Aggregator',
+ '... runtests returns the aggregate';
+
+ ok -e File::Spec->catfile(
+ $ENV{PERL_TEST_HARNESS_DUMP_TAP},
+ $source_tests, 'harness'
+ );
+}
+
+{
+
+ # test name munging
+ my @cases = (
+ { name => 'all the same',
+ input => [ 'foo.t', 'bar.t', 'fletz.t' ],
+ output => [
+ [ 'foo.t', 'foo.t' ], [ 'bar.t', 'bar.t' ],
+ [ 'fletz.t', 'fletz.t' ]
+ ],
+ },
+ { name => 'all the same, already cooked',
+ input => [ 'foo.t', [ 'bar.t', 'brip' ], 'fletz.t' ],
+ output => [
+ [ 'foo.t', 'foo.t' ], [ 'bar.t', 'brip' ],
+ [ 'fletz.t', 'fletz.t' ]
+ ],
+ },
+ { 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/cpan/Test-Harness/t/iterators.t b/cpan/Test-Harness/t/iterators.t
new file mode 100644
index 0000000000..d190be9289
--- /dev/null
+++ b/cpan/Test-Harness/t/iterators.t
@@ -0,0 +1,215 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 76;
+
+use File::Spec;
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+use Config;
+
+sub array_ref_from {
+ my $string = shift;
+ my @lines = split /\n/ => $string;
+ return \@lines;
+}
+
+# we slurp __DATA__ and then reset it so we don't have to duplicate our TAP
+my $offset = tell DATA;
+my $tap = do { local $/; <DATA> };
+seek DATA, $offset, 0;
+
+my $did_setup = 0;
+my $did_teardown = 0;
+
+my $setup = sub { $did_setup++ };
+my $teardown = sub { $did_teardown++ };
+
+package NoForkProcess;
+use vars qw( @ISA );
+@ISA = qw( TAP::Parser::Iterator::Process );
+
+sub _use_open3 {return}
+
+package main;
+
+my @schedule = (
+ { name => 'Process',
+ subclass => 'TAP::Parser::Iterator::Process',
+ source => {
+ command => [
+ $^X,
+ File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'out_err_mix'
+ )
+ ],
+ merge => 1,
+ setup => $setup,
+ teardown => $teardown,
+ },
+ after => sub {
+ is $did_setup, 1, "setup called";
+ is $did_teardown, 1, "teardown called";
+ },
+ need_open3 => 15,
+ },
+ { name => 'Array',
+ subclass => 'TAP::Parser::Iterator::Array',
+ source => array_ref_from($tap),
+ },
+ { name => 'Stream',
+ subclass => 'TAP::Parser::Iterator::Stream',
+ source => \*DATA,
+ },
+ { name => 'Process (Perl -e)',
+ subclass => 'TAP::Parser::Iterator::Process',
+ source =>
+ { command => [ $^X, '-e', 'print qq/one\ntwo\n\nthree\n/' ] },
+ },
+ { name => 'Process (NoFork)',
+ subclass => 'TAP::Parser::Iterator::Process',
+ class => 'NoForkProcess',
+ source =>
+ { command => [ $^X, '-e', 'print qq/one\ntwo\n\nthree\n/' ] },
+ },
+);
+
+sub _can_open3 {
+ return $Config{d_fork};
+}
+
+my $factory = TAP::Parser::IteratorFactory->new;
+for my $test (@schedule) {
+ SKIP: {
+ my $name = $test->{name};
+ my $need_open3 = $test->{need_open3};
+ skip "No open3", $need_open3 if $need_open3 && !_can_open3();
+ my $subclass = $test->{subclass};
+ my $source = $test->{source};
+ 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';
+
+ can_ok $iter, 'exit';
+ ok !defined $iter->exit,
+ "$name: ... and it should be undef before we are done ($subclass)";
+
+ can_ok $iter, 'next';
+ is $iter->next, 'one', "$name: next() should return the first result";
+
+ is $iter->next, 'two',
+ "$name: next() should return the second result";
+
+ is $iter->next, '', "$name: next() should return the third result";
+
+ is $iter->next, 'three',
+ "$name: next() should return the fourth result";
+
+ ok !defined $iter->next,
+ "$name: next() should return undef after it is empty";
+
+ is $iter->exit, 0,
+ "$name: ... and exit should now return 0 ($subclass)";
+
+ is $iter->wait, 0, "$name: wait should also now return 0 ($subclass)";
+
+ if ( my $after = $test->{after} ) {
+ $after->();
+ }
+ }
+}
+
+{
+
+ # coverage tests for the ctor
+
+ my $stream = $factory->make_iterator( IO::Handle->new );
+
+ isa_ok $stream, 'TAP::Parser::Iterator::Stream';
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $factory->make_iterator( \1 ); # a ref to a scalar
+ };
+
+ is @die, 1, 'coverage of error case';
+
+ like pop @die, qr/Can't iterate with a SCALAR/,
+ '...and we died as expected';
+}
+
+{
+
+ # coverage test for VMS case
+
+ my $stream = $factory->make_iterator(
+ [ 'not ',
+ 'ok 1 - I hate VMS',
+ ]
+ );
+
+ is $stream->next, 'not ok 1 - I hate VMS',
+ 'coverage of VMS line-splitting case';
+
+ # coverage test for VMS case - nothing after 'not'
+
+ $stream = $factory->make_iterator(
+ [ 'not ',
+ ]
+ );
+
+ is $stream->next, 'not ', '...and we find "not" by itself';
+}
+
+SKIP: {
+ skip "No open3", 4 unless _can_open3();
+
+ # coverage testing for TAP::Parser::Iterator::Process ctor
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $factory->make_iterator( {} );
+ };
+
+ is @die, 1, 'coverage testing for TPI::Process';
+
+ like pop @die, qr/Must supply a command to execute/,
+ '...and we died as expected';
+
+ my $parser = $factory->make_iterator(
+ { command => [
+ $^X,
+ File::Spec->catfile( 't', 'sample-tests', 'out_err_mix' )
+ ],
+ merge => 1,
+ }
+ );
+
+ 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
+ # bug which frequently throws an error here otherwise.
+ $parser->next;
+}
+__DATA__
+one
+two
+
+three
diff --git a/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy.pm b/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy.pm
new file mode 100644
index 0000000000..81f79ea042
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy.pm
@@ -0,0 +1,9 @@
+package App::Prove::Plugin::Dummy;
+
+use strict;
+
+sub import {
+ main::test_log_import(@_);
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy2.pm b/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy2.pm
new file mode 100644
index 0000000000..ae80003e62
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/App/Prove/Plugin/Dummy2.pm
@@ -0,0 +1,13 @@
+package App::Prove::Plugin::Dummy2;
+
+use strict;
+
+sub import {
+ main::test_log_import(@_);
+}
+
+sub load {
+ main::test_log_plugin_load(@_);
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/Dev/Null.pm b/cpan/Test-Harness/t/lib/Dev/Null.pm
new file mode 100644
index 0000000000..09ca5d6627
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/Dev/Null.pm
@@ -0,0 +1,18 @@
+# For shutting up Test::Harness.
+# Has to work on 5.004 which doesn't have Tie::StdHandle.
+package Dev::Null;
+
+sub WRITE { }
+sub PRINT { }
+sub PRINTF { }
+
+sub TIEHANDLE {
+ my $class = shift;
+ my $fh = do { local *HANDLE; \*HANDLE };
+ return bless $fh, $class;
+}
+sub READ { }
+sub READLINE { }
+sub GETC { }
+
+1;
diff --git a/cpan/Test-Harness/t/lib/EmptyParser.pm b/cpan/Test-Harness/t/lib/EmptyParser.pm
new file mode 100644
index 0000000000..2f7ec2428e
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/EmptyParser.pm
@@ -0,0 +1,30 @@
+package EmptyParser;
+
+use strict;
+use vars qw(@ISA);
+
+use TAP::Parser ();
+
+@ISA = qw(TAP::Parser);
+
+sub _initialize {
+ shift->_set_defaults;
+}
+
+# this should really be in TAP::Parser itself...
+sub _set_defaults {
+ my $self = shift;
+
+ for my $key (
+ qw( source_class perl_source_class grammar_class
+ iterator_factory_class result_factory_class )
+ )
+ {
+ my $default_method = "_default_$key";
+ $self->$key( $self->$default_method() );
+ }
+
+ return $self;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/IO/c55Capture.pm b/cpan/Test-Harness/t/lib/IO/c55Capture.pm
new file mode 100644
index 0000000000..ecbcb49ba7
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/IO/c55Capture.pm
@@ -0,0 +1,120 @@
+package IO::c55Capture;
+
+use IO::Handle;
+
+=head1 Name
+
+t/lib/IO::c55Capture - a wafer-thin test support package
+
+=head1 Why!?
+
+Compatibility with 5.5.3 and no external dependencies.
+
+=head1 Usage
+
+Works with a global filehandle:
+
+ # set a spool to write to
+ tie local *STDOUT, 'IO::c55Capture';
+ ...
+ # clear and retrieve buffer list
+ my @spooled = tied(*STDOUT)->dump();
+
+Or, a lexical (and autocreated) filehandle:
+
+ my $capture = IO::c55Capture->new_handle;
+ ...
+ my @output = tied($$capture)->dump;
+
+Note the '$$' dereference.
+
+=cut
+
+# XXX actually returns an IO::Handle :-/
+sub new_handle {
+ my $class = shift;
+ my $handle = IO::Handle->new;
+ tie $$handle, $class;
+ return ($handle);
+}
+
+sub TIEHANDLE {
+ return bless [], __PACKAGE__;
+}
+
+sub PRINT {
+ my $self = shift;
+
+ push @$self, @_;
+}
+
+sub PRINTF {
+ my $self = shift;
+ push @$self, sprintf(@_);
+}
+
+sub dump {
+ my $self = shift;
+ my @got = @$self;
+ @$self = ();
+ return @got;
+}
+
+package util;
+
+use IO::File;
+
+# mostly stolen from Module::Build MBTest.pm
+
+{ # backwards compatible temp filename recipe adapted from perlfaq
+ my $tmp_count = 0;
+ my $tmp_base_name = sprintf( "%d-%d", $$, time() );
+
+ sub temp_file_name {
+ sprintf( "%s-%04d", $tmp_base_name, ++$tmp_count );
+ }
+}
+########################################################################
+
+sub save_handle {
+ my ( $handle, $subr ) = @_;
+ my $outfile = temp_file_name();
+
+ local *SAVEOUT;
+ open SAVEOUT, ">&" . fileno($handle)
+ or die "Can't save output handle: $!";
+ open $handle, "> $outfile" or die "Can't create $outfile: $!";
+
+ eval { $subr->() };
+ my $err = $@;
+ open $handle, ">&SAVEOUT" or die "Can't restore output: $!";
+
+ my $ret = slurp($outfile);
+ 1 while unlink $outfile;
+ $err and die $err;
+ return $ret;
+}
+
+sub stdout_of { save_handle( \*STDOUT, @_ ) }
+sub stderr_of { save_handle( \*STDERR, @_ ) }
+
+sub stdout_stderr_of {
+ my $subr = shift;
+ my ( $stdout, $stderr );
+ $stdout = stdout_of(
+ sub {
+ $stderr = stderr_of($subr);
+ }
+ );
+ return ( $stdout, $stderr );
+}
+
+sub slurp {
+ my $fh = IO::File->new( $_[0] ) or die "Can't open $_[0]: $!";
+ local $/;
+ return scalar <$fh>;
+}
+
+1;
+
+# vim:ts=4:sw=4:et:sta
diff --git a/cpan/Test-Harness/t/lib/MyCustom.pm b/cpan/Test-Harness/t/lib/MyCustom.pm
new file mode 100644
index 0000000000..2402312edc
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyCustom.pm
@@ -0,0 +1,12 @@
+# avoid cut-n-paste exhaustion with this mixin
+
+package MyCustom;
+use strict;
+
+sub custom {
+ my $self = shift;
+ $main::CUSTOM{ ref($self) }++;
+ return $self;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MyGrammar.pm b/cpan/Test-Harness/t/lib/MyGrammar.pm
new file mode 100644
index 0000000000..ef93f9dfc1
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyGrammar.pm
@@ -0,0 +1,21 @@
+# subclass for testing customizing & subclassing
+
+package MyGrammar;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use TAP::Parser::Grammar;
+
+@ISA = qw( TAP::Parser::Grammar MyCustom );
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ return $self;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MyIterator.pm b/cpan/Test-Harness/t/lib/MyIterator.pm
new file mode 100644
index 0000000000..561f6e2c78
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyIterator.pm
@@ -0,0 +1,26 @@
+# subclass for testing customizing & subclassing
+
+package MyIterator;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use TAP::Parser::Iterator;
+
+@ISA = qw( TAP::Parser::Iterator MyCustom );
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ $self->{content} = [ 'whats TAP all about then?', '1..1', 'ok 1' ];
+ return $self;
+}
+
+sub next {
+ return shift @{ $_[0]->{content} };
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MyIteratorFactory.pm b/cpan/Test-Harness/t/lib/MyIteratorFactory.pm
new file mode 100644
index 0000000000..d8c3269cda
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyIteratorFactory.pm
@@ -0,0 +1,19 @@
+# subclass for testing customizing & subclassing
+
+package MyIteratorFactory;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use MyIterator;
+use TAP::Parser::IteratorFactory;
+
+@ISA = qw( TAP::Parser::IteratorFactory MyCustom );
+
+sub make_iterator {
+ my $class = shift;
+ return MyIterator->new(@_);
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MyPerlSource.pm b/cpan/Test-Harness/t/lib/MyPerlSource.pm
new file mode 100644
index 0000000000..6193db97df
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyPerlSource.pm
@@ -0,0 +1,27 @@
+# subclass for testing customizing & subclassing
+
+package MyPerlSource;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use TAP::Parser::Source::Perl;
+
+@ISA = qw( TAP::Parser::Source::Perl MyCustom );
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ return $self;
+}
+
+sub source {
+ my $self = shift;
+ return $self->SUPER::source(@_);
+}
+
+1;
+
diff --git a/cpan/Test-Harness/t/lib/MyResult.pm b/cpan/Test-Harness/t/lib/MyResult.pm
new file mode 100644
index 0000000000..ab4845dedf
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyResult.pm
@@ -0,0 +1,21 @@
+# subclass for testing customizing & subclassing
+
+package MyResult;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use TAP::Parser::Result;
+
+@ISA = qw( TAP::Parser::Result MyCustom );
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ return $self;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MyResultFactory.pm b/cpan/Test-Harness/t/lib/MyResultFactory.pm
new file mode 100644
index 0000000000..371bba632b
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MyResultFactory.pm
@@ -0,0 +1,23 @@
+# subclass for testing customizing & subclassing
+
+package MyResultFactory;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use MyResult;
+use TAP::Parser::ResultFactory;
+
+@ISA = qw( TAP::Parser::ResultFactory MyCustom );
+
+sub make_result {
+ my $class = shift;
+
+ # I know, this is not really being initialized, but
+ # for consistency's sake, deal with it :)
+ $main::INIT{$class}++;
+ return MyResult->new(@_);
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/MySource.pm b/cpan/Test-Harness/t/lib/MySource.pm
new file mode 100644
index 0000000000..5e41b829ae
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/MySource.pm
@@ -0,0 +1,34 @@
+# subclass for testing customizing & subclassing
+
+package MySource;
+
+use strict;
+use vars '@ISA';
+
+use MyCustom;
+use TAP::Parser::Source;
+
+@ISA = qw( TAP::Parser::Source MyCustom );
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ return $self;
+}
+
+sub source {
+ my $self = shift;
+ return $self->SUPER::source(@_);
+}
+
+sub get_stream {
+ my $self = shift;
+ my $stream = $self->SUPER::get_stream(@_);
+
+ # re-bless it:
+ bless $stream, 'MyIterator';
+}
+
+1;
diff --git a/cpan/Test-Harness/t/lib/NOP.pm b/cpan/Test-Harness/t/lib/NOP.pm
new file mode 100644
index 0000000000..6de1dbfbd5
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/NOP.pm
@@ -0,0 +1,7 @@
+package NOP;
+
+# Do nothing much
+
+sub new { bless {}, shift }
+
+1;
diff --git a/cpan/Test-Harness/t/lib/NoFork.pm b/cpan/Test-Harness/t/lib/NoFork.pm
new file mode 100644
index 0000000000..0225e9628d
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/NoFork.pm
@@ -0,0 +1,21 @@
+package NoFork;
+
+BEGIN {
+ *CORE::GLOBAL::fork = sub { die "you should not fork" };
+}
+use Config;
+tied(%Config)->{d_fork} = 0; # blatant lie
+
+=begin TEST
+
+Assuming not to much chdir:
+
+ PERL5OPT='-It/lib -MNoFork' perl -Ilib bin/prove -r t
+
+=end TEST
+
+=cut
+
+1;
+
+# vim:ts=4:sw=4:et:sta
diff --git a/cpan/Test-Harness/t/lib/TAP/Parser/SubclassTest.pm b/cpan/Test-Harness/t/lib/TAP/Parser/SubclassTest.pm
new file mode 100644
index 0000000000..84becee932
--- /dev/null
+++ b/cpan/Test-Harness/t/lib/TAP/Parser/SubclassTest.pm
@@ -0,0 +1,39 @@
+# subclass for testing subclassing
+
+package TAP::Parser::SubclassTest;
+
+use strict;
+use vars qw(@ISA);
+
+use TAP::Parser;
+
+use MyCustom;
+use MySource;
+use MyPerlSource;
+use MyGrammar;
+use MyIteratorFactory;
+use MyResultFactory;
+
+@ISA = qw( TAP::Parser MyCustom );
+
+sub _default_source_class {'MySource'}
+sub _default_perl_source_class {'MyPerlSource'}
+sub _default_grammar_class {'MyGrammar'}
+sub _default_iterator_factory_class {'MyIteratorFactory'}
+sub _default_result_factory_class {'MyResultFactory'}
+
+sub make_source { shift->SUPER::make_source(@_)->custom }
+sub make_perl_source { shift->SUPER::make_perl_source(@_)->custom }
+sub make_grammar { shift->SUPER::make_grammar(@_)->custom }
+sub make_iterator { shift->SUPER::make_iterator(@_)->custom }
+sub make_result { shift->SUPER::make_result(@_)->custom }
+
+sub _initialize {
+ my $self = shift;
+ $self->SUPER::_initialize(@_);
+ $main::INIT{ ref($self) }++;
+ $self->{initialized} = 1;
+ return $self;
+}
+
+1;
diff --git a/cpan/Test-Harness/t/multiplexer.t b/cpan/Test-Harness/t/multiplexer.t
new file mode 100644
index 0000000000..649d5d161f
--- /dev/null
+++ b/cpan/Test-Harness/t/multiplexer.t
@@ -0,0 +1,170 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More qw( no_plan );
+
+use File::Spec;
+use TAP::Parser;
+use TAP::Parser::Multiplexer;
+use TAP::Parser::Iterator::Process;
+
+my $fork_desc
+ = TAP::Parser::Iterator::Process->_use_open3
+ ? 'fork'
+ : 'nofork';
+
+my @schedule = (
+ { name => 'Single non-selectable source',
+
+ # Returns a list of parser, stash pairs. The stash contains the
+ # TAP that we expect from this parser.
+ sources => sub {
+ my @tap = (
+ '1..1',
+ 'ok 1 Just fine'
+ );
+
+ return [
+ TAP::Parser->new( { tap => join( "\n", @tap ) . "\n" } ),
+ \@tap,
+ ];
+ },
+ },
+ { name => 'Two non-selectable sources',
+ sources => sub {
+ my @tap = (
+ [ '1..1',
+ 'ok 1 Just fine'
+ ],
+ [ '1..2',
+ 'not ok 1 Oh dear',
+ 'ok 2 Better'
+ ]
+ );
+
+ return map {
+ [ TAP::Parser->new( { tap => join( "\n", @$_ ) . "\n" } ),
+ $_
+ ]
+ } @tap;
+ },
+ },
+ { name => 'Single selectable source',
+ sources => sub {
+ return [
+ TAP::Parser->new(
+ { source => File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'simple'
+ ),
+ }
+ ),
+ [ '1..5',
+ 'ok 1',
+ 'ok 2',
+ 'ok 3',
+ 'ok 4',
+ 'ok 5',
+ ]
+ ];
+ },
+ },
+ { name => 'Three selectable sources',
+ sources => sub {
+ return map {
+ [ TAP::Parser->new(
+ { source => File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'simple'
+ ),
+ }
+ ),
+ [ '1..5',
+ 'ok 1',
+ 'ok 2',
+ 'ok 3',
+ 'ok 4',
+ 'ok 5',
+ ]
+ ]
+ } 1 .. 3;
+ },
+ },
+ { name => 'Three selectable sources, two non-selectable sources',
+ sources => sub {
+ my @tap = (
+ [ '1..1',
+ 'ok 1 Just fine'
+ ],
+ [ '1..2',
+ 'not ok 1 Oh dear',
+ 'ok 2 Better'
+ ]
+ );
+
+ return (
+ map {
+ [ TAP::Parser->new(
+ { tap => join( "\n", @$_ ) . "\n" }
+ ),
+ $_
+ ]
+ } @tap
+ ),
+ ( map {
+ [ TAP::Parser->new(
+ { source => File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'simple'
+ ),
+ }
+ ),
+ [ '1..5',
+ 'ok 1',
+ 'ok 2',
+ 'ok 3',
+ 'ok 4',
+ 'ok 5',
+ ]
+ ]
+ } 1 .. 3
+ );
+ },
+ }
+);
+
+for my $test (@schedule) {
+ my $name = "$test->{name} ($fork_desc)";
+ my @sources = $test->{sources}->();
+ my $mux = TAP::Parser::Multiplexer->new;
+
+ my $count = @sources;
+ $mux->add(@$_) for @sources;
+
+ is $mux->parsers, $count, "$name: count OK";
+
+ while ( my ( $parser, $stash, $result ) = $mux->next ) {
+
+ # use Data::Dumper;
+ # diag Dumper( { stash => $stash, result => $result } );
+ if ( defined $result ) {
+ my $expect = ( shift @$stash ) || ' OOPS ';
+ my $got = $result->raw;
+ is $got, $expect, "$name: '$expect' OK";
+ }
+ else {
+ ok @$stash == 0, "$name: EOF OK";
+
+ # Make sure we only get one EOF per stream
+ push @$stash, ' expect no more ';
+ }
+ }
+ is $mux->parsers, 0, "$name: All used up";
+}
+
+1;
diff --git a/cpan/Test-Harness/t/nofork-mux.t b/cpan/Test-Harness/t/nofork-mux.t
new file mode 100644
index 0000000000..4f28bf8c1d
--- /dev/null
+++ b/cpan/Test-Harness/t/nofork-mux.t
@@ -0,0 +1,10 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ use lib 't/lib';
+}
+
+use strict;
+
+use NoFork;
+require( 't/multiplexer.t' );
diff --git a/cpan/Test-Harness/t/nofork.t b/cpan/Test-Harness/t/nofork.t
new file mode 100644
index 0000000000..1d8b340e1b
--- /dev/null
+++ b/cpan/Test-Harness/t/nofork.t
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+
+# check nofork logic on systems which *can* fork()
+# NOTE maybe a good candidate for xt/author or something.
+
+use lib 't/lib';
+
+use strict;
+
+use Config;
+use Test::More (
+ $Config{d_fork}
+ ? 'no_plan'
+ : ( 'skip_all' => 'your system already has no fork' )
+);
+use IO::c55Capture; # for util
+
+use TAP::Harness;
+
+sub backticks {
+ my (@args) = @_;
+
+ util::stdout_of( sub { system(@args) and die "error $?" } );
+}
+
+my @libs = map "-I$_", @INC;
+my @perl = ( $^X, @libs );
+my $mod = 'TAP::Parser::Iterator::Process';
+
+{ # just check the introspective method to start...
+ my $code = qq(print $mod->_use_open3 ? 1 : 2);
+ {
+ my $ans = backticks( @perl, '-MNoFork', "-M$mod", '-e', $code );
+ is( $ans, 2, 'says not to fork' );
+ }
+ {
+ local $ENV{PERL5OPT}; # punt: prevent propogating -MNoFork
+ my $ans = backticks( @perl, "-M$mod", '-e', $code );
+ is( $ans, 1, 'says to fork' );
+ }
+}
+
+{ # and make sure we can run a test
+ my $capture = IO::c55Capture->new_handle;
+ local *STDERR;
+ my $harness = TAP::Harness->new(
+ { verbosity => -2,
+ switches => [ @libs, "-MNoFork" ],
+ stdout => $capture,
+ }
+ );
+ $harness->runtests( 't/sample-tests/simple' );
+ my @output = tied($$capture)->dump;
+ is pop @output, "Result: PASS\n", 'status OK';
+ pop @output; # get rid of summary line
+ is( $output[-1], "All tests successful.\n", 'ran with no fork' );
+}
+
+# vim:ts=4:sw=4:et:sta
diff --git a/cpan/Test-Harness/t/object.t b/cpan/Test-Harness/t/object.t
new file mode 100644
index 0000000000..b1a4dd0b98
--- /dev/null
+++ b/cpan/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/cpan/Test-Harness/t/parse.t b/cpan/Test-Harness/t/parse.t
new file mode 100644
index 0000000000..f0def28c9a
--- /dev/null
+++ b/cpan/Test-Harness/t/parse.t
@@ -0,0 +1,1058 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use lib 't/lib';
+
+use Test::More tests => 294;
+use IO::c55Capture;
+
+use File::Spec;
+
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+
+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 $factory = TAP::Parser::IteratorFactory->new;
+
+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( { stream => $factory->make_iterator($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 stream at/,
+ '...and it failed as expected';
+
+ @die = ();
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $PARSER->new(
+ { stream => 'stream',
+ 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', 'stream', 'tap' or 'source'/,
+ '...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->_stream, 'TAP::Parser::Iterator::Array';
+
+ # 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 determine source for 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->_stream, '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 stream 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 stream
+ my $stream = TAP::Parser::Iterator::Dies->new;
+
+ # now replace the stream - we're forced to us an T::P intenal
+ # method for this
+ $parser->_stream($stream);
+
+ # build a new grammar
+ my $grammar = TAP::Parser::Grammar->new(
+ { stream => $stream,
+ 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 stream
+ my $stream = TAP::Parser::Iterator::Dies->new;
+
+ # now replace the stream - we're forced to us an T::P intenal
+ # method for this
+ $parser->_stream($stream);
+
+ # build a new grammar
+ my $grammar = TAP::Parser::Grammar->new(
+ { stream => $stream,
+ 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 }
+ )
+ );
+ }
+}
diff --git a/cpan/Test-Harness/t/parser-config.t b/cpan/Test-Harness/t/parser-config.t
new file mode 100644
index 0000000000..bd3625902d
--- /dev/null
+++ b/cpan/Test-Harness/t/parser-config.t
@@ -0,0 +1,39 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use vars qw(%INIT %CUSTOM);
+
+use Test::More tests => 11;
+use File::Spec::Functions qw( catfile updir );
+use TAP::Parser;
+
+use_ok('MySource');
+use_ok('MyPerlSource');
+use_ok('MyGrammar');
+use_ok('MyIteratorFactory');
+use_ok('MyResultFactory');
+
+my $source = catfile( 't', '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/cpan/Test-Harness/t/parser-subclass.t b/cpan/Test-Harness/t/parser-subclass.t
new file mode 100644
index 0000000000..303c28ca27
--- /dev/null
+++ b/cpan/Test-Harness/t/parser-subclass.t
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use vars qw(%INIT %CUSTOM);
+
+use Test::More tests => 24;
+use File::Spec::Functions qw( catfile updir );
+
+use_ok('TAP::Parser::SubclassTest');
+
+# TODO: foreach my $source ( ... )
+{ # perl source
+ %INIT = %CUSTOM = ();
+ my $source = catfile( 't', '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', '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/cpan/Test-Harness/t/perl5lib.t b/cpan/Test-Harness/t/perl5lib.t
new file mode 100644
index 0000000000..51113e156b
--- /dev/null
+++ b/cpan/Test-Harness/t/perl5lib.t
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -w
+
+# Test that PERL5LIB is propogated from the harness process to the test
+# process.
+
+use strict;
+use lib 't/lib';
+use Config;
+
+my $path_sep = $Config{path_sep};
+
+sub has_crazy_patch {
+ my $sentinel = 'blirpzoffle';
+ local $ENV{PERL5LIB} = $sentinel;
+ my $command = join ' ',
+ map {qq{"$_"}} ( $^X, '-e', 'print join q(:), @INC' );
+ my $path = `$command`;
+ my @got = ( $path =~ /($sentinel)/g );
+ return @got > 1;
+}
+
+use Test::More (
+ $^O eq 'VMS' ? ( skip_all => 'VMS' )
+ : has_crazy_patch() ? ( skip_all => 'Incompatible @INC patch' )
+ : ( tests => 1 )
+);
+
+use Test::Harness;
+use App::Prove;
+
+# Change PERL5LIB so we ensure it's preserved.
+$ENV{PERL5LIB} = join(
+ $path_sep, 'wibble',
+ ( $ENV{PERL_CORE} ? '../lib' : () ), $ENV{PERL5LIB} || ''
+);
+
+open TEST, ">perl5lib_check.t.tmp";
+print TEST <<"END";
+#!/usr/bin/perl
+use strict;
+use Test::More tests => 1;
+like \$ENV{PERL5LIB}, qr/(^|${path_sep})wibble${path_sep}/;
+END
+close TEST;
+
+END { 1 while unlink 'perl5lib_check.t.tmp'; }
+
+my $h = TAP::Harness->new( { lib => ['something'], verbosity => -3 } );
+ok( !$h->runtests('perl5lib_check.t.tmp')->has_errors );
+
+1;
diff --git a/cpan/Test-Harness/t/premature-bailout.t b/cpan/Test-Harness/t/premature-bailout.t
new file mode 100644
index 0000000000..9226a44064
--- /dev/null
+++ b/cpan/Test-Harness/t/premature-bailout.t
@@ -0,0 +1,125 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 14;
+
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+
+sub tap_to_lines {
+ my $string = shift;
+ my @lines = ( $string =~ /.*\n/g );
+ return \@lines;
+}
+
+my $tap = <<'END_TAP';
+1..4
+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
+Bail out! We ran out of foobar.
+not ok 5
+END_TAP
+
+my $factory = TAP::Parser::IteratorFactory->new;
+my $parser = TAP::Parser->new(
+ { stream => $factory->make_iterator( tap_to_lines($tap) ),
+ }
+);
+
+# results() is sane?
+
+# check the test plan
+my $result = $parser->next();
+
+# TEST
+ok $result->is_plan, 'We should have a plan';
+
+# a normal, passing test
+
+my $test = $parser->next();
+
+# TEST
+ok $test->is_test, '... and a test';
+
+# junk lines should be preserved
+
+my $unknown = $parser->next();
+
+# TEST
+ok $unknown->is_unknown, '... and an unknown line';
+
+# a failing test, which also happens to have a directive
+
+my $failed = $parser->next();
+
+# TEST
+ok $failed->is_test, '... and another test';
+
+# comments
+
+my $comment = $parser->next();
+
+# TEST
+ok $comment->is_comment, '... and a comment';
+
+# another normal, passing test
+
+$test = $parser->next();
+
+# TEST
+ok $test->is_test, '... and another test';
+
+# a failing test
+
+$failed = $parser->next();
+
+# TEST
+ok $failed->is_test, '... and yet another test';
+
+# ok 5 # skip we have no description
+# skipped test
+my $bailout = $parser->next();
+
+# TEST
+ok $bailout->is_bailout, 'And finally we should have a bailout';
+
+# TEST
+is $bailout->as_string, 'We ran out of foobar.',
+ '... and as_string() should return the explanation';
+
+# TEST
+is( $bailout->raw, 'Bail out! We ran out of foobar.',
+ '... and raw() should return the explanation'
+);
+
+# TEST
+is( $bailout->explanation, 'We ran out of foobar.',
+ '... and it should have the correct explanation'
+);
+
+my $more_tap = "1..1\nok 1 - input file opened\n";
+
+my $second_parser = TAP::Parser->new(
+ { stream => $factory->make_iterator( [ split( /\n/, $more_tap ) ] ),
+ }
+);
+
+$result = $second_parser->next();
+
+# TEST
+ok $result->is_plan(), "Result is not the leftover line";
+
+$result = $second_parser->next();
+
+# TEST
+ok $result->is_test(), "Result is a test";
+
+# TEST
+ok $result->is_ok(), "The event has passed";
+
diff --git a/cpan/Test-Harness/t/process.t b/cpan/Test-Harness/t/process.t
new file mode 100644
index 0000000000..5135d67f95
--- /dev/null
+++ b/cpan/Test-Harness/t/process.t
@@ -0,0 +1,53 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+my $hires;
+
+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 File::Spec;
+use TAP::Parser::Iterator::Process;
+
+my @expect = (
+ '1..5',
+ 'ok 1 00000',
+ 'ok 2',
+ 'not ok 3',
+ 'ok 4',
+ 'ok 5 00000',
+);
+
+my $source = File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'delayed'
+);
+
+for my $chunk_size ( 1, 4, 65536 ) {
+ for my $where ( 0 .. 8 ) {
+
+ my $proc = TAP::Parser::Iterator::Process->new(
+ { _chunk_size => $chunk_size,
+ command => [ $^X, $source, ( 1 << $where ) ]
+ }
+ );
+
+ my @got = ();
+ while ( defined( my $line = $proc->next_raw ) ) {
+ push @got, $line;
+ }
+
+ is_deeply \@got, \@expect,
+ "I/O ok with delay at position $where, chunk size $chunk_size";
+ }
+}
diff --git a/cpan/Test-Harness/t/prove.t b/cpan/Test-Harness/t/prove.t
new file mode 100644
index 0000000000..71730cdbf6
--- /dev/null
+++ b/cpan/Test-Harness/t/prove.t
@@ -0,0 +1,1525 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+
+use Test::More;
+use File::Spec;
+
+use App::Prove;
+
+package FakeProve;
+use vars qw( @ISA );
+
+@ISA = qw( App::Prove );
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new(@_);
+ $self->{_log} = [];
+ return $self;
+}
+
+sub _color_default {0}
+
+sub _runtests {
+ my $self = shift;
+ push @{ $self->{_log} }, [ '_runtests', @_ ];
+}
+
+sub get_log {
+ my $self = shift;
+ my @log = @{ $self->{_log} };
+ $self->{_log} = [];
+ return @log;
+}
+
+sub _shuffle {
+ my $self = shift;
+ s/^/xxx/ for @_;
+}
+
+package main;
+
+sub mabs {
+ my $ar = shift;
+ return [ map { File::Spec->rel2abs($_) } @$ar ];
+}
+
+{
+ my @import_log = ();
+ sub test_log_import { push @import_log, [@_] }
+
+ sub get_import_log {
+ my @log = @import_log;
+ @import_log = ();
+ return @log;
+ }
+
+ my @plugin_load_log = ();
+ sub test_log_plugin_load { push @plugin_load_log, [@_] }
+
+ sub get_plugin_load_log {
+ my @log = @plugin_load_log;
+ @plugin_load_log = ();
+ return @log;
+ }
+}
+
+my ( @ATTR, %DEFAULT_ASSERTION, @SCHEDULE );
+
+# see the "ACTUAL TEST" section at the bottom
+
+BEGIN { # START PLAN
+
+ # list of attributes
+ @ATTR = qw(
+ 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
+ %DEFAULT_ASSERTION = map { $_ => undef } @ATTR;
+
+ $DEFAULT_ASSERTION{includes} = $DEFAULT_ASSERTION{argv}
+ = sub { 'ARRAY' eq ref shift };
+
+ my @dummy_tests = map { File::Spec->catdir( 't', 'sample-tests', $_ ) }
+ qw(simple simple_yaml);
+ my $dummy_test = $dummy_tests[0];
+
+ ########################################################################
+ # declarations - this drives all of the subtests.
+ # The cheatsheet follows.
+ # required: name, expect
+ # optional:
+ # args - arguments to constructor
+ # switches - command-line switches
+ # runlog - expected results of internal calls to _runtests, must
+ # match FakeProve's _log attr
+ # run_error - depends on 'runlog' (if missing, asserts no error)
+ # extra - follow-up check to handle exceptional cleanup / verification
+ # class - The App::Prove subclass to test. Defaults to FakeProve
+ @SCHEDULE = (
+ { name => 'Create empty',
+ expect => {}
+ },
+ { name => 'Set all options via constructor',
+ args => {
+ archive => 1,
+ argv => [qw(one two three)],
+ blib => 2,
+ color => 3,
+ directives => 4,
+ exec => 5,
+ failures => 7,
+ formatter => 8,
+ harness => 9,
+ includes => [qw(four five six)],
+ lib => 10,
+ merge => 11,
+ parse => 13,
+ quiet => 14,
+ really_quiet => 15,
+ recurse => 16,
+ backwards => 17,
+ shuffle => 18,
+ taint_fail => 19,
+ taint_warn => 20,
+ verbose => 21,
+ warnings_fail => 22,
+ warnings_warn => 23,
+ },
+ expect => {
+ archive => 1,
+ argv => [qw(one two three)],
+ blib => 2,
+ color => 3,
+ directives => 4,
+ exec => 5,
+ failures => 7,
+ formatter => 8,
+ harness => 9,
+ includes => [qw(four five six)],
+ lib => 10,
+ merge => 11,
+ parse => 13,
+ quiet => 14,
+ really_quiet => 15,
+ recurse => 16,
+ backwards => 17,
+ shuffle => 18,
+ taint_fail => 19,
+ taint_warn => 20,
+ verbose => 21,
+ warnings_fail => 22,
+ warnings_warn => 23,
+ }
+ },
+ { name => 'Call with defaults',
+ args => { argv => [qw( one two three )] },
+ expect => {},
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ # Test all options individually
+
+ # { name => 'Just archive',
+ # args => {
+ # argv => [qw( one two three )],
+ # archive => 1,
+ # },
+ # expect => {
+ # archive => 1,
+ # },
+ # runlog => [
+ # [ { archive => 1,
+ # },
+ # 'TAP::Harness',
+ # 'one', 'two',
+ # 'three'
+ # ]
+ # ],
+ # },
+ { name => 'Just argv',
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ argv => [qw( one two three )],
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0, show_count => 1 },
+ 'TAP::Harness',
+ 'one', 'two',
+ 'three'
+ ]
+ ],
+ },
+ { name => 'Just blib',
+ args => {
+ argv => [qw( one two three )],
+ blib => 1,
+ },
+ expect => {
+ blib => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( [ 'blib/lib', 'blib/arch' ] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ { name => 'Just color',
+ args => {
+ argv => [qw( one two three )],
+ color => 1,
+ },
+ expect => {
+ color => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { color => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ { name => 'Just directives',
+ args => {
+ argv => [qw( one two three )],
+ directives => 1,
+ },
+ expect => {
+ directives => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { directives => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just exec',
+ args => {
+ argv => [qw( one two three )],
+ exec => 1,
+ },
+ expect => {
+ exec => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { exec => [1],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just failures',
+ args => {
+ argv => [qw( one two three )],
+ failures => 1,
+ },
+ expect => {
+ failures => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { failures => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ { name => 'Just formatter',
+ args => {
+ argv => [qw( one two three )],
+ formatter => 'TAP::Harness',
+ },
+ expect => {
+ formatter => 'TAP::Harness',
+ },
+ runlog => [
+ [ '_runtests',
+ { formatter_class => 'TAP::Harness',
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ { name => 'Just includes',
+ args => {
+ argv => [qw( one two three )],
+ includes => [qw( four five six )],
+ },
+ expect => {
+ includes => [qw( four five six )],
+ },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( [qw( four five six )] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just lib',
+ args => {
+ argv => [qw( one two three )],
+ lib => 1,
+ },
+ expect => {
+ lib => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( ['lib'] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just merge',
+ args => {
+ argv => [qw( one two three )],
+ merge => 1,
+ },
+ expect => {
+ merge => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { merge => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just parse',
+ args => {
+ argv => [qw( one two three )],
+ parse => 1,
+ },
+ expect => {
+ parse => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { errors => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just quiet',
+ args => {
+ argv => [qw( one two three )],
+ quiet => 1,
+ },
+ expect => {
+ quiet => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just really_quiet',
+ args => {
+ argv => [qw( one two three )],
+ really_quiet => 1,
+ },
+ expect => {
+ really_quiet => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -2,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just recurse',
+ args => {
+ argv => [qw( one two three )],
+ recurse => 1,
+ },
+ expect => {
+ recurse => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just reverse',
+ args => {
+ argv => [qw( one two three )],
+ backwards => 1,
+ },
+ expect => {
+ backwards => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'three', 'two', 'one'
+ ]
+ ],
+ },
+
+ { name => 'Just shuffle',
+ args => {
+ argv => [qw( one two three )],
+ shuffle => 1,
+ },
+ expect => {
+ shuffle => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'xxxone', 'xxxtwo',
+ 'xxxthree'
+ ]
+ ],
+ },
+ { name => 'Just taint_fail',
+ args => {
+ argv => [qw( one two three )],
+ taint_fail => 1,
+ },
+ expect => {
+ taint_fail => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { switches => ['-T'],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just taint_warn',
+ args => {
+ argv => [qw( one two three )],
+ taint_warn => 1,
+ },
+ expect => {
+ taint_warn => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { switches => ['-t'],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just verbose',
+ args => {
+ argv => [qw( one two three )],
+ verbose => 1,
+ },
+ expect => {
+ verbose => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just warnings_fail',
+ args => {
+ argv => [qw( one two three )],
+ warnings_fail => 1,
+ },
+ expect => {
+ warnings_fail => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { switches => ['-W'],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+ { name => 'Just warnings_warn',
+ args => {
+ argv => [qw( one two three )],
+ warnings_warn => 1,
+ },
+ expect => {
+ warnings_warn => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { switches => ['-w'],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ 'one', 'two', 'three'
+ ]
+ ],
+ },
+
+ # Command line parsing
+ { name => 'Switch -v',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-v', $dummy_test ],
+ expect => {
+ verbose => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --verbose',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--verbose', $dummy_test ],
+ expect => {
+ verbose => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -f',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-f', $dummy_test ],
+ expect => { failures => 1 },
+ runlog => [
+ [ '_runtests',
+ { failures => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --failures',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--failures', $dummy_test ],
+ expect => { failures => 1 },
+ runlog => [
+ [ '_runtests',
+ { failures => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -l',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-l', $dummy_test ],
+ expect => { lib => 1 },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( ['lib'] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --lib',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--lib', $dummy_test ],
+ expect => { lib => 1 },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( ['lib'] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -b',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-b', $dummy_test ],
+ expect => { blib => 1 },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( [ 'blib/lib', 'blib/arch' ] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --blib',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--blib', $dummy_test ],
+ expect => { blib => 1 },
+ runlog => [
+ [ '_runtests',
+ { lib => mabs( [ 'blib/lib', 'blib/arch' ] ),
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -s',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-s', $dummy_test ],
+ expect => { shuffle => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ "xxx$dummy_test"
+ ]
+ ],
+ },
+
+ { name => 'Switch --shuffle',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--shuffle', $dummy_test ],
+ expect => { shuffle => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ "xxx$dummy_test"
+ ]
+ ],
+ },
+
+ { name => 'Switch -c',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-c', $dummy_test ],
+ expect => { color => 1 },
+ runlog => [
+ [ '_runtests',
+ { color => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -r',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-r', $dummy_test ],
+ expect => { recurse => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --recurse',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--recurse', $dummy_test ],
+ expect => { recurse => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --reverse',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--reverse', @dummy_tests ],
+ expect => { backwards => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ reverse @dummy_tests
+ ]
+ ],
+ },
+
+ { name => 'Switch -p',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-p', $dummy_test ],
+ expect => {
+ parse => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { errors => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --parse',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--parse', $dummy_test ],
+ expect => {
+ parse => 1,
+ },
+ runlog => [
+ [ '_runtests',
+ { errors => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -q',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-q', $dummy_test ],
+ expect => { quiet => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --quiet',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--quiet', $dummy_test ],
+ expect => { quiet => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -1,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -Q',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-Q', $dummy_test ],
+ expect => { really_quiet => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -2,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --QUIET',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--QUIET', $dummy_test ],
+ expect => { really_quiet => 1 },
+ runlog => [
+ [ '_runtests',
+ { verbosity => -2,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch -m',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-m', $dummy_test ],
+ expect => { merge => 1 },
+ runlog => [
+ [ '_runtests',
+ { merge => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --merge',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--merge', $dummy_test ],
+ expect => { merge => 1 },
+ runlog => [
+ [ '_runtests',
+ { merge => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Switch --directives',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--directives', $dummy_test ],
+ expect => { directives => 1 },
+ runlog => [
+ [ '_runtests',
+ { directives => 1,
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # .proverc
+ { name => 'Empty exec in .proverc',
+ args => {
+ argv => [qw( one two three )],
+ },
+ proverc => 't/proverc/emptyexec',
+ switches => [$dummy_test],
+ expect => { exec => '' },
+ runlog => [
+ [ '_runtests',
+ { exec => [],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # Executing one word (why would it be a -s though?)
+ { name => 'Switch --exec -s',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--exec', '-s', $dummy_test ],
+ expect => { exec => '-s' },
+ runlog => [
+ [ '_runtests',
+ { exec => ['-s'],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # multi-part exec
+ { name => 'Switch --exec "/foo/bar/perl -Ilib"',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '--exec', '/foo/bar/perl -Ilib', $dummy_test ],
+ expect => { exec => '/foo/bar/perl -Ilib' },
+ runlog => [
+ [ '_runtests',
+ { exec => [qw(/foo/bar/perl -Ilib)],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # null exec (run tests as compiled binaries)
+ { name => 'Switch --exec ""',
+ switches => [ '--exec', '', $dummy_test ],
+ expect => {
+ exec => # ick, must workaround the || default bit with a sub
+ sub { my $val = shift; defined($val) and !length($val) }
+ },
+ runlog => [
+ [ '_runtests',
+ { exec => [],
+ verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # Plugins
+ { name => 'Load plugin',
+ switches => [ '-P', 'Dummy', $dummy_test ],
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ plugins => ['Dummy'],
+ },
+ extra => sub {
+ my @loaded = get_import_log();
+ is_deeply \@loaded, [ ['App::Prove::Plugin::Dummy'] ],
+ "Plugin loaded OK";
+ },
+ plan => 1,
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Load plugin (args)',
+ switches => [ '-P', 'Dummy=cracking,cheese,gromit', $dummy_test ],
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ plugins => ['Dummy'],
+ },
+ extra => sub {
+ my @loaded = get_import_log();
+ is_deeply \@loaded,
+ [ [ 'App::Prove::Plugin::Dummy', 'cracking', 'cheese',
+ 'gromit'
+ ]
+ ],
+ "Plugin loaded OK";
+ },
+ plan => 1,
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Load plugin (explicit path)',
+ switches => [ '-P', 'App::Prove::Plugin::Dummy', $dummy_test ],
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ plugins => ['Dummy'],
+ },
+ extra => sub {
+ my @loaded = get_import_log();
+ is_deeply \@loaded, [ ['App::Prove::Plugin::Dummy'] ],
+ "Plugin loaded OK";
+ },
+ plan => 1,
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Load plugin (args + call load method)',
+ switches => [ '-P', 'Dummy2=fou,du,fafa', $dummy_test ],
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ plugins => ['Dummy2'],
+ },
+ extra => sub {
+ my @import = get_import_log();
+ is_deeply \@import,
+ [ [ 'App::Prove::Plugin::Dummy2', 'fou', 'du', 'fafa' ] ],
+ "Plugin loaded OK";
+
+ my @loaded = get_plugin_load_log();
+ is( scalar @loaded, 1, 'Plugin->load called OK' );
+ my ( $plugin_class, $args ) = @{ shift @loaded };
+ is( $plugin_class, 'App::Prove::Plugin::Dummy2',
+ 'plugin_class passed'
+ );
+ isa_ok(
+ $args->{app_prove}, 'App::Prove',
+ 'app_prove object passed'
+ );
+ is_deeply(
+ $args->{args}, [qw( fou du fafa )],
+ 'expected args passed'
+ );
+ },
+ plan => 5,
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ { name => 'Load module',
+ switches => [ '-M', 'App::Prove::Plugin::Dummy', $dummy_test ],
+ args => {
+ argv => [qw( one two three )],
+ },
+ expect => {
+ plugins => ['Dummy'],
+ },
+ extra => sub {
+ my @loaded = get_import_log();
+ is_deeply \@loaded, [ ['App::Prove::Plugin::Dummy'] ],
+ "Plugin loaded OK";
+ },
+ plan => 1,
+ runlog => [
+ [ '_runtests',
+ { verbosity => 0,
+ show_count => 1,
+ },
+ 'TAP::Harness',
+ $dummy_test
+ ]
+ ],
+ },
+
+ # TODO
+ # Hmm, that doesn't work...
+ # { name => 'Switch -h',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-h', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ '_runtests',
+ # {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+
+ # { name => 'Switch --help',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--help', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ # { name => 'Switch -?',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-?', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch -H',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-H', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --man',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--man', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch -V',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-V', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --version',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--version', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --color!',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--color!', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ { name => 'Switch -I=s@',
+ args => {
+ argv => [qw( one two three )],
+ },
+ switches => [ '-Ilib', $dummy_test ],
+ expect => {
+ includes => sub {
+ my ( $val, $attr ) = @_;
+ return
+ 'ARRAY' eq ref $val
+ && 1 == @$val
+ && $val->[0] =~ /lib$/;
+ },
+ },
+ },
+
+ # { name => 'Switch -a',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-a', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --archive=-s',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--archive=-s', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --formatter=-s',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--formatter=-s', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch -e',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '-e', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+ #
+ # { name => 'Switch --harness=-s',
+ # args => {
+ # argv => [qw( one two three )],
+ # },
+ # switches => [ '--harness=-s', $dummy_test ],
+ # expect => {},
+ # runlog => [
+ # [ {},
+ # 'TAP::Harness',
+ # $dummy_test
+ # ]
+ # ],
+ # },
+
+ );
+
+ # END SCHEDULE
+ ########################################################################
+
+ my $extra_plan = 0;
+ for my $test (@SCHEDULE) {
+ $extra_plan += $test->{plan} || 0;
+ $extra_plan += 2 if $test->{runlog};
+ $extra_plan += 1 if $test->{switches};
+ }
+
+ plan tests => @SCHEDULE * ( 3 + @ATTR ) + $extra_plan;
+} # END PLAN
+
+# ACTUAL TEST
+for my $test (@SCHEDULE) {
+ my $name = $test->{name};
+ my $class = $test->{class} || 'FakeProve';
+
+ local $ENV{HARNESS_TIMER};
+
+ ok my $app = $class->new( exists $test->{args} ? $test->{args} : () ),
+ "$name: App::Prove created OK";
+
+ isa_ok $app, 'App::Prove';
+ isa_ok $app, $class;
+
+ # Optionally parse command args
+ if ( my $switches = $test->{switches} ) {
+ if ( my $proverc = $test->{proverc} ) {
+ $app->add_rc_file( File::Spec->catfile( split /\//, $proverc ) );
+ }
+ eval { $app->process_args( '--norc', @$switches ) };
+ if ( my $err_pattern = $test->{parse_error} ) {
+ like $@, $err_pattern, "$name: expected parse error";
+ }
+ else {
+ ok !$@, "$name: no parse error";
+ }
+ }
+
+ my $expect = $test->{expect} || {};
+ for my $attr ( sort @ATTR ) {
+ my $val = $app->$attr();
+ my $assertion
+ = exists $expect->{$attr}
+ ? $expect->{$attr}
+ : $DEFAULT_ASSERTION{$attr};
+ my $is_ok = undef;
+
+ if ( 'CODE' eq ref $assertion ) {
+ $is_ok = ok $assertion->( $val, $attr ),
+ "$name: $attr has the expected value";
+ }
+ elsif ( 'Regexp' eq ref $assertion ) {
+ $is_ok = like $val, $assertion, "$name: $attr matches $assertion";
+ }
+ else {
+ $is_ok = is_deeply $val, $assertion,
+ "$name: $attr has the expected value";
+ }
+
+ unless ($is_ok) {
+ diag "got $val for $attr";
+ }
+ }
+
+ if ( my $runlog = $test->{runlog} ) {
+ eval { $app->run };
+ if ( my $err_pattern = $test->{run_error} ) {
+ like $@, $err_pattern, "$name: expected error OK";
+ pass;
+ pass for 1 .. $test->{plan};
+ }
+ else {
+ unless ( ok !$@, "$name: no error OK" ) {
+ diag "$name: error: $@\n";
+ }
+
+ my $gotlog = [ $app->get_log ];
+
+ if ( my $extra = $test->{extra} ) {
+ $extra->($gotlog);
+ }
+
+ unless (
+ is_deeply $gotlog, $runlog,
+ "$name: run results match"
+ )
+ {
+ use Data::Dumper;
+ diag Dumper( { wanted => $runlog, got => $gotlog } );
+ }
+ }
+ }
+}
diff --git a/cpan/Test-Harness/t/proveenv.t b/cpan/Test-Harness/t/proveenv.t
new file mode 100644
index 0000000000..be9942a043
--- /dev/null
+++ b/cpan/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/cpan/Test-Harness/t/proverc.t b/cpan/Test-Harness/t/proverc.t
new file mode 100644
index 0000000000..37d6de803b
--- /dev/null
+++ b/cpan/Test-Harness/t/proverc.t
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+use Test::More tests => 1;
+use File::Spec;
+use App::Prove;
+
+my $prove = App::Prove->new;
+
+$prove->add_rc_file(
+ File::Spec->catfile(
+ 't', 'data',
+ 'proverc'
+ )
+);
+
+is_deeply $prove->{rc_opts},
+ [ '--should', 'be', '--split', 'correctly', 'Can', 'quote things',
+ 'using single or', 'double quotes', '--this', 'is', 'OK?'
+ ],
+ 'options parsed';
+
diff --git a/cpan/Test-Harness/t/proverc/emptyexec b/cpan/Test-Harness/t/proverc/emptyexec
new file mode 100644
index 0000000000..5381b8f015
--- /dev/null
+++ b/cpan/Test-Harness/t/proverc/emptyexec
@@ -0,0 +1,2 @@
+--exec ''
+
diff --git a/cpan/Test-Harness/t/proverun.t b/cpan/Test-Harness/t/proverun.t
new file mode 100644
index 0000000000..6e6c2f33f5
--- /dev/null
+++ b/cpan/Test-Harness/t/proverun.t
@@ -0,0 +1,176 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use Test::More;
+use File::Spec;
+use App::Prove;
+
+my @SCHEDULE;
+
+BEGIN {
+
+ # to add a new test to proverun, just list the name of the file in
+ # t/sample-tests and a name for the test. The rest is handled
+ # automatically.
+ my @tests = (
+ { file => 'simple',
+ name => 'Create empty',
+ },
+ { file => 'todo_inline',
+ name => 'Passing TODO',
+ },
+ );
+ foreach my $test (@tests) {
+
+ # let's fully expand that filename
+ $test->{file} = File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ $test->{file}
+ );
+ }
+ @SCHEDULE = (
+ map {
+ { name => $_->{name},
+ args => [ $_->{file} ],
+ expect => [
+ [ 'new',
+ 'TAP::Parser::Iterator::Process',
+ { merge => undef,
+ command => [
+ 'PERL',
+ $_->{file},
+ ],
+ setup => \'CODE',
+ teardown => \'CODE',
+
+ }
+ ]
+ ]
+ }
+ } @tests
+ );
+
+ plan tests => @SCHEDULE * 3;
+}
+
+# Waaaaay too much boilerplate
+
+package FakeProve;
+use vars qw( @ISA );
+
+@ISA = qw( App::Prove );
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new(@_);
+ $self->{_log} = [];
+ return $self;
+}
+
+sub get_log {
+ my $self = shift;
+ my @log = @{ $self->{_log} };
+ $self->{_log} = [];
+ return @log;
+}
+
+package main;
+
+{
+ use TAP::Parser::Iterator::Process;
+ use TAP::Formatter::Console;
+
+ # Patch TAP::Parser::Iterator::Process
+ my @call_log = ();
+
+ local $^W; # no warnings
+
+ 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;
+ *TAP::Formatter::Console::_output = sub {
+
+ # push @call_log, [ '_output', @_ ];
+ };
+
+ sub get_log {
+ my @log = @call_log;
+ @call_log = ();
+ return @log;
+ }
+}
+
+sub _slacken {
+ my $obj = shift;
+ if ( my $ref = ref $obj ) {
+ if ( 'HASH' eq ref $obj ) {
+ return { map { $_ => _slacken( $obj->{$_} ) } keys %$obj };
+ }
+ elsif ( 'ARRAY' eq ref $obj ) {
+ return [ map { _slacken($_) } @$obj ];
+ }
+ elsif ( 'SCALAR' eq ref $obj ) {
+ return $obj;
+ }
+ else {
+ return \$ref;
+ }
+ }
+ else {
+ return $obj;
+ }
+}
+
+sub is_slackly($$$) {
+ my ( $got, $want, $msg ) = @_;
+ return is_deeply _slacken($got), _slacken($want), $msg;
+}
+
+# ACTUAL TEST
+for my $test (@SCHEDULE) {
+ my $name = $test->{name};
+
+ my $app = FakeProve->new;
+ $app->process_args( '--norc', @{ $test->{args} } );
+
+ # Why does this make the output from the test spew out of
+ # our STDOUT?
+ ok eval { $app->run }, 'run returned true';
+ ok !$@, 'no errors' or diag $@;
+
+ my @log = get_log();
+
+ # Bodge: we don't know what pathname will be used for the exe so we
+ # obliterate it here. Need to test that it's sane.
+ for my $call (@log) {
+ if ( 'HASH' eq ref $call->[2] && exists $call->[2]->{command} ) {
+ $call->[2]->{command}->[0] = 'PERL';
+ }
+ }
+
+ is_slackly \@log, $test->{expect}, "$name: command args OK";
+
+ # use Data::Dumper;
+ # diag Dumper(
+ # { got => \@log,
+ # expect => $test->{expect}
+ # }
+ # );
+}
+
diff --git a/cpan/Test-Harness/t/regression.t b/cpan/Test-Harness/t/regression.t
new file mode 100644
index 0000000000..20879ca2b6
--- /dev/null
+++ b/cpan/Test-Harness/t/regression.t
@@ -0,0 +1,3264 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ push @INC, 't/lib';
+}
+
+use strict;
+
+use Test::More 'no_plan';
+
+use File::Spec;
+use Config;
+
+use constant TRUE => "__TRUE__";
+use constant FALSE => "__FALSE__";
+
+# if wait() is non-zero, we cannot reliably predict its value
+use constant NOT_ZERO => "__NOT_ZERO__";
+
+use TAP::Parser;
+
+my $IsVMS = $^O eq 'VMS';
+my $IsWin32 = $^O eq 'MSWin32';
+
+my $SAMPLE_TESTS = File::Spec->catdir(
+ File::Spec->curdir,
+ 't',
+ 'sample-tests'
+);
+
+my %deprecated = map { $_ => 1 } qw(
+ TAP::Parser::good_plan
+ TAP::Parser::Result::Plan::passed
+ TAP::Parser::Result::Test::passed
+ TAP::Parser::Result::Test::actual_passed
+ TAP::Parser::Result::passed
+);
+$SIG{__WARN__} = sub {
+ if ( $_[0] =~ /is deprecated/ ) {
+ my @caller = caller(1);
+ my $sub = $caller[3];
+ ok exists $deprecated{$sub},
+ "... we should get a deprecated warning for $sub";
+ }
+ else {
+ CORE::warn @_;
+ }
+};
+
+# the %samples keys are the names of test scripts in t/sample-tests
+my %samples = (
+ descriptive => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "Interlock activated",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "Megathrusters are go",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "Head formed",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "Blazing sword formed",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "Robeast destroyed",
+ is_unplanned => FALSE,
+ }
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ descriptive_trailing => {
+ results => [
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "Interlock activated",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "Megathrusters are go",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "Head formed",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "Blazing sword formed",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "Robeast destroyed",
+ is_unplanned => FALSE,
+ },
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ empty => {
+ results => [],
+ plan => '',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ is_good_plan => FALSE,
+ tests_planned => undef,
+ tests_run => 0,
+ parse_errors => ['No plan found in TAP output'],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ simple => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ space_after_plan => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5 ',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ simple_yaml => {
+ results => [
+ { is_version => TRUE,
+ raw => 'TAP version 13',
+ },
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { is_yaml => TRUE,
+ data => [
+ { 'fnurk' => 'skib', 'ponk' => 'gleeb' },
+ { 'bar' => 'krup', 'foo' => 'plink' }
+ ],
+ raw =>
+ " ---\n -\n fnurk: skib\n ponk: gleeb\n -\n bar: krup\n foo: plink\n ...",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { is_yaml => TRUE,
+ data => {
+ 'got' => [ '1', 'pong', '4' ],
+ 'expected' => [ '1', '2', '4' ]
+ },
+ raw =>
+ " ---\n expected:\n - 1\n - 2\n - 4\n got:\n - 1\n - pong\n - 4\n ...",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 13,
+ },
+ simple_fail => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1, 3, 4 ],
+ actual_passed => [ 1, 3, 4 ],
+ failed => [ 2, 5 ],
+ actual_failed => [ 2, 5 ],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ skip => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => TRUE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ explanation => 'rain delay',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [2],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ skip_nomsg => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..1',
+ tests_planned => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => TRUE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ explanation => '',
+ },
+ ],
+ plan => '1..1',
+ passed => [1],
+ actual_passed => [1],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [1],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 1,
+ tests_run => TRUE,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ todo_inline => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..3',
+ tests_planned => 3,
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 1,
+ description => "- Foo",
+ explanation => 'Just testing the todo interface.',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 2,
+ description => "- Unexpected success",
+ explanation => 'Just testing the todo interface.',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "- This is not todo",
+ explanation => '',
+ },
+ ],
+ plan => '1..3',
+ passed => [ 1, 2, 3 ],
+ actual_passed => [ 2, 3 ],
+ failed => [],
+ actual_failed => [1],
+ todo => [ 1, 2 ],
+ todo_passed => [2],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 3,
+ tests_run => 3,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ todo => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..5 todo 3 2;',
+ tests_planned => 5,
+ todo_list => [ 3, 2 ],
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 2,
+ description => "",
+ explanation => '',
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 3,
+ description => "",
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ explanation => '',
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1, 2, 3, 4, 5 ],
+ actual_passed => [ 1, 2, 4, 5 ],
+ failed => [],
+ actual_failed => [3],
+ todo => [ 2, 3 ],
+ todo_passed => [2],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ duplicates => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..10',
+ tests_planned => 10,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 6,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 7,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 8,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 9,
+ description => '',
+ explanation => '',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 10,
+ description => '',
+ explanation => '',
+ is_unplanned => TRUE,
+ },
+ ],
+ plan => '1..10',
+ passed => [ 1 .. 4, 4 .. 9 ],
+ actual_passed => [ 1 .. 4, 4 .. 10 ],
+ failed => [10],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => 10,
+ tests_run => 11,
+ parse_errors => [
+ 'Tests out of sequence. Found (4) but expected (5)',
+ 'Tests out of sequence. Found (5) but expected (6)',
+ 'Tests out of sequence. Found (6) but expected (7)',
+ 'Tests out of sequence. Found (7) but expected (8)',
+ 'Tests out of sequence. Found (8) but expected (9)',
+ 'Tests out of sequence. Found (9) but expected (10)',
+ 'Tests out of sequence. Found (10) but expected (11)',
+ 'Bad plan. You planned 10 tests but ran 11.',
+ ],
+ 'exit' => 0,
+ wait => 0,
+ },
+ no_nums => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ }
+ ],
+ plan => '1..5',
+ passed => [ 1, 2, 4, 5 ],
+ actual_passed => [ 1, 2, 4, 5 ],
+ failed => [3],
+ actual_failed => [3],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ bailout => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { is_bailout => TRUE,
+ explanation => "GERONIMMMOOOOOO!!!",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ }
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ no_output => {
+ results => [],
+ plan => '',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => undef,
+ tests_run => 0,
+ parse_errors => [ 'No plan found in TAP output', ],
+ 'exit' => 0,
+ wait => 0,
+ },
+ too_many => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..3',
+ tests_planned => 3,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ is_unplanned => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ is_unplanned => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 6,
+ description => "",
+ is_unplanned => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 7,
+ description => "",
+ is_unplanned => TRUE,
+ },
+ ],
+ plan => '1..3',
+ passed => [ 1 .. 3 ],
+ actual_passed => [ 1 .. 7 ],
+ failed => [ 4 .. 7 ],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => 3,
+ tests_run => 7,
+ parse_errors => ['Bad plan. You planned 3 tests but ran 7.'],
+ 'exit' => 4,
+ wait => NOT_ZERO,
+ skip_if => sub {$IsVMS},
+ },
+ taint => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..1',
+ tests_planned => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "- -T honored",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ },
+ ],
+ plan => '1..1',
+ passed => [ 1 .. 1 ],
+ actual_passed => [ 1 .. 1 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => TRUE,
+ tests_run => TRUE,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ 'die' => {
+ results => [],
+ plan => '',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => undef,
+ tests_run => 0,
+ parse_errors => [ 'No plan found in TAP output', ],
+ 'exit' => NOT_ZERO,
+ wait => NOT_ZERO,
+ },
+ die_head_end => {
+ results => [
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ },
+ ],
+ plan => '',
+ passed => [ 1 .. 4 ],
+ actual_passed => [ 1 .. 4 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => undef,
+ tests_run => 4,
+ parse_errors => [ 'No plan found in TAP output', ],
+ 'exit' => NOT_ZERO,
+ wait => NOT_ZERO,
+ },
+ die_last_minute => {
+ results => [
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..4',
+ tests_planned => 4,
+ },
+ ],
+ plan => '1..4',
+ passed => [ 1 .. 4 ],
+ actual_passed => [ 1 .. 4 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 4,
+ tests_run => 4,
+ parse_errors => [],
+ 'exit' => NOT_ZERO,
+ wait => NOT_ZERO,
+ },
+ bignum => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..2',
+ tests_planned => 2,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 136211425,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 136211426,
+ description => '',
+ explanation => '',
+ },
+ ],
+ plan => '1..2',
+ passed => [ 1, 2 ],
+ actual_passed => [ 1, 2, 136211425, 136211426 ],
+ failed => [ 136211425, 136211426 ],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => 2,
+ tests_run => 4,
+ parse_errors => [
+ 'Tests out of sequence. Found (136211425) but expected (3)',
+ 'Tests out of sequence. Found (136211426) but expected (4)',
+ 'Bad plan. You planned 2 tests but ran 4.'
+ ],
+ 'exit' => 0,
+ wait => 0,
+ },
+ bignum_many => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..2',
+ tests_planned => 2,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 99997,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 99998,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 99999,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100000,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100001,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100002,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100003,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100004,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 100005,
+ description => '',
+ explanation => '',
+ },
+ ],
+ plan => '1..2',
+ passed => [ 1, 2 ],
+ actual_passed => [ 1, 2, 99997 .. 100005 ],
+ failed => [ 99997 .. 100005 ],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ tests_planned => 2,
+ tests_run => 11,
+ parse_errors => [
+ 'Tests out of sequence. Found (99997) but expected (3)',
+ 'Tests out of sequence. Found (99998) but expected (4)',
+ 'Tests out of sequence. Found (99999) but expected (5)',
+ 'Tests out of sequence. Found (100000) but expected (6)',
+ 'Tests out of sequence. Found (100001) but expected (7)',
+ 'Tests out of sequence. Found (100002) but expected (8)',
+ 'Tests out of sequence. Found (100003) but expected (9)',
+ 'Tests out of sequence. Found (100004) but expected (10)',
+ 'Tests out of sequence. Found (100005) but expected (11)',
+ 'Bad plan. You planned 2 tests but ran 11.'
+ ],
+ 'exit' => 0,
+ wait => 0,
+ },
+ combined => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..10',
+ tests_planned => 10,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => 'basset hounds got long ears',
+ explanation => '',
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => 'all hell broke loose',
+ explanation => '',
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 4,
+ description => '',
+ explanation => 'if I heard a voice from heaven ...',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => 'say "live without loving",',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 6,
+ description => "I'd beg off.",
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => '1',
+ has_todo => FALSE,
+ number => 7,
+ description => '',
+ explanation => 'contract negotiations',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 8,
+ description => 'Girls are such exquisite hell',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => TRUE,
+ number => 9,
+ description => 'Elegy 9B',
+ explanation => '',
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 10,
+ description => '',
+ explanation => '',
+ },
+ ],
+ plan => '1..10',
+ passed => [ 1 .. 2, 4 .. 9 ],
+ actual_passed => [ 1 .. 2, 5 .. 9 ],
+ failed => [ 3, 10 ],
+ actual_failed => [ 3, 4, 10 ],
+ todo => [ 4, 9 ],
+ todo_passed => [9],
+ skipped => [7],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 10,
+ tests_run => 10,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ head_end => {
+ results => [
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comments',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comment',
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..4',
+ tests_planned => 4,
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'more ignored stuff',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'and yet more',
+ },
+ ],
+ plan => '1..4',
+ passed => [ 1 .. 4 ],
+ actual_passed => [ 1 .. 4 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 4,
+ tests_run => 4,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ head_fail => {
+ results => [
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comments',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comment',
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..4',
+ tests_planned => 4,
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'more ignored stuff',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'and yet more',
+ },
+ ],
+ plan => '1..4',
+ passed => [ 1, 3, 4 ],
+ actual_passed => [ 1, 3, 4 ],
+ failed => [2],
+ actual_failed => [2],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 4,
+ tests_run => 4,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ out_of_order => {
+ results => [
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '- Test that argument passing works',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description =>
+ '- Test that passing arguments as references work',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '- Test a normal sub',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 6,
+ description => '- Detach test',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 8,
+ description => '- Nested thread test',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 9,
+ description => '- Nested thread test',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 10,
+ description => '- Wanted 7, got 7',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 11,
+ description => '- Wanted 7, got 7',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 12,
+ description => '- Wanted 8, got 8',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 13,
+ description => '- Wanted 8, got 8',
+ explanation => '',
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..15',
+ tests_planned => 15,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => '- Check that Config::threads is true',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 7,
+ description => '- Detach test',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 14,
+ description =>
+ '- Check so that tid for threads work for main thread',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 15,
+ description =>
+ '- Check so that tid for threads work for main thread',
+ explanation => '',
+ },
+ ],
+ plan => '1..15',
+ passed => [ 2 .. 4, 6, 8 .. 13, 1, 5, 7, 14, 15 ],
+ actual_passed => [ 2 .. 4, 6, 8 .. 13, 1, 5, 7, 14, 15 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ is_good_plan => FALSE,
+ tests_planned => 15,
+ tests_run => 15,
+
+ # Note that tests 14 and 15 *are* in the correct sequence.
+ parse_errors => [
+ 'Tests out of sequence. Found (2) but expected (1)',
+ 'Tests out of sequence. Found (3) but expected (2)',
+ 'Tests out of sequence. Found (4) but expected (3)',
+ 'Tests out of sequence. Found (6) but expected (4)',
+ 'Tests out of sequence. Found (8) but expected (5)',
+ 'Tests out of sequence. Found (9) but expected (6)',
+ 'Tests out of sequence. Found (10) but expected (7)',
+ 'Tests out of sequence. Found (11) but expected (8)',
+ 'Tests out of sequence. Found (12) but expected (9)',
+ 'Tests out of sequence. Found (13) but expected (10)',
+ 'Plan (1..15) must be at the beginning or end of the TAP output',
+ 'Tests out of sequence. Found (1) but expected (11)',
+ 'Tests out of sequence. Found (5) but expected (12)',
+ 'Tests out of sequence. Found (7) but expected (13)',
+ ],
+ 'exit' => 0,
+ wait => 0,
+ },
+ skipall => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..0 # skipping: rope',
+ tests_planned => 0,
+ passed => TRUE,
+ is_ok => TRUE,
+ directive => 'SKIP',
+ explanation => 'rope'
+ },
+ ],
+ plan => '1..0',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 0,
+ tests_run => 0,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ skip_all => 'rope',
+ },
+ skipall_v13 => {
+ results => [
+ { is_version => TRUE,
+ raw => 'TAP version 13',
+ },
+ { is_unknown => TRUE,
+ raw => '1..0 # skipping: rope',
+ },
+ ],
+ plan => '',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => FALSE,
+ is_good_plan => FALSE,
+ tests_planned => FALSE,
+ tests_run => 0,
+ parse_errors => ['No plan found in TAP output'],
+ 'exit' => 0,
+ wait => 0,
+ version => 13,
+ },
+ strict => {
+ results => [
+ { is_version => TRUE,
+ raw => 'TAP version 13',
+ },
+ { is_plan => TRUE,
+ raw => '1..1',
+ },
+ { is_pragma => TRUE,
+ raw => 'pragma +strict',
+ pragmas => ['+strict'],
+ },
+ { is_unknown => TRUE, raw => 'Nonsense!',
+ },
+ { is_pragma => TRUE,
+ raw => 'pragma -strict',
+ pragmas => ['-strict'],
+ },
+ { is_unknown => TRUE,
+ raw => "Doesn't matter.",
+ },
+ { is_test => TRUE,
+ raw => 'ok 1 All OK',
+ }
+ ],
+ plan => '1..1',
+ passed => [1],
+ actual_passed => [1],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 1,
+ tests_run => 1,
+ parse_errors => ['Unknown TAP token: "Nonsense!"'],
+ 'exit' => 0, # TODO: Is this right???
+ wait => 0,
+ version => 13,
+ },
+ skipall_nomsg => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..0',
+ tests_planned => 0,
+ passed => TRUE,
+ is_ok => TRUE,
+ directive => 'SKIP',
+ explanation => ''
+ },
+ ],
+ plan => '1..0',
+ passed => [],
+ actual_passed => [],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 0,
+ tests_run => 0,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ skip_all => '(no reason given)',
+ },
+ todo_misparse => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..1',
+ tests_planned => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => FALSE,
+ is_actual_ok => FALSE,
+ passed => FALSE,
+ is_ok => FALSE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => 'Hamlette # TODOORNOTTODO',
+ explanation => '',
+ },
+ ],
+ plan => '1..1',
+ passed => [],
+ actual_passed => [],
+ failed => [1],
+ actual_failed => [1],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => TRUE,
+ tests_run => 1,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ shbang_misparse => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..2',
+ tests_planned => 2,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => "",
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ ],
+ plan => '1..2',
+ passed => [ 1 .. 2 ],
+ actual_passed => [ 1 .. 2 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 2,
+ tests_run => 2,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ switches => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..1',
+ tests_planned => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ explanation => '',
+ },
+ ],
+ __ARGS__ => { switches => ['-Mstrict'] },
+ plan => '1..1',
+ passed => [1],
+ actual_passed => [1],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 1,
+ tests_run => TRUE,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ inc_taint => {
+ results => [
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..1',
+ tests_planned => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ explanation => '',
+ },
+ ],
+ __ARGS__ => { switches => ['-Iexamples'] },
+ plan => '1..1',
+ passed => [1],
+ actual_passed => [1],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 1,
+ tests_run => TRUE,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ sequence_misparse => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "\# skipped on foobar system",
+ },
+ { is_comment => TRUE,
+ comment => '1234567890123456789012345678901234567890',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { is_comment => TRUE,
+ comment => '1234567890123456789012345678901234567890',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+
+ # For some reason mixing stdout with stderr is unreliable on Windows
+ ( $IsWin32
+ ? ()
+ : ( stdout_stderr => {
+ results => [
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comments',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => '',
+ explanation => '',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => '',
+ explanation => '',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'comment',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => '',
+ explanation => '',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'more ignored stuff',
+ },
+ { is_comment => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ comment => 'and yet more',
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..4',
+ tests_planned => 4,
+ },
+ ],
+ plan => '1..4',
+ passed => [ 1 .. 4 ],
+ actual_passed => [ 1 .. 4 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 4,
+ tests_run => 4,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ need_open3 => 1,
+ }
+ )
+ ),
+
+ junk_before_plan => {
+ results => [
+ { is_unknown => TRUE,
+ raw => 'this is junk',
+ },
+ { is_comment => TRUE,
+ comment => "this is a comment",
+ },
+ { is_plan => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ raw => '1..1',
+ tests_planned => 1,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ },
+ ],
+ plan => '1..1',
+ passed => [ 1 .. 1 ],
+ actual_passed => [ 1 .. 1 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 1,
+ tests_run => 1,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ version_good => {
+ results => [
+ { is_version => TRUE,
+ raw => 'TAP version 13',
+ },
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 13,
+ },
+ version_old => {
+ results => [
+ { is_version => TRUE,
+ raw => 'TAP version 12',
+ },
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors =>
+ ['Explicit TAP version must be at least 13. Got version 12'],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+ version_late => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { is_version => TRUE,
+ raw => 'TAP version 13',
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 4,
+ description => "",
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ description => "",
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 5 ],
+ actual_passed => [ 1 .. 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors =>
+ ['If TAP version is present it must be the first line of output'],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+
+ escape_eol => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..2',
+ tests_planned => 2,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description =>
+ 'Should parse as literal backslash --> \\',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => 'Not a continuation line',
+ is_unplanned => FALSE,
+ },
+ ],
+ plan => '1..2',
+ passed => [ 1 .. 2 ],
+ actual_passed => [ 1 .. 2 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 2,
+ tests_run => 2,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+
+ escape_hash => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..3',
+ tests_planned => 3,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => 'Not a \\# TODO',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ description => 'Not a \\# SKIP',
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ description => 'Escaped \\\\\\#',
+ is_unplanned => FALSE,
+ },
+ ],
+ plan => '1..3',
+ passed => [ 1 .. 3 ],
+ actual_passed => [ 1 .. 3 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 3,
+ tests_run => 3,
+ parse_errors => [],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+
+ zero_valid => {
+ results => [
+ { is_plan => TRUE,
+ raw => '1..5',
+ tests_planned => 5,
+ passed => TRUE,
+ is_ok => TRUE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => '- One',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 1,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => '- Two',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 2,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => '- Three',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 3,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => '- Four',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 0,
+ is_unplanned => FALSE,
+ },
+ { actual_passed => TRUE,
+ is_actual_ok => TRUE,
+ description => '- Five',
+ passed => TRUE,
+ is_ok => TRUE,
+ is_test => TRUE,
+ has_skip => FALSE,
+ has_todo => FALSE,
+ number => 5,
+ is_unplanned => FALSE,
+ },
+ ],
+ plan => '1..5',
+ passed => [ 1 .. 3, 0, 5 ],
+ actual_passed => [ 1 .. 3, 0, 5 ],
+ failed => [],
+ actual_failed => [],
+ todo => [],
+ todo_passed => [],
+ skipped => [],
+ good_plan => TRUE,
+ is_good_plan => TRUE,
+ tests_planned => 5,
+ tests_run => 5,
+ parse_errors => [
+ 'Tests out of sequence. Found (0) but expected (4)',
+ ],
+ 'exit' => 0,
+ wait => 0,
+ version => 12,
+ },
+);
+
+my %HANDLER_FOR = (
+ NOT_ZERO, sub { local $^W; 0 != shift },
+ TRUE, sub { local $^W; !!shift },
+ FALSE, sub { local $^W; !shift },
+);
+
+my $can_open3 = ( $Config{d_fork} || $IsWin32 ) ? 1 : 0;
+
+for my $hide_fork ( 0 .. $can_open3 ) {
+ if ($hide_fork) {
+ no strict 'refs';
+ local $^W = 0;
+ *{'TAP::Parser::Iterator::Process::_use_open3'} = sub {return};
+ }
+
+ TEST:
+ for my $test ( sort keys %samples ) {
+
+ #next unless 'empty' eq $test;
+ my %details = %{ $samples{$test} };
+
+ if ( my $skip_if = delete $details{skip_if} ) {
+ next TEST if $skip_if->();
+ }
+
+ my $results = delete $details{results};
+ my $args = delete $details{__ARGS__};
+ my $need_open3 = delete $details{need_open3};
+
+ next TEST if $need_open3 && ( $hide_fork || !$can_open3 );
+
+ # the following acrobatics are necessary to make it easy for the
+ # Test::Builder::failure_output() method to be overridden when
+ # TAP::Parser is not installed. Otherwise, these tests will fail.
+
+ unshift @{ $args->{switches} },
+ $ENV{PERL_CORE} ? ( map {"-I$_"} @INC ) : ('-It/lib');
+
+ $args->{source} = File::Spec->catfile( $SAMPLE_TESTS, $test );
+ $args->{merge} = !$hide_fork;
+
+ my $parser = eval { analyze_test( $test, [@$results], $args ) };
+ my $error = $@;
+ ok !$error, "'$test' should parse successfully"
+ or diag $error;
+
+ if ($error) {
+ my $tests = 0;
+ while ( my ( $method, $answer ) = each %details ) {
+ $tests += ref $answer ? 2 : 1;
+ }
+ SKIP: {
+ skip "$test did not parse successfully", $tests;
+ }
+ }
+ else {
+ while ( my ( $method, $answer ) = each %details ) {
+ if ( my $handler = $HANDLER_FOR{ $answer || '' } ) { # yuck
+ ok $handler->( $parser->$method() ),
+ "... and $method should return a reasonable value ($test)";
+ }
+ elsif ( !ref $answer ) {
+ local $^W; # uninit warnings
+
+ $answer = _vmsify_answer( $method, $answer );
+
+ is $parser->$method(), $answer,
+ "... and $method should equal $answer ($test)";
+ }
+ else {
+ is scalar $parser->$method(), scalar @$answer,
+ "... and $method should be the correct amount ($test)";
+ is_deeply [ $parser->$method() ], $answer,
+ "... and $method should be the correct values ($test)";
+ }
+ }
+ }
+ }
+}
+
+my %Unix2VMS_Exit_Codes = ( 1 => 4, );
+
+sub _vmsify_answer {
+ my ( $method, $answer ) = @_;
+
+ return $answer unless $IsVMS;
+
+ if ( $method eq 'exit'
+ and exists $Unix2VMS_Exit_Codes{$answer} )
+ {
+ $answer = $Unix2VMS_Exit_Codes{$answer};
+ }
+
+ return $answer;
+}
+
+sub analyze_test {
+ my ( $test, $results, $args ) = @_;
+
+ my $parser = TAP::Parser->new($args);
+ my $count = 1;
+ while ( defined( my $result = $parser->next ) ) {
+
+ my $expected = shift @$results;
+ my $desc
+ = $result->is_test
+ ? $result->description
+ : $result->raw;
+ $desc = $result->plan
+ if $result->is_plan && $desc =~ /SKIP/i;
+ $desc =~ s/#/<hash>/g;
+ $desc =~ s/\s+/ /g; # Drop newlines
+ ok defined $expected,
+ "$test/$count We should have a result for $desc";
+ while ( my ( $method, $answer ) = each %$expected ) {
+
+ if ( my $handler = $HANDLER_FOR{ $answer || '' } ) { # yuck
+ ok $handler->( $result->$method() ),
+ "... and $method should return a reasonable value ($test/$count)";
+ }
+ elsif ( ref $answer ) {
+ is_deeply scalar( $result->$method() ), $answer,
+ "... and $method should return the correct structure ($test/$count)";
+ }
+ else {
+ is $result->$method(), $answer,
+ "... and $method should return the correct answer ($test/$count)";
+ }
+ }
+ $count++;
+ }
+ is @$results, 0,
+ "... and we should have the correct number of results ($test)";
+ return $parser;
+}
+
+# vms_nit
diff --git a/cpan/Test-Harness/t/results.t b/cpan/Test-Harness/t/results.t
new file mode 100644
index 0000000000..0522dd6299
--- /dev/null
+++ b/cpan/Test-Harness/t/results.t
@@ -0,0 +1,295 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 227;
+
+use TAP::Parser::ResultFactory;
+use TAP::Parser::Result;
+
+use constant RESULT => 'TAP::Parser::Result';
+use constant PLAN => 'TAP::Parser::Result::Plan';
+use constant TEST => 'TAP::Parser::Result::Test';
+use constant COMMENT => 'TAP::Parser::Result::Comment';
+use constant BAILOUT => 'TAP::Parser::Result::Bailout';
+use constant UNKNOWN => 'TAP::Parser::Result::Unknown';
+
+my $warning;
+$SIG{__WARN__} = sub { $warning = shift };
+
+#
+# Note that the are basic unit tests. More comprehensive path coverage is
+# found in the regression tests.
+#
+
+my $factory = TAP::Parser::ResultFactory->new;
+my %inherited_methods = (
+ is_plan => '',
+ is_test => '',
+ is_comment => '',
+ is_bailout => '',
+ is_unknown => '',
+ is_ok => 1,
+);
+
+my $abstract_class = bless { type => 'no_such_type' },
+ RESULT; # you didn't see this
+run_method_tests( $abstract_class, {} ); # check the defaults
+
+can_ok $abstract_class, 'type';
+is $abstract_class->type, 'no_such_type',
+ '... and &type should return the correct result';
+
+can_ok $abstract_class, 'passed';
+$warning = '';
+ok $abstract_class->passed, '... and it should default to true';
+like $warning, qr/^\Qpassed() is deprecated. Please use "is_ok()"/,
+ '... but it should emit a deprecation warning';
+
+can_ok RESULT, 'new';
+
+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
+#
+
+run_tests(
+ { class => UNKNOWN,
+ data => {
+ type => 'unknown',
+ raw => '... this line is junk ... ',
+ },
+ },
+ { is_unknown => 1,
+ raw => '... this line is junk ... ',
+ as_string => '... this line is junk ... ',
+ type => 'unknown',
+ has_directive => '',
+ }
+);
+
+#
+# test comment tokens
+#
+
+run_tests(
+ { class => COMMENT,
+ data => {
+ type => 'comment',
+ raw => '# this is a comment',
+ comment => 'this is a comment',
+ },
+ },
+ { is_comment => 1,
+ raw => '# this is a comment',
+ as_string => '# this is a comment',
+ comment => 'this is a comment',
+ type => 'comment',
+ has_directive => '',
+ }
+);
+
+#
+# test bailout tokens
+#
+
+run_tests(
+ { class => BAILOUT,
+ data => {
+ type => 'bailout',
+ raw => 'Bailout! This blows!',
+ bailout => 'This blows!',
+ },
+ },
+ { is_bailout => 1,
+ raw => 'Bailout! This blows!',
+ as_string => 'This blows!',
+ type => 'bailout',
+ has_directive => '',
+ }
+);
+
+#
+# test plan tokens
+#
+
+run_tests(
+ { class => PLAN,
+ data => {
+ type => 'plan',
+ raw => '1..20',
+ tests_planned => 20,
+ directive => '',
+ explanation => '',
+ },
+ },
+ { is_plan => 1,
+ raw => '1..20',
+ tests_planned => 20,
+ directive => '',
+ explanation => '',
+ has_directive => '',
+ }
+);
+
+run_tests(
+ { class => PLAN,
+ data => {
+ type => 'plan',
+ raw => '1..0 # SKIP help me, Rhonda!',
+ tests_planned => 0,
+ directive => 'SKIP',
+ explanation => 'help me, Rhonda!',
+ },
+ },
+ { is_plan => 1,
+ raw => '1..0 # SKIP help me, Rhonda!',
+ tests_planned => 0,
+ directive => 'SKIP',
+ explanation => 'help me, Rhonda!',
+ has_directive => 1,
+ }
+);
+
+#
+# test 'test' tokens
+#
+
+my $test = run_tests(
+ { class => TEST,
+ data => {
+ ok => 'ok',
+ test_num => 5,
+ description => '... and this test is fine',
+ directive => '',
+ explanation => '',
+ raw => 'ok 5 and this test is fine',
+ type => 'test',
+ },
+ },
+ { is_test => 1,
+ type => 'test',
+ ok => 'ok',
+ number => 5,
+ description => '... and this test is fine',
+ directive => '',
+ explanation => '',
+ is_ok => 1,
+ is_actual_ok => 1,
+ todo_passed => '',
+ has_skip => '',
+ has_todo => '',
+ as_string => 'ok 5 ... and this test is fine',
+ is_unplanned => '',
+ has_directive => '',
+ }
+);
+
+can_ok $test, 'actual_passed';
+$warning = '';
+is $test->actual_passed, $test->is_actual_ok,
+ '... and it should return the correct value';
+like $warning,
+ qr/^\Qactual_passed() is deprecated. Please use "is_actual_ok()"/,
+ '... but issue a deprecation warning';
+
+can_ok $test, 'todo_failed';
+$warning = '';
+is $test->todo_failed, $test->todo_passed,
+ '... and it should return the correct value';
+like $warning,
+ qr/^\Qtodo_failed() is deprecated. Please use "todo_passed()"/,
+ '... but issue a deprecation warning';
+
+# TODO directive
+
+$test = run_tests(
+ { class => TEST,
+ data => {
+ ok => 'not ok',
+ test_num => 5,
+ description => '... and this test is fine',
+ directive => 'TODO',
+ explanation => 'why not?',
+ raw => 'not ok 5 and this test is fine # TODO why not?',
+ type => 'test',
+ },
+ },
+ { is_test => 1,
+ type => 'test',
+ ok => 'not ok',
+ number => 5,
+ description => '... and this test is fine',
+ directive => 'TODO',
+ explanation => 'why not?',
+ is_ok => 1,
+ is_actual_ok => '',
+ todo_passed => '',
+ has_skip => '',
+ has_todo => 1,
+ as_string =>
+ 'not ok 5 ... and this test is fine # TODO why not?',
+ is_unplanned => '',
+ has_directive => 1,
+ }
+);
+
+sub run_tests {
+ my ( $instantiated, $value_for ) = @_;
+ my $result = instantiate($instantiated);
+ run_method_tests( $result, $value_for );
+ return $result;
+}
+
+sub instantiate {
+ my $instantiated = shift;
+ my $class = $instantiated->{class};
+ ok my $result = $factory->make_result( $instantiated->{data} ),
+ 'Creating $class results should succeed';
+ isa_ok $result, $class, '.. and the object it returns';
+ return $result;
+}
+
+sub run_method_tests {
+ my ( $result, $value_for ) = @_;
+ while ( my ( $method, $default ) = each %inherited_methods ) {
+ can_ok $result, $method;
+ if ( defined( my $value = delete $value_for->{$method} ) ) {
+ is $result->$method(), $value,
+ "... and $method should be correct";
+ }
+ else {
+ is $result->$method(), $default,
+ "... and $method default should be correct";
+ }
+ }
+ while ( my ( $method, $value ) = each %$value_for ) {
+ can_ok $result, $method;
+ is $result->$method(), $value, "... and $method should be correct";
+ }
+}
diff --git a/cpan/Test-Harness/t/sample-tests/bailout b/cpan/Test-Harness/t/sample-tests/bailout
new file mode 100644
index 0000000000..b25f417b52
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/bailout
@@ -0,0 +1,11 @@
+# Sleep makes Mac OS open3 race problem more repeatable
+sleep 1;
+print <<DUMMY_TEST;
+1..5
+ok 1
+ok 2
+ok 3
+Bail out! GERONIMMMOOOOOO!!!
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/bignum b/cpan/Test-Harness/t/sample-tests/bignum
new file mode 100644
index 0000000000..b5824a12a1
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/bignum
@@ -0,0 +1,7 @@
+print <<DUMMY;
+1..2
+ok 1
+ok 2
+ok 136211425
+ok 136211426
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/bignum_many b/cpan/Test-Harness/t/sample-tests/bignum_many
new file mode 100644
index 0000000000..1e30b2f1dd
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/bignum_many
@@ -0,0 +1,14 @@
+print <<DUMMY;
+1..2
+ok 1
+ok 2
+ok 99997
+ok 99998
+ok 99999
+ok 100000
+ok 100001
+ok 100002
+ok 100003
+ok 100004
+ok 100005
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/combined b/cpan/Test-Harness/t/sample-tests/combined
new file mode 100644
index 0000000000..7e157092b3
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/combined
@@ -0,0 +1,13 @@
+print <<DUMMY_TEST;
+1..10
+ok 1
+ok 2 basset hounds got long ears
+not ok 3 all hell broke loose
+not ok 4 # TODO if I heard a voice from heaven ...
+ok say "live without loving",
+ok 6 I'd beg off.
+ok 7 # Skip contract negotiations
+ok 8 Girls are such exquisite hell
+ok 9 Elegy 9B # TOdO
+not ok 10
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/combined_compat b/cpan/Test-Harness/t/sample-tests/combined_compat
new file mode 100644
index 0000000000..8dfaa28e92
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/combined_compat
@@ -0,0 +1,13 @@
+print <<DUMMY_TEST;
+1..10 todo 4 10
+ok 1
+ok 2 basset hounds got long ears
+not ok 3 all hell broke lose
+ok 4
+ok
+ok 6
+ok 7 # Skip contract negociations
+ok 8
+not ok 9
+not ok 10
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/delayed b/cpan/Test-Harness/t/sample-tests/delayed
new file mode 100644
index 0000000000..1f24ef6790
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/delayed
@@ -0,0 +1,26 @@
+# Used to test Process.pm
+use Time::HiRes qw(sleep);
+
+my $delay = 0.01;
+
+$| = 1;
+
+my @parts = (
+ "1.",
+ ".5\n",
+ "ok 1 00000\n",
+ "ok 2\nnot",
+ " ok 3",
+ "\nok 4\nok ",
+ "5 00000",
+ ""
+);
+
+my $delay_at = shift || 0;
+
+while (@parts) {
+ sleep $delay if ( $delay_at & 1 );
+ $delay_at >>= 1;
+ print shift @parts;
+}
+sleep $delay if ( $delay_at & 1 );
diff --git a/cpan/Test-Harness/t/sample-tests/descriptive b/cpan/Test-Harness/t/sample-tests/descriptive
new file mode 100644
index 0000000000..e165ac1bf5
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/descriptive
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5
+ok 1 Interlock activated
+ok 2 Megathrusters are go
+ok 3 Head formed
+ok 4 Blazing sword formed
+ok 5 Robeast destroyed
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/descriptive_trailing b/cpan/Test-Harness/t/sample-tests/descriptive_trailing
new file mode 100644
index 0000000000..f92d7ca694
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/descriptive_trailing
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+ok 1 Interlock activated
+ok 2 Megathrusters are go
+ok 3 Head formed
+ok 4 Blazing sword formed
+ok 5 Robeast destroyed
+1..5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/die b/cpan/Test-Harness/t/sample-tests/die
new file mode 100644
index 0000000000..ca8b0a9b0b
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/die
@@ -0,0 +1,2 @@
+eval "use vmsish 'hushed'" if ($^O eq 'VMS');
+exit 1; # exit because die() can be noisy
diff --git a/cpan/Test-Harness/t/sample-tests/die_head_end b/cpan/Test-Harness/t/sample-tests/die_head_end
new file mode 100644
index 0000000000..494e4d3c82
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/die_head_end
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+ok 1
+ok 2
+ok 3
+ok 4
+DUMMY_TEST
+
+eval "use vmsish 'hushed'" if ($^O eq 'VMS');
+exit 1;
diff --git a/cpan/Test-Harness/t/sample-tests/die_last_minute b/cpan/Test-Harness/t/sample-tests/die_last_minute
new file mode 100644
index 0000000000..ea533d628e
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/die_last_minute
@@ -0,0 +1,10 @@
+print <<DUMMY_TEST;
+ok 1
+ok 2
+ok 3
+ok 4
+1..4
+DUMMY_TEST
+
+eval "use vmsish 'hushed'" if ($^O eq 'VMS');
+exit 1;
diff --git a/cpan/Test-Harness/t/sample-tests/die_unfinished b/cpan/Test-Harness/t/sample-tests/die_unfinished
new file mode 100644
index 0000000000..3efd08ff09
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/die_unfinished
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+1..4
+ok 1
+ok 2
+ok 3
+DUMMY_TEST
+
+eval "use vmsish 'hushed'" if ($^O eq 'VMS');
+exit 1;
diff --git a/cpan/Test-Harness/t/sample-tests/duplicates b/cpan/Test-Harness/t/sample-tests/duplicates
new file mode 100644
index 0000000000..63f6a706b6
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/duplicates
@@ -0,0 +1,14 @@
+print <<DUMMY_TEST
+1..10
+ok 1
+ok 2
+ok 3
+ok 4
+ok 4
+ok 5
+ok 6
+ok 7
+ok 8
+ok 9
+ok 10
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/echo b/cpan/Test-Harness/t/sample-tests/echo
new file mode 100644
index 0000000000..6696e71f17
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/echo
@@ -0,0 +1,2 @@
+print '1..', scalar(@ARGV), "\n";
+print "ok $_ ", $ARGV[ $_ - 1 ], "\n" for 1 .. @ARGV;
diff --git a/cpan/Test-Harness/t/sample-tests/empty b/cpan/Test-Harness/t/sample-tests/empty
new file mode 100644
index 0000000000..66d42ad402
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/empty
@@ -0,0 +1,2 @@
+__END__
+Used to exercise the "empty test" case.
diff --git a/cpan/Test-Harness/t/sample-tests/escape_eol b/cpan/Test-Harness/t/sample-tests/escape_eol
new file mode 100644
index 0000000000..1b8ba27f1e
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/escape_eol
@@ -0,0 +1,5 @@
+print <<DUMMY_TEST;
+1..2
+ok 1 Should parse as literal backslash --> \\
+ok 2 Not a continuation line
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/escape_hash b/cpan/Test-Harness/t/sample-tests/escape_hash
new file mode 100644
index 0000000000..c404372c0c
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/escape_hash
@@ -0,0 +1,6 @@
+print <<DUMMY_TEST;
+1..3
+ok 1 Not a \\# TODO
+ok 2 Not a \\# SKIP
+ok 3 Escaped \\\\\\#
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/head_end b/cpan/Test-Harness/t/sample-tests/head_end
new file mode 100644
index 0000000000..14a32f2fe6
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/head_end
@@ -0,0 +1,11 @@
+print <<DUMMY_TEST;
+# comments
+ok 1
+ok 2
+ok 3
+ok 4
+# comment
+1..4
+# more ignored stuff
+# and yet more
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/head_fail b/cpan/Test-Harness/t/sample-tests/head_fail
new file mode 100644
index 0000000000..9d1667ab19
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/head_fail
@@ -0,0 +1,11 @@
+print <<DUMMY_TEST;
+# comments
+ok 1
+not ok 2
+ok 3
+ok 4
+# comment
+1..4
+# more ignored stuff
+# and yet more
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/inc_taint b/cpan/Test-Harness/t/sample-tests/inc_taint
new file mode 100644
index 0000000000..d1be66706c
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/inc_taint
@@ -0,0 +1,6 @@
+#!/usr/bin/perl -Tw
+
+use Test::More tests => 1;
+
+ok( grep( /examples/, @INC ) );
+
diff --git a/cpan/Test-Harness/t/sample-tests/junk_before_plan b/cpan/Test-Harness/t/sample-tests/junk_before_plan
new file mode 100644
index 0000000000..b2ad018301
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/junk_before_plan
@@ -0,0 +1,6 @@
+print <<DUMMY_TEST;
+this is junk
+# this is a comment
+1..1
+ok 1
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/lone_not_bug b/cpan/Test-Harness/t/sample-tests/lone_not_bug
new file mode 100644
index 0000000000..10eaa2a3b0
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/lone_not_bug
@@ -0,0 +1,9 @@
+# There was a bug where the first test would be considered a
+# 'lone not' failure.
+print <<DUMMY;
+ok 1
+ok 2
+ok 3
+ok 4
+1..4
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/no_nums b/cpan/Test-Harness/t/sample-tests/no_nums
new file mode 100644
index 0000000000..c32d3f22ba
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/no_nums
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5
+ok
+ok
+not ok
+ok
+ok
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/no_output b/cpan/Test-Harness/t/sample-tests/no_output
new file mode 100644
index 0000000000..505acda7e6
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/no_output
@@ -0,0 +1,3 @@
+#!/usr/bin/perl -w
+
+exit;
diff --git a/cpan/Test-Harness/t/sample-tests/out_err_mix b/cpan/Test-Harness/t/sample-tests/out_err_mix
new file mode 100644
index 0000000000..c802eb4a11
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/out_err_mix
@@ -0,0 +1,13 @@
+sub _autoflush {
+ my $flushed = shift;
+ my $old_fh = select $flushed;
+ $| = 1;
+ select $old_fh;
+}
+
+_autoflush( \*STDOUT );
+_autoflush( \*STDERR );
+
+print STDOUT "one\n";
+print STDERR "two\n\n";
+print STDOUT "three\n";
diff --git a/cpan/Test-Harness/t/sample-tests/out_of_order b/cpan/Test-Harness/t/sample-tests/out_of_order
new file mode 100644
index 0000000000..77641aa362
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/out_of_order
@@ -0,0 +1,22 @@
+# From a bungled core thread test.
+#
+# The important thing here is that the last test is the right test.
+# Test::Harness would misparse this as being a valid test.
+print <<DUMMY;
+ok 2 - Test that argument passing works
+ok 3 - Test that passing arguments as references work
+ok 4 - Test a normal sub
+ok 6 - Detach test
+ok 8 - Nested thread test
+ok 9 - Nested thread test
+ok 10 - Wanted 7, got 7
+ok 11 - Wanted 7, got 7
+ok 12 - Wanted 8, got 8
+ok 13 - Wanted 8, got 8
+1..15
+ok 1
+ok 5 - Check that Config::threads is true
+ok 7 - Detach test
+ok 14 - Check so that tid for threads work for main thread
+ok 15 - Check so that tid for threads work for main thread
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/schwern b/cpan/Test-Harness/t/sample-tests/schwern
new file mode 100644
index 0000000000..d45726bc7a
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/schwern
@@ -0,0 +1,3 @@
+use Test::More;
+plan tests => 1;
+ok 23, 42;
diff --git a/cpan/Test-Harness/t/sample-tests/schwern-todo-quiet b/cpan/Test-Harness/t/sample-tests/schwern-todo-quiet
new file mode 100644
index 0000000000..4d482d43fa
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/schwern-todo-quiet
@@ -0,0 +1,13 @@
+print <<DUMMY_TEST;
+1..3
+ok 1
+not ok 2
+# Failed test at ../../andy/schwern.pl line 17.
+# got: '23'
+# expected: '42'
+not ok 3 # TODO Roman numerials still not a built in type
+# Failed (TODO) test at ../../andy/schwern.pl line 20.
+# got: 'XXIII'
+# expected: '23'
+# Looks like you failed 1 test of 3.
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/segfault b/cpan/Test-Harness/t/sample-tests/segfault
new file mode 100644
index 0000000000..c5670a42b5
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/segfault
@@ -0,0 +1,5 @@
+#!/usr/bin/perl
+
+print "1..1\n";
+print "ok 1\n";
+kill 11, $$;
diff --git a/cpan/Test-Harness/t/sample-tests/sequence_misparse b/cpan/Test-Harness/t/sample-tests/sequence_misparse
new file mode 100644
index 0000000000..c66d127bb0
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/sequence_misparse
@@ -0,0 +1,14 @@
+#
+# This was causing parse failures due to an error in the TAP specification.
+# Hash marks *are* allowed in the description.
+#
+print <<DUMMY;
+1..5
+ok 1
+ok 2
+ok 3 # skipped on foobar system
+# 1234567890123456789012345678901234567890
+ok 4
+# 1234567890123456789012345678901234567890
+ok 5
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/shbang_misparse b/cpan/Test-Harness/t/sample-tests/shbang_misparse
new file mode 100644
index 0000000000..ab93b468ae
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/shbang_misparse
@@ -0,0 +1,12 @@
+#!/usr/bin/perl-latest
+
+# The above #! line was misparsed as having a -t.
+# Pre-5.8 this will simply cause perl to choke, since there was no -t.
+# Post-5.8 taint warnings will mistakenly be on.
+
+print "1..2\n";
+print "ok 1\n";
+my $warning = '';
+$SIG{__WARN__} = sub { $warning .= $_[0] };
+eval( "#" . substr( $0, 0, 0 ) );
+print $warning ? "not ok 2\n" : "ok 2\n";
diff --git a/cpan/Test-Harness/t/sample-tests/simple b/cpan/Test-Harness/t/sample-tests/simple
new file mode 100644
index 0000000000..d6b85846b2
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/simple
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/simple_fail b/cpan/Test-Harness/t/sample-tests/simple_fail
new file mode 100644
index 0000000000..aa65f5f66d
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/simple_fail
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5
+ok 1
+not ok 2
+ok 3
+ok 4
+not ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/simple_yaml b/cpan/Test-Harness/t/sample-tests/simple_yaml
new file mode 100644
index 0000000000..9f52c5c8a8
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/simple_yaml
@@ -0,0 +1,27 @@
+print <<DUMMY_TEST;
+TAP version 13
+1..5
+ok 1
+ok 2
+ ---
+ -
+ fnurk: skib
+ ponk: gleeb
+ -
+ bar: krup
+ foo: plink
+ ...
+ok 3
+ok 4
+ ---
+ expected:
+ - 1
+ - 2
+ - 4
+ got:
+ - 1
+ - pong
+ - 4
+ ...
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/skip b/cpan/Test-Harness/t/sample-tests/skip
new file mode 100644
index 0000000000..6a9cd662bc
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/skip
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5
+ok 1
+ok 2 # skip rain delay
+ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/skip_nomsg b/cpan/Test-Harness/t/sample-tests/skip_nomsg
new file mode 100644
index 0000000000..51d1ed6b43
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/skip_nomsg
@@ -0,0 +1,4 @@
+print <<DUMMY;
+1..1
+ok 1 # Skip
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/skipall b/cpan/Test-Harness/t/sample-tests/skipall
new file mode 100644
index 0000000000..ceb2c19b3a
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/skipall
@@ -0,0 +1,3 @@
+print <<DUMMY_TEST;
+1..0 # skipping: rope
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/skipall_nomsg b/cpan/Test-Harness/t/sample-tests/skipall_nomsg
new file mode 100644
index 0000000000..9b0dc11a69
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/skipall_nomsg
@@ -0,0 +1,2 @@
+print "1..0\n";
+exit 0;
diff --git a/cpan/Test-Harness/t/sample-tests/skipall_v13 b/cpan/Test-Harness/t/sample-tests/skipall_v13
new file mode 100644
index 0000000000..d16bd4f652
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/skipall_v13
@@ -0,0 +1,4 @@
+print <<DUMMY_TEST;
+TAP version 13
+1..0 # skipping: rope
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/space_after_plan b/cpan/Test-Harness/t/sample-tests/space_after_plan
new file mode 100644
index 0000000000..d454c20d4d
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/space_after_plan
@@ -0,0 +1,3 @@
+# gforth TAP generates a space after the plan. Should probably be allowed.
+print "1..5 \n";
+print "ok $_ \n" for 1..5;
diff --git a/cpan/Test-Harness/t/sample-tests/stdout_stderr b/cpan/Test-Harness/t/sample-tests/stdout_stderr
new file mode 100644
index 0000000000..ce17484d65
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/stdout_stderr
@@ -0,0 +1,9 @@
+use Test::More 'no_plan';
+diag 'comments';
+ok 1;
+ok 1;
+ok 1;
+diag 'comment';
+ok 1;
+diag 'more ignored stuff';
+diag 'and yet more';
diff --git a/cpan/Test-Harness/t/sample-tests/strict b/cpan/Test-Harness/t/sample-tests/strict
new file mode 100644
index 0000000000..b89138de40
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/strict
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+TAP version 13
+1..1
+pragma +strict
+Nonsense!
+pragma -strict
+Doesn't matter.
+ok 1 All OK
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/switches b/cpan/Test-Harness/t/sample-tests/switches
new file mode 100644
index 0000000000..8ce9c9a589
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/switches
@@ -0,0 +1,2 @@
+print "1..1\n";
+print $INC{'strict.pm'} ? "ok 1\n" : "not ok 1\n";
diff --git a/cpan/Test-Harness/t/sample-tests/taint b/cpan/Test-Harness/t/sample-tests/taint
new file mode 100644
index 0000000000..c36698e042
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/taint
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -Tw
+
+use lib qw(t/lib);
+use Test::More tests => 1;
+
+eval { `$^X -e1` };
+like( $@, '/^Insecure dependency/', '-T honored' );
diff --git a/cpan/Test-Harness/t/sample-tests/taint_warn b/cpan/Test-Harness/t/sample-tests/taint_warn
new file mode 100644
index 0000000000..398d6181ee
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/taint_warn
@@ -0,0 +1,11 @@
+#!/usr/bin/perl -tw
+
+use lib qw(t/lib);
+use Test::More tests => 1;
+
+my $warnings = '';
+{
+ local $SIG{__WARN__} = sub { $warnings .= join '', @_ };
+ `$^X -e1`;
+}
+like( $warnings, '/^Insecure dependency/', '-t honored' );
diff --git a/cpan/Test-Harness/t/sample-tests/todo b/cpan/Test-Harness/t/sample-tests/todo
new file mode 100644
index 0000000000..77f00b4dc9
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/todo
@@ -0,0 +1,8 @@
+print <<DUMMY_TEST;
+1..5 todo 3 2;
+ok 1
+ok 2
+not ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/todo_inline b/cpan/Test-Harness/t/sample-tests/todo_inline
new file mode 100644
index 0000000000..5b96d68caf
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/todo_inline
@@ -0,0 +1,6 @@
+print <<DUMMY_TEST;
+1..3
+not ok 1 - Foo # TODO Just testing the todo interface.
+ok 2 - Unexpected success # TODO Just testing the todo interface.
+ok 3 - This is not todo
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/todo_misparse b/cpan/Test-Harness/t/sample-tests/todo_misparse
new file mode 100644
index 0000000000..138f3fbaaa
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/todo_misparse
@@ -0,0 +1,5 @@
+print <<'END';
+1..1
+not ok 1 Hamlette # TODOORNOTTODO
+END
+
diff --git a/cpan/Test-Harness/t/sample-tests/too_many b/cpan/Test-Harness/t/sample-tests/too_many
new file mode 100644
index 0000000000..46acaded4d
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/too_many
@@ -0,0 +1,14 @@
+print <<DUMMY;
+1..3
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+ok 6
+ok 7
+DUMMY
+
+exit 4; # simulate Test::More's exit status
+
+
diff --git a/cpan/Test-Harness/t/sample-tests/version_good b/cpan/Test-Harness/t/sample-tests/version_good
new file mode 100644
index 0000000000..9e4ab908a2
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/version_good
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+TAP version 13
+1..5
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/version_late b/cpan/Test-Harness/t/sample-tests/version_late
new file mode 100644
index 0000000000..4537a322e3
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/version_late
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+1..5
+TAP version 13
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/version_old b/cpan/Test-Harness/t/sample-tests/version_old
new file mode 100644
index 0000000000..3c0c44ffb1
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/version_old
@@ -0,0 +1,9 @@
+print <<DUMMY_TEST;
+TAP version 12
+1..5
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/vms_nit b/cpan/Test-Harness/t/sample-tests/vms_nit
new file mode 100644
index 0000000000..1df7804309
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/vms_nit
@@ -0,0 +1,6 @@
+print <<DUMMY;
+1..2
+not
+ok 1
+ok 2
+DUMMY
diff --git a/cpan/Test-Harness/t/sample-tests/with_comments b/cpan/Test-Harness/t/sample-tests/with_comments
new file mode 100644
index 0000000000..7aa913985b
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/with_comments
@@ -0,0 +1,14 @@
+print <<DUMMY_TEST;
+# and stuff
+1..5 todo 1 2 4 5;
+# yeah, that
+not ok 1
+# Failed test 1 in t/todo.t at line 9 *TODO*
+ok 2 # (t/todo.t at line 10 TODO?!)
+ok 3
+not ok 4
+# Test 4 got: '0' (t/todo.t at line 12 *TODO*)
+# Expected: '1' (need more tuits)
+ok 5 # (t/todo.t at line 13 TODO?!)
+# woo
+DUMMY_TEST
diff --git a/cpan/Test-Harness/t/sample-tests/zero_valid b/cpan/Test-Harness/t/sample-tests/zero_valid
new file mode 100644
index 0000000000..dae91a18fb
--- /dev/null
+++ b/cpan/Test-Harness/t/sample-tests/zero_valid
@@ -0,0 +1,8 @@
+print <<DUMMY;
+1..5
+ok 1 - One
+ok 2 - Two
+ok - Three
+ok 0 - Four
+ok 5 - Five
+DUMMY
diff --git a/cpan/Test-Harness/t/scheduler.t b/cpan/Test-Harness/t/scheduler.t
new file mode 100644
index 0000000000..b2742078b1
--- /dev/null
+++ b/cpan/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/cpan/Test-Harness/t/source.t b/cpan/Test-Harness/t/source.t
new file mode 100644
index 0000000000..ce9063e57b
--- /dev/null
+++ b/cpan/Test-Harness/t/source.t
@@ -0,0 +1,93 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+
+use Test::More tests => 26;
+
+use File::Spec;
+
+use EmptyParser;
+use TAP::Parser::Source;
+use TAP::Parser::Source::Perl;
+
+my $parser = EmptyParser->new;
+my $test = File::Spec->catfile(
+ 't',
+ 'source_tests',
+ 'source'
+);
+
+my $perl = $^X;
+
+can_ok 'TAP::Parser::Source', 'new';
+my $source = TAP::Parser::Source->new;
+isa_ok $source, 'TAP::Parser::Source';
+
+can_ok $source, 'source';
+eval { $source->source("$perl -It/lib $test") };
+ok my $error = $@, '... and calling it with a string should fail';
+like $error, qr/^Argument to &source must be an array reference/,
+ '... with an appropriate error message';
+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($parser);
+
+isa_ok $stream, 'TAP::Parser::Iterator::Process',
+ 'get_stream returns the right object';
+can_ok $stream, 'next';
+is $stream->next, '1..1', '... and the first line should be correct';
+is $stream->next, 'ok 1', '... as should the second';
+ok !$stream->next, '... and we should have no more results';
+
+can_ok 'TAP::Parser::Source::Perl', 'new';
+$source = TAP::Parser::Source::Perl->new;
+isa_ok $source, 'TAP::Parser::Source::Perl', '... and the object it returns';
+
+can_ok $source, 'source';
+ok $source->source( [$test] ),
+ '... and calling it with valid args should succeed';
+
+can_ok $source, 'get_stream';
+$stream = $source->get_stream($parser);
+
+isa_ok $stream, 'TAP::Parser::Iterator::Process',
+ '... and the object it returns';
+can_ok $stream, 'next';
+is $stream->next, '1..1', '... and the first line should be correct';
+is $stream->next, 'ok 1', '... as should the second';
+ok !$stream->next, '... and we should have no more results';
+
+# internals tests!
+
+can_ok $source, '_switches';
+ok( grep( $_ =~ /^['"]?-T['"]?$/, $source->_switches ),
+ '... and it should find the taint switch'
+);
+
+# coverage test for TAP::PArser::Source
+
+{
+
+ # coverage for method get_steam
+
+ my $source = TAP::Parser::Source->new( { parser => $parser } );
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ $source->get_stream;
+ };
+
+ is @die, 1, 'coverage testing of get_stream';
+
+ like pop @die, qr/No command found!/, '...and it failed as expect';
+}
+
diff --git a/cpan/Test-Harness/t/source_tests/harness b/cpan/Test-Harness/t/source_tests/harness
new file mode 100644
index 0000000000..7fef7d5459
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/harness
@@ -0,0 +1,6 @@
+#!/usr/bin/perl
+
+print <<'END_TESTS';
+1..1
+ok 1 - this is a test
+END_TESTS
diff --git a/cpan/Test-Harness/t/source_tests/harness_badtap b/cpan/Test-Harness/t/source_tests/harness_badtap
new file mode 100644
index 0000000000..bf8233a5ca
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/harness_badtap
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+print <<'END_TESTS';
+1..2
+ok 1 - this is a test
+not ok 2 - this is another test
+1..2
+END_TESTS
diff --git a/cpan/Test-Harness/t/source_tests/harness_complain b/cpan/Test-Harness/t/source_tests/harness_complain
new file mode 100644
index 0000000000..1ef4cf0534
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/harness_complain
@@ -0,0 +1,7 @@
+#!/usr/bin/perl
+
+print "1..1\n";
+
+die "I should have no args -- @ARGV" if (@ARGV);
+print "ok 1 - this is a test\n";
+
diff --git a/cpan/Test-Harness/t/source_tests/harness_directives b/cpan/Test-Harness/t/source_tests/harness_directives
new file mode 100644
index 0000000000..91ada58bf3
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/harness_directives
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+print <<'END_TESTS';
+1..3
+ok 1 - this is a test
+not ok 2 - we have a something # TODO some output
+ok 3 houston, we don't have liftoff # SKIP no funding
+END_TESTS
diff --git a/cpan/Test-Harness/t/source_tests/harness_failure b/cpan/Test-Harness/t/source_tests/harness_failure
new file mode 100644
index 0000000000..a36e5c129b
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/harness_failure
@@ -0,0 +1,11 @@
+#!/usr/bin/perl
+
+print <<'END_TESTS';
+1..2
+ok 1 - this is a test
+not ok 2 - this is another test
+# Failed test 'this is another test'
+# in harness_failure.t at line 5.
+# got: 'waffle'
+# expected: 'yarblokos'
+END_TESTS
diff --git a/cpan/Test-Harness/t/source_tests/source b/cpan/Test-Harness/t/source_tests/source
new file mode 100644
index 0000000000..be28995e63
--- /dev/null
+++ b/cpan/Test-Harness/t/source_tests/source
@@ -0,0 +1,14 @@
+#!/usr/bin/perl -wT
+
+BEGIN {
+ if ( $ENV{PERL_CORE} ) {
+ @INC = ( '../../lib', 't/lib' );
+ }
+ else {
+ unshift @INC, 't/lib';
+ }
+}
+
+use Test::More tests => 1;
+
+ok 1;
diff --git a/cpan/Test-Harness/t/spool.t b/cpan/Test-Harness/t/spool.t
new file mode 100644
index 0000000000..d22ffcdd77
--- /dev/null
+++ b/cpan/Test-Harness/t/spool.t
@@ -0,0 +1,139 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+# test T::H::_open_spool and _close_spool - these are good examples
+# of the 'Fragile Test' pattern - messing with I/O primitives breaks
+# nearly everything
+
+use strict;
+use Test::More;
+
+my $useOrigOpen;
+my $useOrigClose;
+
+# setup replacements for core open and close - breaking these makes everything very fragile
+BEGIN {
+ $useOrigOpen = $useOrigClose = 1;
+
+ # taken from http://www.perl.com/pub/a/2002/06/11/threads.html?page=2
+
+ *CORE::GLOBAL::open = \&my_open;
+
+ sub my_open (*@) {
+ if ($useOrigOpen) {
+ if ( defined( $_[0] ) ) {
+ use Symbol qw();
+ my $handle = Symbol::qualify( $_[0], (caller)[0] );
+ no strict 'refs';
+ if ( @_ == 1 ) {
+ return CORE::open($handle);
+ }
+ elsif ( @_ == 2 ) {
+ return CORE::open( $handle, $_[1] );
+ }
+ else {
+ die "Can't open with more than two args";
+ }
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ *CORE::GLOBAL::close = sub (*) {
+ if ($useOrigClose) { return CORE::close(shift) }
+ else {return}
+ };
+
+}
+
+use TAP::Harness;
+use TAP::Parser;
+
+plan tests => 4;
+
+{
+
+ # coverage tests for the basically untested T::H::_open_spool
+
+ my @spool = ( 't', 'spool' );
+ $ENV{PERL_TEST_HARNESS_DUMP_TAP} = File::Spec->catfile(@spool);
+
+# now given that we're going to be writing stuff to the file system, make sure we have
+# a cleanup hook
+
+ END {
+ use File::Path;
+
+ $useOrigOpen = $useOrigClose = 1;
+
+ # remove the tree if we made it this far
+ rmtree( $ENV{PERL_TEST_HARNESS_DUMP_TAP} )
+ if $ENV{PERL_TEST_HARNESS_DUMP_TAP};
+ }
+
+ my @die;
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ # use the broken open
+ $useOrigOpen = 0;
+
+ TAP::Harness->_open_spool(
+ File::Spec->catfile(qw (source_tests harness )) );
+
+ # restore universal sanity
+ $useOrigOpen = 1;
+ };
+
+ is @die, 1, 'open failed, die as expected';
+
+ my $spoolDir = quotemeta(
+ File::Spec->catfile( @spool, qw( source_tests harness ) ) );
+
+ like pop @die, qr/ Can't write $spoolDir \( /, '...with expected message';
+
+ # now make close fail
+
+ use Symbol;
+
+ my $spoolHandle = gensym;
+
+ my $tap = <<'END_TAP';
+1..1
+ok 1 - input file opened
+
+END_TAP
+
+ my $parser = TAP::Parser->new(
+ { spool => $spoolHandle,
+ stream =>
+ TAP::Parser::IteratorFactory->new( [ split /\n/ => $tap ] )
+ }
+ );
+
+ @die = ();
+
+ eval {
+ local $SIG{__DIE__} = sub { push @die, @_ };
+
+ # use the broken CORE::close
+ $useOrigClose = 0;
+
+ TAP::Harness->_close_spool($parser);
+
+ $useOrigClose = 1;
+ };
+
+ unless ( is @die, 1, 'close failed, die as expected' ) {
+ diag " >>> $_ <<<\n" for @die;
+ }
+
+ like pop @die, qr/ Error closing TAP spool file[(] /,
+ '...with expected message';
+}
diff --git a/cpan/Test-Harness/t/state.t b/cpan/Test-Harness/t/state.t
new file mode 100644
index 0000000000..2d94e9bbce
--- /dev/null
+++ b/cpan/Test-Harness/t/state.t
@@ -0,0 +1,251 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use Test::More;
+use App::Prove::State;
+use App::Prove::State::Result;
+
+my @schedule = (
+ { options => 'all',
+ get_tests_args => [],
+ expect => [
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/source.t',
+ 't/yamlish-writer.t',
+ ],
+ },
+ { options => 'failed',
+ get_tests_args => [],
+ expect => [
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ ],
+ },
+ { options => 'passed',
+ get_tests_args => [],
+ expect => [
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/source.t',
+ 't/yamlish-writer.t',
+ ],
+ },
+ { options => 'last',
+ get_tests_args => [],
+ expect => [
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/source.t',
+ ],
+ },
+ { options => 'todo',
+ get_tests_args => [],
+ expect => [
+ 't/compat/version.t',
+ 't/compat/failure.t',
+ ],
+
+ },
+ { options => 'hot',
+ get_tests_args => [],
+ expect => [
+ 't/compat/version.t',
+ 't/yamlish-writer.t',
+ 't/compat/env.t',
+ ],
+ },
+ { options => 'adrian',
+ get_tests_args => [],
+ expect => [
+ 't/compat/version.t',
+ 't/yamlish-writer.t',
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/compat/inc_taint.t',
+ 't/source.t',
+ ],
+ },
+ { options => 'failed,passed',
+ get_tests_args => [],
+ expect => [
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/source.t',
+ 't/yamlish-writer.t',
+ ],
+ },
+ { options => [ 'failed', 'passed' ],
+ get_tests_args => [],
+ expect => [
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/source.t',
+ 't/yamlish-writer.t',
+ ],
+ },
+ { options => 'slow',
+ get_tests_args => [],
+ expect => [
+ 't/yamlish-writer.t',
+ 't/compat/env.t',
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/compat/failure.t',
+ 't/source.t',
+ ],
+ },
+ { options => 'fast',
+ get_tests_args => [],
+ expect => [
+ 't/source.t',
+ 't/compat/failure.t',
+ 't/compat/version.t',
+ 't/compat/inc_taint.t',
+ 't/compat/env.t',
+ 't/yamlish-writer.t',
+ ],
+ },
+ { options => 'old',
+ get_tests_args => [],
+ expect => [
+ 't/source.t',
+ 't/compat/inc_taint.t',
+ 't/compat/version.t',
+ 't/yamlish-writer.t',
+ 't/compat/failure.t',
+ 't/compat/env.t',
+ ],
+ },
+ { options => 'new',
+ get_tests_args => [],
+ expect => [
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ 't/yamlish-writer.t',
+ 't/compat/version.t',
+ 't/compat/inc_taint.t',
+ 't/source.t',
+ ],
+ },
+ { options => 'fresh',
+ get_tests_args => [],
+ expect => [
+ 't/compat/env.t',
+ 't/compat/failure.t',
+ ],
+ },
+);
+
+plan tests => @schedule * 2;
+
+for my $test (@schedule) {
+ my $state = App::Prove::State->new;
+ isa_ok $state, 'App::Prove::State';
+
+ my $desc = $test->{options};
+
+ # Naughty
+ $state->{_} = get_state();
+ my $options = $test->{options};
+ $options = [$options] unless 'ARRAY' eq ref $options;
+ $state->apply_switch(@$options);
+
+ my @got = $state->get_tests( @{ $test->{get_tests_args} } );
+ my @expect = @{ $test->{expect} };
+ unless ( is_deeply \@got, \@expect, "$desc: order OK" ) {
+ use Data::Dumper;
+ diag( Dumper( { got => \@got, want => \@expect } ) );
+ }
+}
+
+sub get_state {
+ return App::Prove::State::Result->new(
+ { generation => 51,
+ last_run_time => 1196285439,
+ tests => {
+ 't/compat/failure.t' => {
+ last_result => 0,
+ last_run_time => 1196371471.57738,
+ last_pass_time => 1196371471.57738,
+ total_passes => 48,
+ seq => 1549,
+ gen => 51,
+ elapsed => 0.1230,
+ last_todo => 1,
+ mtime => 1196285623,
+ },
+ 't/yamlish-writer.t' => {
+ last_result => 0,
+ last_run_time => 1196371480.5761,
+ last_pass_time => 1196371480.5761,
+ last_fail_time => 1196368609,
+ total_passes => 41,
+ seq => 1578,
+ gen => 49,
+ elapsed => 12.2983,
+ last_todo => 0,
+ mtime => 1196285400,
+ },
+ 't/compat/env.t' => {
+ last_result => 0,
+ last_run_time => 1196371471.42967,
+ last_pass_time => 1196371471.42967,
+ last_fail_time => 1196368608,
+ total_passes => 48,
+ seq => 1548,
+ gen => 52,
+ elapsed => 3.1290,
+ last_todo => 0,
+ mtime => 1196285739,
+ },
+ 't/compat/version.t' => {
+ last_result => 2,
+ last_run_time => 1196371472.96476,
+ last_pass_time => 1196371472.96476,
+ last_fail_time => 1196368609,
+ total_passes => 47,
+ seq => 1555,
+ gen => 51,
+ elapsed => 0.2363,
+ last_todo => 4,
+ mtime => 1196285239,
+ },
+ 't/compat/inc_taint.t' => {
+ last_result => 3,
+ last_run_time => 1196371471.89682,
+ last_pass_time => 1196371471.89682,
+ total_passes => 47,
+ seq => 1551,
+ gen => 51,
+ elapsed => 1.6938,
+ last_todo => 0,
+ mtime => 1196185639,
+ },
+ 't/source.t' => {
+ last_result => 0,
+ last_run_time => 1196371479.72508,
+ last_pass_time => 1196371479.72508,
+ total_passes => 41,
+ seq => 1570,
+ gen => 51,
+ elapsed => 0.0143,
+ last_todo => 0,
+ mtime => 1186285639,
+ },
+ }
+ }
+ );
+}
diff --git a/cpan/Test-Harness/t/state_results.t b/cpan/Test-Harness/t/state_results.t
new file mode 100644
index 0000000000..fe0b944333
--- /dev/null
+++ b/cpan/Test-Harness/t/state_results.t
@@ -0,0 +1,148 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+use strict;
+use Test::More tests => 25;
+use App::Prove::State;
+
+my $test_suite_data = test_suite_data();
+
+#
+# Test test suite results
+#
+
+can_ok 'App::Prove::State::Result', 'new';
+isa_ok my $result = App::Prove::State::Result->new($test_suite_data),
+ 'App::Prove::State::Result', '... and the object it returns';
+
+ok $result, 'state_version';
+ok defined $result->state_version, '... and it should be defined';
+
+can_ok $result, 'generation';
+is $result->generation, $test_suite_data->{generation},
+ '... and it should return the correct generation';
+
+can_ok $result, 'num_tests';
+is $result->num_tests, scalar keys %{ $test_suite_data->{tests} },
+ '... and it should return the number of tests run';
+
+can_ok $result, 'raw';
+is_deeply $result->raw, $test_suite_data,
+ '... and it should return the raw, unblessed data';
+
+#
+# Check individual tests.
+#
+
+can_ok $result, 'tests';
+
+can_ok $result, 'test';
+eval { $result->test };
+my $error = $@;
+like $error, qr/^\Qtest() requires a test name/,
+ '... and it should croak() if a test name is not supplied';
+
+my $name = 't/compat/failure.t';
+ok my $test = $result->test('t/compat/failure.t'),
+ 'result() should succeed if the test name is found';
+isa_ok $test, 'App::Prove::State::Result::Test',
+ '... and the object it returns';
+
+can_ok $test, 'name';
+is $test->name, $name, '... and it should return the test name';
+
+can_ok $test, 'last_pass_time';
+like $test->last_pass_time, qr/^\d+\.\d+$/,
+ '... and it should return a numeric value';
+
+can_ok $test, 'last_fail_time';
+ok !defined $test->last_fail_time,
+ '... and it should return undef if the test has never failed';
+
+can_ok $result, 'remove';
+ok $result->remove($name), '... and calling it should succeed';
+
+ok $test = $result->test($name),
+ '... and fetching the removed test should suceed';
+ok !defined $test->last_pass_time, '... and it should have clean values';
+
+sub test_suite_data {
+ return {
+ 'version' => App::Prove::State::Result->state_version,
+ 'generation' => '51',
+ 'tests' => {
+ 't/compat/failure.t' => {
+ 'last_result' => '0',
+ 'last_run_time' => '1196371471.57738',
+ 'last_pass_time' => '1196371471.57738',
+ 'total_passes' => '48',
+ 'seq' => '1549',
+ 'gen' => '51',
+ 'elapsed' => 0.1230,
+ 'last_todo' => '1',
+ 'mtime' => 1196285623,
+ },
+ 't/yamlish-writer.t' => {
+ 'last_result' => '0',
+ 'last_run_time' => '1196371480.5761',
+ 'last_pass_time' => '1196371480.5761',
+ 'last_fail_time' => '1196368609',
+ 'total_passes' => '41',
+ 'seq' => '1578',
+ 'gen' => '49',
+ 'elapsed' => 12.2983,
+ 'last_todo' => '0',
+ 'mtime' => 1196285400,
+ },
+ 't/compat/env.t' => {
+ 'last_result' => '0',
+ 'last_run_time' => '1196371471.42967',
+ 'last_pass_time' => '1196371471.42967',
+ 'last_fail_time' => '1196368608',
+ 'total_passes' => '48',
+ 'seq' => '1548',
+ 'gen' => '52',
+ 'elapsed' => 3.1290,
+ 'last_todo' => '0',
+ 'mtime' => 1196285739,
+ },
+ 't/compat/version.t' => {
+ 'last_result' => '2',
+ 'last_run_time' => '1196371472.96476',
+ 'last_pass_time' => '1196371472.96476',
+ 'last_fail_time' => '1196368609',
+ 'total_passes' => '47',
+ 'seq' => '1555',
+ 'gen' => '51',
+ 'elapsed' => 0.2363,
+ 'last_todo' => '4',
+ 'mtime' => 1196285239,
+ },
+ 't/compat/inc_taint.t' => {
+ 'last_result' => '3',
+ 'last_run_time' => '1196371471.89682',
+ 'last_pass_time' => '1196371471.89682',
+ 'total_passes' => '47',
+ 'seq' => '1551',
+ 'gen' => '51',
+ 'elapsed' => 1.6938,
+ 'last_todo' => '0',
+ 'mtime' => 1196185639,
+ },
+ 't/source.t' => {
+ 'last_result' => '0',
+ 'last_run_time' => '1196371479.72508',
+ 'last_pass_time' => '1196371479.72508',
+ 'total_passes' => '41',
+ 'seq' => '1570',
+ 'gen' => '51',
+ 'elapsed' => 0.0143,
+ 'last_todo' => '0',
+ 'mtime' => 1186285639,
+ },
+ }
+ };
+}
diff --git a/cpan/Test-Harness/t/streams.t b/cpan/Test-Harness/t/streams.t
new file mode 100644
index 0000000000..b312ae8367
--- /dev/null
+++ b/cpan/Test-Harness/t/streams.t
@@ -0,0 +1,171 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 47;
+
+use TAP::Parser;
+use TAP::Parser::IteratorFactory;
+
+my $STREAMED = 'TAP::Parser';
+my $ITER = 'TAP::Parser::Iterator';
+my $ITER_FH = "${ITER}::Stream";
+my $ITER_ARRAY = "${ITER}::Array";
+
+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',
+ '... and creating a streamed parser should succeed';
+
+can_ok $parser, '_stream';
+is ref $parser->_stream, $ITER_FH,
+ '... and it should return the proper iterator';
+can_ok $parser, 'next';
+is $parser->next->as_string, '1..5',
+ '... and the plan should parse correctly';
+is $parser->next->as_string, 'ok 1 - input file opened',
+ '... and the first test should parse correctly';
+is $parser->next->as_string, '... this is junk',
+ '... and junk should parse correctly';
+is $parser->next->as_string,
+ 'not ok 2 first line of the input valid # TODO some data',
+ '... and the second test should parse correctly';
+is $parser->next->as_string, '# this is a comment',
+ '... and comments should parse correctly';
+is $parser->next->as_string, 'ok 3 - read the rest of the file',
+ '... and the third test should parse correctly';
+is $parser->next->as_string, 'not ok 4 - this is a real failure',
+ '... and the fourth test should parse correctly';
+is $parser->next->as_string, 'ok 5 # SKIP we have no description',
+ '... and fifth test should parse correctly';
+
+ok !$parser->parse_errors, '... and we should have no parse errors';
+
+# plan at end
+
+my $tap = <<'END_TAP';
+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
+ok 5 # skip we have no description
+1..5
+END_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,
+ '... and now we should have an array iterator';
+is $parser->next->as_string, 'ok 1 - input file opened',
+ '... and the first test should parse correctly';
+is $parser->next->as_string, '... this is junk',
+ '... and junk should parse correctly';
+is $parser->next->as_string,
+ 'not ok 2 first line of the input valid # TODO some data',
+ '... and the second test should parse correctly';
+is $parser->next->as_string, '# this is a comment',
+ '... and comments should parse correctly';
+is $parser->next->as_string, 'ok 3 - read the rest of the file',
+ '... and the third test should parse correctly';
+is $parser->next->as_string, 'not ok 4 - this is a real failure',
+ '... and the fourth test should parse correctly';
+is $parser->next->as_string, 'ok 5 # SKIP we have no description',
+ '... and fifth test should parse correctly';
+is $parser->next->as_string, '1..5',
+ '... and the plan should parse correctly';
+
+ok !$parser->parse_errors, '... and we should have no parse errors';
+
+# misplaced plan (and one-off errors)
+
+$tap = <<'END_TAP';
+ok 1 - input file opened
+1..5
+... 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
+ok 5 # skip we have no description
+END_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';
+is $parser->next->as_string, 'ok 1 - input file opened',
+ '... and the first test should parse correctly';
+is $parser->next->as_string, '1..5',
+ '... and the plan should parse correctly';
+is $parser->next->as_string, '... this is junk',
+ '... and junk should parse correctly';
+is $parser->next->as_string,
+ 'not ok 2 first line of the input valid # TODO some data',
+ '... and the second test should parse correctly';
+is $parser->next->as_string, '# this is a comment',
+ '... and comments should parse correctly';
+is $parser->next->as_string, 'ok 3 - read the rest of the file',
+ '... and the third test should parse correctly';
+is $parser->next->as_string, 'not ok 4 - this is a real failure',
+ '... and the fourth test should parse correctly';
+is $parser->next->as_string, 'ok 5 # SKIP we have no description',
+ '... and fifth test should parse correctly';
+
+ok $parser->parse_errors, '... and we should have one parse error';
+is + ( $parser->parse_errors )[0],
+ 'Plan (1..5) must be at the beginning or end of the TAP output',
+ '... telling us that our plan went awry';
+
+$tap = <<'END_TAP';
+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
+1..5
+ok 5 # skip we have no description
+END_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';
+is $parser->next->as_string, 'ok 1 - input file opened',
+ '... and the first test should parse correctly';
+is $parser->next->as_string, '... this is junk',
+ '... and junk should parse correctly';
+is $parser->next->as_string,
+ 'not ok 2 first line of the input valid # TODO some data',
+ '... and the second test should parse correctly';
+is $parser->next->as_string, '# this is a comment',
+ '... and comments should parse correctly';
+is $parser->next->as_string, 'ok 3 - read the rest of the file',
+ '... and the third test should parse correctly';
+is $parser->next->as_string, 'not ok 4 - this is a real failure',
+ '... and the fourth test should parse correctly';
+is $parser->next->as_string, '1..5',
+ '... and the plan should parse correctly';
+is $parser->next->as_string, 'ok 5 # SKIP we have no description',
+ '... and fifth test should parse correctly';
+
+ok $parser->parse_errors, '... and we should have one parse error';
+is + ( $parser->parse_errors )[0],
+ 'Plan (1..5) must be at the beginning or end of the TAP output',
+ '... telling us that our plan went awry';
+
+__DATA__
+1..5
+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
+ok 5 # skip we have no description
diff --git a/cpan/Test-Harness/t/subclass_tests/non_perl_source b/cpan/Test-Harness/t/subclass_tests/non_perl_source
new file mode 100644
index 0000000000..12f0f74012
--- /dev/null
+++ b/cpan/Test-Harness/t/subclass_tests/non_perl_source
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo "1..1"
+echo "ok 1 - this is a test"
diff --git a/cpan/Test-Harness/t/subclass_tests/perl_source b/cpan/Test-Harness/t/subclass_tests/perl_source
new file mode 100644
index 0000000000..7fef7d5459
--- /dev/null
+++ b/cpan/Test-Harness/t/subclass_tests/perl_source
@@ -0,0 +1,6 @@
+#!/usr/bin/perl
+
+print <<'END_TESTS';
+1..1
+ok 1 - this is a test
+END_TESTS
diff --git a/cpan/Test-Harness/t/taint.t b/cpan/Test-Harness/t/taint.t
new file mode 100644
index 0000000000..2812fc4375
--- /dev/null
+++ b/cpan/Test-Harness/t/taint.t
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+ unshift @INC, 't/lib';
+}
+
+# Test that options in PERL5OPT are propogated to tainted tests
+
+use strict;
+use Test::More ( $^O eq 'VMS' ? ( skip_all => 'VMS' ) : ( tests => 1 ) );
+
+use Config;
+use TAP::Parser;
+
+my $lib_path = join( ', ', map "'$_'", grep !ref, grep defined, @INC );
+
+sub run_test_file {
+ my ( $test_template, @args ) = @_;
+
+ my $test_file = 'temp_test.tmp';
+
+ open TEST, ">$test_file" or die $!;
+ printf TEST $test_template, @args;
+ close TEST;
+
+ my $p = TAP::Parser->new(
+ { source => $test_file,
+
+ # Test taint when there's spaces in a -I path
+ switches => [q["-Ifoo bar"]],
+ }
+ );
+ 1 while $p->next;
+ ok !$p->has_problems;
+
+ unlink $test_file;
+}
+
+{
+ local $ENV{PERL5OPT} = $ENV{PERL_CORE} ? '-I../../lib -Mstrict' : '-Mstrict';
+ run_test_file(<<'END');
+#!/usr/bin/perl -T
+
+print "1..1\n";
+print $INC{'strict.pm'} ? "ok 1\n" : "not ok 1\n";
+END
+}
+
+1;
diff --git a/cpan/Test-Harness/t/testargs.t b/cpan/Test-Harness/t/testargs.t
new file mode 100644
index 0000000000..aa3aa7337c
--- /dev/null
+++ b/cpan/Test-Harness/t/testargs.t
@@ -0,0 +1,128 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 19;
+use File::Spec;
+use TAP::Parser;
+use TAP::Harness;
+use App::Prove;
+
+my $test = File::Spec->catfile(
+ 't',
+ 'sample-tests',
+ 'echo'
+);
+
+diag( "\n\n", bigness( join ' ', @ARGV ), "\n\n" ) if @ARGV;
+
+sub echo_ok {
+ my $options = shift;
+ my @args = @_;
+ my $parser = TAP::Parser->new( { %$options, test_args => \@args } );
+ my @got = ();
+ while ( my $result = $parser->next ) {
+ push @got, $result;
+ }
+ my $plan = shift @got;
+ ok $plan->is_plan;
+ for (@got) {
+ is $_->description, shift(@args),
+ join( ', ', keys %$options ) . ": option passed OK";
+ }
+}
+
+for my $args ( [qw( yes no maybe )], [qw( 1 2 3 )] ) {
+ echo_ok( { source => $test }, @$args );
+ echo_ok( { exec => [ $^X, $test ] }, @$args );
+}
+
+{
+ my $harness = TAP::Harness->new(
+ { verbosity => -9, test_args => [qw( magic hat brigade )] } );
+ my $aggregate = $harness->runtests($test);
+
+ is $aggregate->total, 3, "ran the right number of tests";
+ is $aggregate->passed, 3, "and they passed";
+}
+
+package Test::Prove;
+
+use vars qw(@ISA);
+@ISA = 'App::Prove';
+
+sub _runtests {
+ my $self = shift;
+ push @{ $self->{_log} }, [@_];
+ return;
+}
+
+sub get_run_log {
+ my $self = shift;
+ return $self->{_log};
+}
+
+package main;
+
+{
+ my $app = Test::Prove->new;
+
+ $app->process_args( '--norc', $test, '::', 'one', 'two', 'huh' );
+ $app->run();
+ my $log = $app->get_run_log;
+ is_deeply $log->[0]->[0]->{test_args}, [ 'one', 'two', 'huh' ],
+ "prove args match";
+}
+
+sub bigness {
+ my $str = join '', @_;
+ my @cdef = (
+ '0000000000000000', '1818181818001800', '6c6c6c0000000000',
+ '36367f367f363600', '0c3f683e0b7e1800', '60660c1830660600',
+ '386c6c386d663b00', '0c18300000000000', '0c18303030180c00',
+ '30180c0c0c183000', '00187e3c7e180000', '0018187e18180000',
+ '0000000000181830', '0000007e00000000', '0000000000181800',
+ '00060c1830600000', '3c666e7e76663c00', '1838181818187e00',
+ '3c66060c18307e00', '3c66061c06663c00', '0c1c3c6c7e0c0c00',
+ '7e607c0606663c00', '1c30607c66663c00', '7e060c1830303000',
+ '3c66663c66663c00', '3c66663e060c3800', '0000181800181800',
+ '0000181800181830', '0c18306030180c00', '00007e007e000000',
+ '30180c060c183000', '3c660c1818001800', '3c666e6a6e603c00',
+ '3c66667e66666600', '7c66667c66667c00', '3c66606060663c00',
+ '786c6666666c7800', '7e60607c60607e00', '7e60607c60606000',
+ '3c66606e66663c00', '6666667e66666600', '7e18181818187e00',
+ '3e0c0c0c0c6c3800', '666c7870786c6600', '6060606060607e00',
+ '63777f6b6b636300', '6666767e6e666600', '3c66666666663c00',
+ '7c66667c60606000', '3c6666666a6c3600', '7c66667c6c666600',
+ '3c66603c06663c00', '7e18181818181800', '6666666666663c00',
+ '66666666663c1800', '63636b6b7f776300', '66663c183c666600',
+ '6666663c18181800', '7e060c1830607e00', '7c60606060607c00',
+ '006030180c060000', '3e06060606063e00', '183c664200000000',
+ '00000000000000ff', '1c36307c30307e00', '00003c063e663e00',
+ '60607c6666667c00', '00003c6660663c00', '06063e6666663e00',
+ '00003c667e603c00', '1c30307c30303000', '00003e66663e063c',
+ '60607c6666666600', '1800381818183c00', '1800381818181870',
+ '6060666c786c6600', '3818181818183c00', '0000367f6b6b6300',
+ '00007c6666666600', '00003c6666663c00', '00007c66667c6060',
+ '00003e66663e0607', '00006c7660606000', '00003e603c067c00',
+ '30307c3030301c00', '0000666666663e00', '00006666663c1800',
+ '0000636b6b7f3600', '0000663c183c6600', '00006666663e063c',
+ '00007e0c18307e00', '0c18187018180c00', '1818180018181800',
+ '3018180e18183000', '316b460000000000'
+ );
+ my @chars = unpack( 'C*', $str );
+ my @out = ();
+ for my $row ( 0 .. 7 ) {
+ for my $char (@chars) {
+ next if $char < 32 || $char > 126;
+ my $size = scalar(@cdef);
+ my $byte = hex( substr( $cdef[ $char - 32 ], $row * 2, 2 ) );
+ my $bits = sprintf( '%08b', $byte );
+ $bits =~ tr/01/ #/;
+ push @out, $bits;
+ }
+ push @out, "\n";
+ }
+ return join '', @out;
+}
diff --git a/cpan/Test-Harness/t/unicode.t b/cpan/Test-Harness/t/unicode.t
new file mode 100644
index 0000000000..88d32081ba
--- /dev/null
+++ b/cpan/Test-Harness/t/unicode.t
@@ -0,0 +1,125 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+use Test::More;
+use TAP::Parser;
+
+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;
+
+ plan skip_all => "PERL_UNICODE set"
+ if defined $ENV{PERL_UNICODE};
+
+ eval "use File::Temp";
+ plan skip_all => "File::Temp unavailable"
+ if $@;
+
+ eval "use Encode";
+ plan skip_all => "Encode unavailable"
+ if $@;
+
+ # Subs that take the supplied TAP and turn it into a set of args to
+ # supply to TAP::Harness->new. The returned hash includes the
+ # temporary file so that its reference count doesn't go to zero
+ # until we're finished with it.
+ %make_test = (
+ file => sub {
+ my $source = shift;
+ my $tmp = File::Temp->new;
+ open my $fh, ">$tmp" or die "Can't write $tmp ($!)\n";
+ eval 'binmode( $fh, ":utf8" )';
+ print $fh join( "\n", @$source ), "\n";
+ close $fh;
+
+ open my $taph, "<$tmp" or die "Can't read $tmp ($!)\n";
+ eval 'binmode( $taph, ":utf8" )';
+ return {
+ temp => $tmp,
+ args => { source => $taph },
+ };
+ },
+ script => sub {
+ my $source = shift;
+ my $tmp = File::Temp->new;
+ open my $fh, ">$tmp" or die "Can't write $tmp ($!)\n";
+ eval 'binmode( $fh, ":utf8" )';
+ print $fh map {"print qq{$_\\n};\n"} @$source;
+ close $fh;
+
+ open my $taph, "<$tmp" or die "Can't read $tmp ($!)\n";
+ return {
+ temp => $tmp,
+ args => { exec => [ $^X, "$tmp" ] },
+ };
+ },
+ );
+
+ @schedule = (
+ { name => 'Non-unicode warm up',
+ source => [
+ 'TAP version 13',
+ '1..1',
+ 'ok 1 Everything is fine',
+ ],
+ expect => [
+ { isa => 'TAP::Parser::Result::Version', },
+ { isa => 'TAP::Parser::Result::Plan', },
+ { isa => 'TAP::Parser::Result::Test',
+ description => "Everything is fine"
+ },
+ ],
+ },
+ { name => 'Unicode smiley',
+ source => [
+ 'TAP version 13',
+ '1..1',
+
+ # Funky quoting / eval to avoid errors on older Perls
+ eval qq{"ok 1 Everything is fine \\x{263a}"},
+ ],
+ expect => [
+ { isa => 'TAP::Parser::Result::Version', },
+ { isa => 'TAP::Parser::Result::Plan', },
+ { isa => 'TAP::Parser::Result::Test',
+ description => eval qq{"Everything is fine \\x{263a}"}
+ },
+ ],
+ }
+ );
+
+ plan 'no_plan';
+}
+
+for my $test (@schedule) {
+ for my $type ( sort keys %make_test ) {
+ my $name = sprintf( "%s (%s)", $test->{name}, $type );
+ my $args = $make_test{$type}->( $test->{source} );
+
+ my $parser = TAP::Parser->new( $args->{args} );
+ isa_ok $parser, 'TAP::Parser';
+ my @expect = @{ $test->{expect} };
+ while ( my $tok = $parser->next ) {
+ my $exp = shift @expect;
+ for my $item ( sort keys %$exp ) {
+ my $val = $exp->{$item};
+ if ( 'isa' eq $item ) {
+ isa_ok $tok, $val;
+ }
+ elsif ( 'CODE' eq ref $val ) {
+ ok $val->($tok), "$name: assertion for $item";
+ }
+ else {
+ my $got = $tok->$item();
+ is $got, $val, "$name: value for $item matches";
+ }
+ }
+ }
+ }
+}
diff --git a/cpan/Test-Harness/t/utils.t b/cpan/Test-Harness/t/utils.t
new file mode 100644
index 0000000000..4851ac1f1c
--- /dev/null
+++ b/cpan/Test-Harness/t/utils.t
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+use strict;
+use lib 't/lib';
+
+use TAP::Parser::Utils qw( split_shell );
+use Test::More;
+
+my @schedule = (
+ { name => 'Bare words',
+ in => 'bare words are here',
+ out => [ 'bare', 'words', 'are', 'here' ],
+ },
+ { name => 'Single quotes',
+ in => "'bare' 'words' 'are' 'here'",
+ out => [ 'bare', 'words', 'are', 'here' ],
+ },
+ { name => 'Double quotes',
+ in => '"bare" "words" "are" "here"',
+ out => [ 'bare', 'words', 'are', 'here' ],
+ },
+ { name => 'Escapes',
+ in => '\ "ba\"re" \'wo\\\'rds\' \\\\"are" "here"',
+ out => [ ' ', 'ba"re', "wo'rds", '\\are', 'here' ],
+ },
+ { name => 'Flag',
+ in => '-e "system(shift)"',
+ out => [ '-e', 'system(shift)' ],
+ },
+ { name => 'Nada',
+ in => undef,
+ out => [],
+ },
+ { name => 'Nada II',
+ in => '',
+ out => [],
+ },
+ { name => 'Zero',
+ in => 0,
+ out => ['0'],
+ },
+ { name => 'Empty',
+ in => '""',
+ out => [''],
+ },
+ { name => 'Empty II',
+ in => "''",
+ out => [''],
+ },
+);
+
+plan tests => 1 * @schedule;
+
+for my $test (@schedule) {
+ my $name = $test->{name};
+ my @got = split_shell( $test->{in} );
+ unless ( is_deeply \@got, $test->{out}, "$name: parse OK" ) {
+ use Data::Dumper;
+ diag( Dumper( { want => $test->{out}, got => \@got } ) );
+ }
+}
diff --git a/cpan/Test-Harness/t/yamlish-output.t b/cpan/Test-Harness/t/yamlish-output.t
new file mode 100644
index 0000000000..914d7ea237
--- /dev/null
+++ b/cpan/Test-Harness/t/yamlish-output.t
@@ -0,0 +1,100 @@
+#!/usr/bin/perl -wT
+
+use strict;
+use lib 't/lib';
+
+use Test::More tests => 9;
+
+use TAP::Parser::YAMLish::Writer;
+
+my $out = [
+ "---",
+ "bill-to:",
+ " address:",
+ " city: \"Royal Oak\"",
+ " lines: \"458 Walkman Dr.\\nSuite #292\\n\"",
+ " postal: 48046",
+ " state: MI",
+ " family: Dumars",
+ " given: Chris",
+ "comments: \"Late afternoon is best. Backup contact is Nancy Billsmer \@ 338-4338\\n\"",
+ "date: 2001-01-23",
+ "invoice: 34843",
+ "product:",
+ " -",
+ " description: Basketball",
+ " price: 450.00",
+ " quantity: 4",
+ " sku: BL394D",
+ " -",
+ " description: \"Super Hoop\"",
+ " price: 2392.00",
+ " quantity: 1",
+ " sku: BL4438H",
+ "tax: 251.42",
+ "total: 4443.52",
+ "...",
+];
+
+my $in = {
+ 'bill-to' => {
+ 'given' => 'Chris',
+ 'address' => {
+ 'city' => 'Royal Oak',
+ 'postal' => '48046',
+ 'lines' => "458 Walkman Dr.\nSuite #292\n",
+ 'state' => 'MI'
+ },
+ 'family' => 'Dumars'
+ },
+ 'invoice' => '34843',
+ 'date' => '2001-01-23',
+ 'tax' => '251.42',
+ 'product' => [
+ { 'sku' => 'BL394D',
+ 'quantity' => '4',
+ 'price' => '450.00',
+ 'description' => 'Basketball'
+ },
+ { 'sku' => 'BL4438H',
+ 'quantity' => '1',
+ 'price' => '2392.00',
+ 'description' => 'Super Hoop'
+ }
+ ],
+ 'comments' =>
+ "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n",
+ 'total' => '4443.52'
+};
+
+my @buf1 = ();
+my @buf2 = ();
+my $buf3 = '';
+
+my @destination = (
+ { name => 'Array reference',
+ destination => \@buf1,
+ normalise => sub { return \@buf1 },
+ },
+ { name => 'Closure',
+ destination => sub { push @buf2, shift },
+ normalise => sub { return \@buf2 },
+ },
+ { name => 'Scalar',
+ destination => \$buf3,
+ normalise => sub {
+ my @ar = split( /\n/, $buf3 );
+ return \@ar;
+ },
+ },
+);
+
+for my $dest (@destination) {
+ my $name = $dest->{name};
+ ok my $yaml = TAP::Parser::YAMLish::Writer->new, "$name: Created";
+ isa_ok $yaml, 'TAP::Parser::YAMLish::Writer';
+
+ $yaml->write( $in, $dest->{destination} );
+ my $got = $dest->{normalise}->();
+ is_deeply $got, $out, "$name: Result matches";
+}
diff --git a/cpan/Test-Harness/t/yamlish-writer.t b/cpan/Test-Harness/t/yamlish-writer.t
new file mode 100644
index 0000000000..f7a22c3dab
--- /dev/null
+++ b/cpan/Test-Harness/t/yamlish-writer.t
@@ -0,0 +1,274 @@
+#!/usr/bin/perl
+
+use strict;
+use lib 't/lib';
+
+use Test::More;
+
+use TAP::Parser::YAMLish::Reader;
+use TAP::Parser::YAMLish::Writer;
+
+my @SCHEDULE;
+
+BEGIN {
+ @SCHEDULE = (
+ { name => 'Simple scalar',
+ in => 1,
+ out => [
+ '--- 1',
+ '...',
+ ],
+ },
+ { name => 'Undef',
+ in => undef,
+ out => [
+ '--- ~',
+ '...',
+ ],
+ },
+ { name => 'Unprintable',
+ in => "\x01\n\t",
+ out => [
+ '--- "\x01\n\t"',
+ '...',
+ ],
+ },
+ { name => 'Simple array',
+ in => [ 1, 2, 3 ],
+ out => [
+ '---',
+ '- 1',
+ '- 2',
+ '- 3',
+ '...',
+ ],
+ },
+ { name => 'Empty array',
+ in => [],
+ out => [
+ '--- []',
+ '...'
+ ],
+ },
+ { name => 'Empty hash',
+ in => {},
+ out => [
+ '--- {}',
+ '...'
+ ],
+ },
+ { name => 'Array, two elements, undef',
+ in => [ undef, undef ],
+ out => [
+ '---',
+ '- ~',
+ '- ~',
+ '...',
+ ],
+ },
+ { name => 'Nested array',
+ in => [ 1, 2, [ 3, 4 ], 5 ],
+ out => [
+ '---',
+ '- 1',
+ '- 2',
+ '-',
+ ' - 3',
+ ' - 4',
+ '- 5',
+ '...',
+ ],
+ },
+ { name => 'Nested empty',
+ in => [ 1, 2, [], 5 ],
+ out => [
+ '---',
+ '- 1',
+ '- 2',
+ '- []',
+ '- 5',
+ '...',
+ ],
+ },
+ { name => 'Simple hash',
+ in => { one => '1', two => '2', three => '3' },
+ out => [
+ '---',
+ 'one: 1',
+ 'three: 3',
+ 'two: 2',
+ '...',
+ ],
+ },
+ { name => 'Nested hash',
+ in => {
+ one => '1', two => '2',
+ more => { three => '3', four => '4' }
+ },
+ out => [
+ '---',
+ 'more:',
+ ' four: 4',
+ ' three: 3',
+ 'one: 1',
+ 'two: 2',
+ '...',
+ ],
+ },
+ { name => 'Nested empty',
+ in => { one => '1', two => '2', more => {} },
+ out => [
+ '---',
+ 'more: {}',
+ 'one: 1',
+ 'two: 2',
+ '...',
+ ],
+ },
+ { name => 'Unprintable key',
+ in => { one => '1', "\x02" => '2', three => '3' },
+ out => [
+ '---',
+ '"\x02": 2',
+ 'one: 1',
+ 'three: 3',
+ '...',
+ ],
+ },
+ { name => 'Empty key',
+ in => { '' => 'empty' },
+ out => [
+ '---',
+ "'': empty",
+ '...',
+ ],
+ },
+ { name => 'Empty value',
+ in => { '' => '' },
+ out => [
+ '---',
+ "'': ''",
+ '...',
+ ],
+ },
+ { name => 'Funky hash key',
+ in => { './frob' => 'is_frob' },
+ out => [
+ '---',
+ '"./frob": is_frob',
+ '...',
+ ]
+ },
+ { name => 'Complex',
+ in => {
+ 'bill-to' => {
+ 'given' => 'Chris',
+ 'address' => {
+ 'city' => 'Royal Oak',
+ 'postal' => '48046',
+ 'lines' => "458 Walkman Dr.\nSuite #292\n",
+ 'state' => 'MI'
+ },
+ 'family' => 'Dumars'
+ },
+ 'invoice' => '34843',
+ 'date' => '2001-01-23',
+ 'tax' => '251.42',
+ 'product' => [
+ { 'sku' => 'BL394D',
+ 'quantity' => '4',
+ 'price' => '450.00',
+ 'description' => 'Basketball'
+ },
+ { 'sku' => 'BL4438H',
+ 'quantity' => '1',
+ 'price' => '2392.00',
+ 'description' => 'Super Hoop'
+ }
+ ],
+ 'comments' =>
+ "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n",
+ 'total' => '4443.52'
+ },
+ out => [
+ "---",
+ "bill-to:",
+ " address:",
+ " city: \"Royal Oak\"",
+ " lines: \"458 Walkman Dr.\\nSuite #292\\n\"",
+ " postal: 48046",
+ " state: MI",
+ " family: Dumars",
+ " given: Chris",
+ "comments: \"Late afternoon is best. Backup contact is Nancy Billsmer \@ 338-4338\\n\"",
+ "date: 2001-01-23",
+ "invoice: 34843",
+ "product:",
+ " -",
+ " description: Basketball",
+ " price: 450.00",
+ " quantity: 4",
+ " sku: BL394D",
+ " -",
+ " description: \"Super Hoop\"",
+ " price: 2392.00",
+ " quantity: 1",
+ " sku: BL4438H",
+ "tax: 251.42",
+ "total: 4443.52",
+ "...",
+ ],
+ },
+ );
+
+ plan tests => @SCHEDULE * 6;
+}
+
+sub iter {
+ my $ar = shift;
+ return sub {
+ return shift @$ar;
+ };
+}
+
+for my $test (@SCHEDULE) {
+ my $name = $test->{name};
+ ok my $yaml = TAP::Parser::YAMLish::Writer->new, "$name: Created";
+ isa_ok $yaml, 'TAP::Parser::YAMLish::Writer';
+
+ my $got = [];
+ my $writer = sub { push @$got, shift };
+
+ my $data = $test->{in};
+
+ eval { $yaml->write( $data, $writer ) };
+
+ if ( my $err = $test->{error} ) {
+ unless ( like $@, $err, "$name: Error message" ) {
+ diag "Error: $@\n";
+ }
+ is_deeply $got, [], "$name: No result";
+ pass;
+ }
+ else {
+ my $want = $test->{out};
+ unless ( ok !$@, "$name: No error" ) {
+ diag "Error: $@\n";
+ }
+ unless ( is_deeply $got, $want, "$name: Result matches" ) {
+ use Data::Dumper;
+ diag Dumper($got);
+ diag Dumper($want);
+ }
+
+ my $yr = TAP::Parser::YAMLish::Reader->new;
+
+ # Now try parsing it
+ my $reader = sub { shift @$got };
+ my $parsed = eval { $yr->read($reader) };
+ ok !$@, "$name: no error" or diag "$@";
+
+ is_deeply $parsed, $data, "$name: Reparse OK";
+ }
+}
+
diff --git a/cpan/Test-Harness/t/yamlish.t b/cpan/Test-Harness/t/yamlish.t
new file mode 100644
index 0000000000..76ba7982b4
--- /dev/null
+++ b/cpan/Test-Harness/t/yamlish.t
@@ -0,0 +1,529 @@
+#!perl -w
+
+use strict;
+use lib 't/lib';
+
+use Test::More;
+
+use TAP::Parser::YAMLish::Reader;
+
+my @SCHEDULE;
+
+BEGIN {
+ @SCHEDULE = (
+ { name => 'Hello World',
+ in => [
+ '--- Hello, World',
+ '...',
+ ],
+ out => "Hello, World",
+ },
+ { name => 'Hello World 2',
+ in => [
+ '--- \'Hello, \'\'World\'',
+ '...',
+ ],
+ out => "Hello, 'World",
+ },
+ { name => 'Hello World 3',
+ in => [
+ '--- "Hello, World"',
+ '...',
+ ],
+ out => "Hello, World",
+ },
+ { name => 'Hello World 4',
+ in => [
+ '--- "Hello, World"',
+ '...',
+ ],
+ out => "Hello, World",
+ },
+ { name => 'Hello World 4',
+ in => [
+ '--- >',
+ ' Hello,',
+ ' World',
+ '...',
+ ],
+ out => "Hello, World\n",
+ },
+ { name => 'Hello World Block',
+ in => [
+ '--- |',
+ ' Hello,',
+ ' World',
+ '...',
+ ],
+ out => "Hello,\n World\n",
+ },
+ { name => 'Hello World 5',
+ in => [
+ '--- >',
+ ' Hello,',
+ ' World',
+ '...',
+ ],
+ error => qr{Missing\s+'[.][.][.]'},
+ },
+ { name => 'Simple array',
+ in => [
+ '---',
+ '- 1',
+ '- 2',
+ '- 3',
+ '...',
+ ],
+ out => [ '1', '2', '3' ],
+ },
+ { name => 'Mixed array',
+ in => [
+ '---',
+ '- 1',
+ '- \'two\'',
+ '- "three\n"',
+ '...',
+ ],
+ out => [ '1', 'two', "three\n" ],
+ },
+ { name => 'Hash in array',
+ in => [
+ '---',
+ '- 1',
+ '- two: 2',
+ '- 3',
+ '...',
+ ],
+ out => [ '1', { two => '2' }, '3' ],
+ },
+ { name => 'Hash in array 2',
+ in => [
+ '---',
+ '- 1',
+ '- two: 2',
+ ' three: 3',
+ '- 4',
+ '...',
+ ],
+ out => [ '1', { two => '2', three => '3' }, '4' ],
+ },
+ { name => 'Nested array',
+ in => [
+ '---',
+ '- one',
+ '-',
+ ' - two',
+ ' -',
+ ' - three',
+ ' - four',
+ '- five',
+ '...',
+ ],
+ out => [ 'one', [ 'two', ['three'], 'four' ], 'five' ],
+ },
+ { name => 'Nested hash',
+ in => [
+ '---',
+ 'one:',
+ ' five: 5',
+ ' two:',
+ ' four: 4',
+ ' three: 3',
+ 'six: 6',
+ '...',
+ ],
+ out => {
+ one => { two => { three => '3', four => '4' }, five => '5' },
+ six => '6'
+ },
+ },
+ { name => 'Space after colon',
+ in => [ '---', 'spog: ', ' - 1', ' - 2', '...' ],
+ out => { spog => [ 1, 2 ] },
+ },
+ { name => 'Original YAML::Tiny test',
+ in => [
+ '---',
+ 'invoice: 34843',
+ 'date : 2001-01-23',
+ 'bill-to:',
+ ' given : Chris',
+ ' family : Dumars',
+ ' address:',
+ ' lines: |',
+ ' 458 Walkman Dr.',
+ ' Suite #292',
+ ' city : Royal Oak',
+ ' state : MI',
+ ' postal : 48046',
+ 'product:',
+ ' - sku : BL394D',
+ ' quantity : 4',
+ ' description : Basketball',
+ ' price : 450.00',
+ ' - sku : BL4438H',
+ ' quantity : 1',
+ ' description : Super Hoop',
+ ' price : 2392.00',
+ 'tax : 251.42',
+ 'total: 4443.52',
+ 'comments: >',
+ ' Late afternoon is best.',
+ ' Backup contact is Nancy',
+ ' Billsmer @ 338-4338',
+ '...',
+ ],
+ out => {
+ 'bill-to' => {
+ 'given' => 'Chris',
+ 'address' => {
+ 'city' => 'Royal Oak',
+ 'postal' => '48046',
+ 'lines' => "458 Walkman Dr.\nSuite #292\n",
+ 'state' => 'MI'
+ },
+ 'family' => 'Dumars'
+ },
+ 'invoice' => '34843',
+ 'date' => '2001-01-23',
+ 'tax' => '251.42',
+ 'product' => [
+ { 'sku' => 'BL394D',
+ 'quantity' => '4',
+ 'price' => '450.00',
+ 'description' => 'Basketball'
+ },
+ { 'sku' => 'BL4438H',
+ 'quantity' => '1',
+ 'price' => '2392.00',
+ 'description' => 'Super Hoop'
+ }
+ ],
+ 'comments' =>
+ "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338\n",
+ 'total' => '4443.52'
+ }
+ },
+
+ # Tests harvested from YAML::Tiny
+ { in => ['...'],
+ name => 'Regression: empty',
+ error => qr{document\s+header\s+not\s+found}
+ },
+ { in => [
+ '# comment',
+ '...'
+ ],
+ name => 'Regression: only_comment',
+ error => qr{document\s+header\s+not\s+found}
+ },
+ { out => undef,
+ in => [
+ '---',
+ '...'
+ ],
+ name => 'Regression: only_header',
+ error => qr{Premature\s+end}i,
+ },
+ { out => undef,
+ in => [
+ '---',
+ '---',
+ '...'
+ ],
+ name => 'Regression: two_header',
+ error => qr{Unexpected\s+start}i,
+ },
+ { out => undef,
+ in => [
+ '--- ~',
+ '...'
+ ],
+ name => 'Regression: one_undef'
+ },
+ { out => undef,
+ in => [
+ '--- ~',
+ '...'
+ ],
+ name => 'Regression: one_undef2'
+ },
+ { in => [
+ '--- ~',
+ '---',
+ '...'
+ ],
+ name => 'Regression: two_undef',
+ error => qr{Missing\s+'[.][.][.]'},
+ },
+ { out => 'foo',
+ in => [
+ '--- foo',
+ '...'
+ ],
+ name => 'Regression: one_scalar',
+ },
+ { out => 'foo',
+ in => [
+ '--- foo',
+ '...'
+ ],
+ name => 'Regression: one_scalar2',
+ },
+ { in => [
+ '--- foo',
+ '--- bar',
+ '...'
+ ],
+ name => 'Regression: two_scalar',
+ error => qr{Missing\s+'[.][.][.]'},
+ },
+ { out => ['foo'],
+ in => [
+ '---',
+ '- foo',
+ '...'
+ ],
+ name => 'Regression: one_list1'
+ },
+ { out => [
+ 'foo',
+ 'bar'
+ ],
+ in => [
+ '---',
+ '- foo',
+ '- bar',
+ '...'
+ ],
+ name => 'Regression: one_list2'
+ },
+ { out => [
+ undef,
+ 'bar'
+ ],
+ in => [
+ '---',
+ '- ~',
+ '- bar',
+ '...'
+ ],
+ name => 'Regression: one_listundef'
+ },
+ { out => { 'foo' => 'bar' },
+ in => [
+ '---',
+ 'foo: bar',
+ '...'
+ ],
+ name => 'Regression: one_hash1'
+ },
+ { out => {
+ 'foo' => 'bar',
+ 'this' => undef
+ },
+ in => [
+ '---',
+ 'foo: bar',
+ 'this: ~',
+ '...'
+ ],
+ name => 'Regression: one_hash2'
+ },
+ { out => {
+ 'foo' => [
+ 'bar',
+ undef,
+ 'baz'
+ ]
+ },
+ in => [
+ '---',
+ 'foo:',
+ ' - bar',
+ ' - ~',
+ ' - baz',
+ '...'
+ ],
+ name => 'Regression: array_in_hash'
+ },
+ { out => {
+ 'bar' => { 'foo' => 'bar' },
+ 'foo' => undef
+ },
+ in => [
+ '---',
+ 'foo: ~',
+ 'bar:',
+ ' foo: bar',
+ '...'
+ ],
+ name => 'Regression: hash_in_hash'
+ },
+ { out => [
+ { 'foo' => undef,
+ 'this' => 'that'
+ },
+ 'foo', undef,
+ { 'foo' => 'bar',
+ 'this' => 'that'
+ }
+ ],
+ in => [
+ '---',
+ '-',
+ ' foo: ~',
+ ' this: that',
+ '- foo',
+ '- ~',
+ '-',
+ ' foo: bar',
+ ' this: that',
+ '...'
+ ],
+ name => 'Regression: hash_in_array'
+ },
+ { out => ['foo'],
+ in => [
+ '---',
+ '- \'foo\'',
+ '...'
+ ],
+ name => 'Regression: single_quote1'
+ },
+ { out => [' '],
+ in => [
+ '---',
+ '- \' \'',
+ '...'
+ ],
+ name => 'Regression: single_spaces'
+ },
+ { out => [''],
+ in => [
+ '---',
+ '- \'\'',
+ '...'
+ ],
+ name => 'Regression: single_null'
+ },
+ { out => ' ',
+ in => [
+ '--- " "',
+ '...'
+ ],
+ name => 'Regression: only_spaces'
+ },
+ { out => [
+ undef,
+ { 'foo' => 'bar',
+ 'this' => 'that'
+ },
+ 'baz'
+ ],
+ in => [
+ '---',
+ '- ~',
+ '- foo: bar',
+ ' this: that',
+ '- baz',
+ '...'
+ ],
+ name => 'Regression: inline_nested_hash'
+ },
+ { name => "Unprintables",
+ in => [
+ "---",
+ "- \"\\z\\x01\\x02\\x03\\x04\\x05\\x06\\a\\x08\\t\\n\\v\\f\\r\\x0e\\x0f\"",
+ "- \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\e\\x1c\\x1d\\x1e\\x1f\"",
+ "- \" !\\\"#\$%&'()*+,-./\"",
+ "- 0123456789:;<=>?",
+ "- '\@ABCDEFGHIJKLMNO'",
+ "- 'PQRSTUVWXYZ[\\]^_'",
+ "- '`abcdefghijklmno'",
+ "- 'pqrstuvwxyz{|}~\177'",
+ "- \200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217",
+ "- \220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237",
+ "- \240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257",
+ "- \260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",
+ "- \300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317",
+ "- \320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337",
+ "- \340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357",
+ "- \360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
+ "..."
+ ],
+ out => [
+ "\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17",
+ "\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37",
+ " !\"#\$%&'()*+,-./",
+ "0123456789:;<=>?",
+ "\@ABCDEFGHIJKLMNO",
+ "PQRSTUVWXYZ[\\]^_",
+ "`abcdefghijklmno",
+ "pqrstuvwxyz{|}~\177",
+ "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217",
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237",
+ "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257",
+ "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317",
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337",
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357",
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
+ ],
+ },
+ { name => 'Quoted hash keys',
+ in => [
+ '---',
+ ' "quoted": Magic!',
+ ' "\n\t": newline, tab',
+ '...',
+ ],
+ out => {
+ quoted => 'Magic!',
+ "\n\t" => 'newline, tab',
+ },
+ },
+ { name => 'Empty',
+ in => [],
+ out => undef,
+ },
+ );
+
+ plan tests => @SCHEDULE * 5;
+}
+
+sub iter {
+ my $ar = shift;
+ return sub {
+ return shift @$ar;
+ };
+}
+
+for my $test (@SCHEDULE) {
+ my $name = $test->{name};
+ ok my $yaml = TAP::Parser::YAMLish::Reader->new, "$name: Created";
+ isa_ok $yaml, 'TAP::Parser::YAMLish::Reader';
+
+ my $source = join( "\n", @{ $test->{in} } ) . "\n";
+
+ my $iter = iter( $test->{in} );
+ my $got = eval { $yaml->read($iter) };
+
+ my $raw = $yaml->get_raw;
+
+ if ( my $err = $test->{error} ) {
+ unless ( like $@, $err, "$name: Error message" ) {
+ diag "Error: $@\n";
+ }
+ ok !$got, "$name: No result";
+ pass;
+ }
+ else {
+ my $want = $test->{out};
+ unless ( ok !$@, "$name: No error" ) {
+ diag "Error: $@\n";
+ }
+ is_deeply $got, $want, "$name: Result matches";
+ is $raw, $source, "$name: Captured source matches";
+ }
+}