cpan/Test-Harness/t/nested.t Test::Harness test
cpan/Test-Harness/t/nofork-mux.t Test::Harness test
cpan/Test-Harness/t/nofork.t Test::Harness test
-cpan/Test-Harness/t/nowarn.t
cpan/Test-Harness/t/object.t Test::Harness test
cpan/Test-Harness/t/parser-config.t Test::Harness test
cpan/Test-Harness/t/parser-subclass.t Test::Harness test
'Test::Harness' => {
'MAINTAINER' => 'andya',
- 'DISTRIBUTION' => 'OVID/Test-Harness-3.26.tar.gz',
+ 'DISTRIBUTION' => 'OVID/Test-Harness-3.28.tar.gz',
'FILES' => q[cpan/Test-Harness],
'EXCLUDED' => [
qr{^examples/},
Revision history for Test-Harness
+3.28 2013-05-02
+ - Bugfix: Fix taint failures on Windows (Jan Dubois)
+
+3.27 2013-04-30
+ - Dramatically reduce memory usage (Nick Clark, RT #84939)
+ - Store test_num (in Grammar.pm) as a number instead of a string.
+ Reduces memory usage (Nick Clark, RT #84939)
+ - PERL5LIB is always propogated to a test's @INC, even with taint more
+ (Schwern, RT #84377)
+
3.26 2013-01-16
- Renamed env.opts.t to env_opts.t (for VMS)
- Skipped some TAP::Formatter::HTML tests due to this bug: #82738
t/nested.t
t/nofork-mux.t
t/nofork.t
-t/nowarn.t
t/object.t
t/parse.t
t/parser-config.t
t/compat/060-version.t
t/compat/base.t
t/compat/callback.t
-t/compat/env.opts.t
t/compat/env.t
t/compat/failure.t
t/compat/from_line.t
t/nested.t
t/nofork-mux.t
t/nofork.t
-t/nowarn.t
t/object.t
t/parse.t
t/parser-config.t
(default)
--nocount Disable the X/Y test count.
-D --dry Dry run. Show test that would have run.
- --ext Set the extension for tests (default '.t')
-f, --failures Show failed tests.
-o, --comments Show comments.
--ignore-exit Ignore exit status from test scripts.
-M Load a module.
-e, --exec Interpreter to run the tests ('' for compiled
tests.)
+ --ext Set the extension for tests (default '.t')
--harness Define test harness to use. See TAP::Harness.
--formatter Result formatter to use. See FORMATTERS.
--source Load and/or configure a SourceHandler. See
-j, --jobs N Run N test jobs in parallel (try 9.)
--state=opts Control prove's persistent state.
--rc=rcfile Process options from rcfile
+ --rules Rules for parallel vs sequential processing.
=head1 NOTES
$ prove -b --state=hot --state=all,save
+=head2 --rules
+
+The C<--rules> option is used to control which tests are run sequentially and
+which are run in parallel, if the C<--jobs> option is specified. The option may
+be specified multiple times, and the order matters.
+
+The most practical use is likely to specify that some tests are not
+"parallel-ready". Since mentioning a file with --rules doens't cause it to
+selected to run as a test, you can "set and forget" some rules preferences in
+your .proverc file. Then you'll be able to take maximum advantage of the
+performance benefits of parallel testing, while some exceptions are still run
+in parallel.
+
+=head3 --rules examples
+
+ # All tests are allowed to run in parallel, except those starting with "p"
+ --rules='seq=t/p*.t' --rules='par=**'
+
+ # All tests must run in sequence except those starting with "p", which should be run parallel
+ --rules='par=t/p*.t'
+
+=head3 --rules resolution
+
+=over4
+
+=item * By default, all tests are eligible to be run in parallel. Specifying any of your own rules removes this one.
+
+=item * "First match wins". The first rule that matches a test will be the one that applies.
+
+=item * Any test which does not match a rule will be run in sequence at the end of the run.
+
+=item * The existence of a rule does not imply selecting a test. You must still specify the tests to run.
+
+=item * Specifying a rule to allow tests to run in parallel does not make the run in parallel. You still need specify the number of parallel C<jobs> in your Harness object.
+
+=back
+
+=head3 --rules Glob-style pattern matching
+
+We implement our own glob-style pattern matching for --rules. Here are the
+supported patterns:
+
+ ** is any number of characters, including /, within a pathname
+ * is zero or more characters within a filename/directory name
+ ? is exactly one character within a filename/directory name
+ {foo,bar,baz} is any of foo, bar or baz.
+ \ is an escape character
+
+=head3 More advance specifications for parallel vs sequence run rules
+
+If you need more advanced management of what runs in parallel vs in sequence, see
+the associated 'rules' documentation in L<TAP::Harness> and L<TAP::Parser::Scheduler>.
+If what's possible directly through C<prove> is not sufficient, you can write your own
+harness to access these features directly.
+
=head2 @INC
prove introduces a separation between "options passed to the perl which
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 SYNOPSIS
# Re-run failed tests
- $ prove --state=fail,save -rbv
+ $ prove --state=failed,save -rbv
=cut
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 SYNOPSIS
# Re-run failed tests
- $ prove --state=fail,save -rbv
+ $ prove --state=failed,save -rbv
=cut
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 SYNOPSIS
# Re-run failed tests
- $ prove --state=fail,save -rbv
+ $ prove --state=failed,save -rbv
=cut
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
use constant GOT_TIME_HIRES => do {
eval 'use Time::HiRes qw(time);';
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 METHODS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
$ENV{HARNESS_ACTIVE} = 1;
$ENV{HARNESS_VERSION} = $VERSION;
=item * C<rules>
-A reference to a hash of rules that control which tests may be
-executed in parallel. This is an experimental feature and the
-interface may change.
-
- $harness->rules(
- { par => [
- { seq => '../ext/DB_File/t/*' },
- { seq => '../ext/IO_Compress_Zlib/t/*' },
- { seq => '../lib/CPANPLUS/*' },
- { seq => '../lib/ExtUtils/t/*' },
- '*'
- ]
- }
- );
+A reference to a hash of rules that control which tests may be executed in
+parallel. If no rules are declared, all tests are eligible for being run in
+parallel. Here some simple examples. For the full details of the data structure
+and the related glob-style pattern matching, see
+L<TAP::Parser::Scheduler/"Rules data structure">.
+
+ # Run all tests in sequence, except those starting with "p"
+ $harness->rules({
+ par => 't/p*.t'
+ });
+
+ # Run all tests in parallel, except those starting with "p"
+ $harness->rules({
+ seq => [
+ { seq => 't/p*.t' },
+ { par => '**' },
+ ],
+ });
+
+ # Run some startup tests in sequence, then some parallel tests than some
+ # teardown tests in sequence.
+ $harness->rules({
+ seq => [
+ { seq => 't/startup/*.t' },
+ { par => ['t/a/*.t','t/b/*.t','t/c/*.t'], }
+ { seq => 't/shutdown/*.t' },
+ ],
+
+ });
+
+This is an experimental feature and the interface may change.
=item * C<stdout>
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
my $DEFAULT_TAP_VERSION = 12;
my $MAX_TAP_VERSION = 13;
=cut
-sub passed { @{ shift->{passed} } }
+sub passed {
+ return @{ $_[0]->{passed} }
+ if ref $_[0]->{passed};
+ return wantarray ? 1 .. $_[0]->{passed} : $_[0]->{passed};
+}
=head3 C<failed>
=cut
-sub actual_passed { @{ shift->{actual_passed} } }
+sub actual_passed {
+ return @{ $_[0]->{actual_passed} }
+ if ref $_[0]->{actual_passed};
+ return wantarray ? 1 .. $_[0]->{actual_passed} : $_[0]->{actual_passed};
+}
*actual_ok = \&actual_passed;
=head3 C<actual_ok>
}
$self->is_good_plan(0) unless defined $self->is_good_plan;
+
+ unless ( $self->parse_errors ) {
+ # Optimise storage where possible
+ if ( $self->tests_run == @{$self->{passed}} ) {
+ $self->{passed} = $self->tests_run;
+ }
+ if ( $self->tests_run == @{$self->{actual_passed}} ) {
+ $self->{actual_passed} = $self->tests_run;
+ }
+ }
+
return $self;
}
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
my ( $self, $line, $ok, $num, $desc, $dir, $explanation ) = @_;
return {
ok => $ok,
- test_num => $num,
+
+ # forcing this to be an integer (and not a string) reduces memory
+ # consumption. RT #84939
+ test_num => ( defined $num ? 0 + $num : undef ),
description => _trim($desc),
directive => ( defined $dir ? uc $dir : '' ),
explanation => _trim($explanation),
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head2 DESCRIPTION
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head3 C<new>
- my $sched = TAP::Parser::Scheduler->new;
+ my $sched = TAP::Parser::Scheduler->new(tests => \@tests);
+ my $sched = TAP::Parser::Scheduler->new(
+ tests => [ ['t/test_name.t','Test Description'], ... ],
+ rules => \%rules,
+ );
+
+Given 'tests' and optional 'rules' as input, returns a new
+C<TAP::Parser::Scheduler> object. Each member of C<@tests> should be either a
+a test file name, or a two element arrayref, where the first element is a test
+file name, and the second element is a test description. By default, we'll use
+the test name as the description.
+
+The optional C<rules> attribute provides direction on which tests should be run
+in parallel and which should be run sequentially. If no rule data structure is
+provided, a default data structure is used which makes every test eligible to
+be run in parallel:
+
+ { par => '**' },
+
+The rules data structure is documented more in the next section.
+
+=head2 Rules data structure
+
+The "C<rules>" data structure is the the heart of the scheduler. It allows you
+to express simple rules like "run all tests in sequence" or "run all tests in
+parallel except these five tests.". However, the rules structure also supports
+glob-style pattern matching and recursive definitions, so you can also express
+arbitarily complicated patterns.
+
+The rule must only have one top level key: either 'par' for "parallel" or 'seq'
+for "sequence".
+
+Values must be either strings with possible glob-style matching, or arrayrefs
+of strings or hashrefs which follow this pattern recursively.
+
+Every element in an arrayref directly below a 'par' key is eligible to be run
+in parallel, while vavalues directly below a 'seq' key must be run in sequence.
+
+=head3 Rules examples
+
+Here are some examples:
+
+ # All tests be run in parallel (the default rule)
+ { par => '**' },
+
+ # Run all tests in sequence, except those starting with "p"
+ { par => 't/p*.t' },
+
+ # Run all tests in parallel, except those starting with "p"
+ {
+ seq => [
+ { seq => 't/p*.t' },
+ { par => '**' },
+ ],
+ }
+
+ # Run some startup tests in sequence, then some parallel tests than some
+ # teardown tests in sequence.
+ {
+ seq => [
+ { seq => 't/startup/*.t' },
+ { par => ['t/a/*.t','t/b/*.t','t/c/*.t'], }
+ { seq => 't/shutdown/*.t' },
+ ],
+ },
+
-Returns a new C<TAP::Parser::Scheduler> object.
+=head3 Rules resolution
+
+=over4
+
+=item * By default, all tests are eligible to be run in parallel. Specifying any of your own rules removes this one.
+
+=item * "First match wins". The first rule that matches a test will be the one that applies.
+
+=item * Any test which does not match a rule will be run in sequence at the end of the run.
+
+=item * The existence of a rule does not imply selecting a test. You must still specify the tests to run.
+
+=item * Specifying a rule to allow tests to run in parallel does not make the run in parallel. You still need specify the number of parallel C<jobs> in your Harness object.
+
+=back
+
+=head3 Glob-style pattern matching for rules
+
+We implement our own glob-style pattern matching. Here are the patterns it supports:
+
+ ** is any number of characters, including /, within a pathname
+ * is zero or more characters within a filename/directory name
+ ? is exactly one character within a filename/directory name
+ {foo,bar,baz} is any of foo, bar or baz.
+ \ is an escape character
=cut
sub _set_rules {
my ( $self, $rules, $tests ) = @_;
+
+ # Convert all incoming tests to job objects.
+ # If no test description is provided use the file name as the description.
my @tests = map { TAP::Parser::Scheduler::Job->new(@$_) }
map { 'ARRAY' eq ref $_ ? $_ : [ $_, $_ ] } @$tests;
my $schedule = $self->_rule_clause( $rules, \@tests );
return @match;
}
+=head2 Instance Methods
+
=head3 C<get_all>
Get a list of all remaining tests.
=head3 C<get_job>
-Return the next available job or C<undef> if none are available. Returns
-a C<TAP::Parser::Scheduler::Spinner> if the scheduler still has pending
-jobs but none are available to run right now.
+Return the next available job as L<TAP::Parser::Scheduler::Job> object or
+C<undef> if none are available. Returns a L<TAP::Parser::Scheduler::Spinner> if
+the scheduler still has pending jobs but none are available to run right now.
=cut
=head3 C<as_string>
Return a human readable representation of the scheduling tree.
+For example:
+
+ my @tests = (qw{
+ t/startup/foo.t
+ t/shutdown/foo.t
+
+ t/a/foo.t t/b/foo.t t/c/foo.t t/d/foo.t
+ });
+ my $sched = TAP::Parser::Scheduler->new(
+ tests => \@tests,
+ rules => {
+ seq => [
+ { seq => 't/startup/*.t' },
+ { par => ['t/a/*.t','t/b/*.t','t/c/*.t'] },
+ { seq => 't/shutdown/*.t' },
+ ],
+ },
+ );
+
+Produces:
+
+ par:
+ seq:
+ par:
+ seq:
+ par:
+ seq:
+ 't/startup/foo.t'
+ par:
+ seq:
+ 't/a/foo.t'
+ seq:
+ 't/b/foo.t'
+ seq:
+ 't/c/foo.t'
+ par:
+ seq:
+ 't/shutdown/foo.t'
+ 't/d/foo.t'
+
=cut
+
sub as_string {
my $self = shift;
return $self->_as_string( $self->{schedule} );
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head3 C<new>
my $job = TAP::Parser::Scheduler::Job->new(
- $name, $desc
+ $filename, $description
);
-Returns a new C<TAP::Parser::Scheduler::Job> object.
+Given the filename and description of a test as scalars, returns a new
+L<TAP::Parser::Scheduler::Job> object.
=cut
}, $class;
}
+=head2 Instance Methods
+
=head3 C<on_finish>
-Register a closure to be called when this job is destroyed.
+ $self->on_finish(\&method).
+
+Register a closure to be called when this job is destroyed. The callback
+will be passed the C<TAP::Parser::Scheduler::Job> object as it's only argument.
=cut
=head3 C<finish>
-Called when a job is complete to unlock it.
+ $self->finish;
+
+Called when a job is complete to unlock it. If a callback has been registered
+with C<on_finish>, it calls it. Otherwise, it does nothing.
=cut
}
}
+=head2 Attributes
+
+ $self->filename;
+ $self->description;
+ $self->context;
+
+These are all "getters" which return the data set for these attributes during object construction.
+
+
=head3 C<filename>
=head3 C<description>
=head3 C<is_spinner>
+ $self->is_spinner;
+
Returns false indicating that this is a real job rather than a
'spinner'. Spinners are returned when the scheduler still has pending
jobs but can't (because of locking) return one right now.
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
my $job = TAP::Parser::Scheduler::Spinner->new;
-Returns a new C<TAP::Parser::Scheduler::Spinner> object.
+Ignores any arguments and returns a new C<TAP::Parser::Scheduler::Spinner> object.
=cut
sub new { bless {}, shift }
+=head2 Instance Methods
+
=head3 C<is_spinner>
Returns true indicating that is a 'spinner' job. Spinners are returned
sub is_spinner {1}
+=head1 SEE ALSO
+
+L<TAP::Parser::Scheduler>, L<TAP::Parser::Scheduler::Job>
+
+=cut
+
1;
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
$class->_run( $source, $libs, $switches );
}
+
+sub _has_taint_switch {
+ my( $class, $switches ) = @_;
+
+ my $has_taint = grep { $_ eq "-T" || $_ eq "-t" } @{$switches};
+ return $has_taint ? 1 : 0;
+}
+
sub _mangle_switches {
my ( $class, $libs, $switches ) = @_;
# Taint mode ignores environment variables so we must retranslate
# PERL5LIB as -I switches and place PERL5OPT on the command line
# in order that it be seen.
- if ( grep { $_ eq "-T" || $_ eq "-t" } @{$switches} ) {
+ if ( $class->_has_taint_switch($switches) ) {
+ my @perl5lib = split /$Config{path_sep}/, $ENV{PERL5LIB};
return (
$libs,
[ @{$switches},
- $class->_libs2switches($libs),
+ $class->_libs2switches([@$libs, @perl5lib]),
split_shell( $ENV{PERL5OPT} )
],
);
}
sub _iterator_hooks {
- my ( $class, $source, $libs ) = @_;
+ my ( $class, $source, $libs, $switches ) = @_;
my $setup = sub {
- if ( @{$libs} ) {
+ if ( @{$libs} and !$class->_has_taint_switch($switches) ) {
$ENV{PERL5LIB} = join(
$Config{path_sep}, grep {defined} @{$libs},
$ENV{PERL5LIB}
}
};
- # Cargo culted from comments seen elsewhere about VMS / environment
- # variables. I don't know if this is actually necessary.
+ # VMS environment variables aren't guaranteed to reset at the end of
+ # the process, so we need to put PERL5LIB back.
my $previous = $ENV{PERL5LIB};
my $teardown = sub {
if ( defined $previous ) {
my @command = $class->_get_command_for_switches( $source, $switches )
or $class->_croak("No command found!");
- my ( $setup, $teardown ) = $class->_iterator_hooks( $source, $libs );
+ my ( $setup, $teardown ) = $class->_iterator_hooks( $source, $libs, $switches );
return $class->_create_iterator( $source, \@command, $setup, $teardown );
}
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
=head1 SYNOPSIS
use TAP::Object ();
@ISA = 'TAP::Object';
-$VERSION = '3.26';
+$VERSION = '3.28';
# TODO:
# Handle blessed object syntax
=head1 VERSION
-Version 3.26
+Version 3.28
=head1 SYNOPSIS
use TAP::Object ();
@ISA = 'TAP::Object';
-$VERSION = '3.26';
+$VERSION = '3.28';
my $ESCAPE_CHAR = qr{ [ \x00-\x1f \" ] }x;
my $ESCAPE_KEY = qr{ (?: ^\W ) | $ESCAPE_CHAR }x;
=head1 VERSION
-Version 3.26
+Version 3.28
=head1 SYNOPSIS
=head1 VERSION
-Version 3.26
+Version 3.28
=cut
-$VERSION = '3.26';
+$VERSION = '3.28';
# Backwards compatibility for exportable variable names.
*verbose = *Verbose;
$Verbose = $ENV{HARNESS_VERBOSE} || 0;
$Debug = $ENV{HARNESS_DEBUG} || 0;
-$Switches = '';
+$Switches = '-w';
$Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
$Columns--; # Some shells have trouble with a full line of text.
$Timer = $ENV{HARNESS_TIMER} || 0;
=over 4
+=item C<HARNESS_PERL_SWITCHES>
+
+Setting this adds perl command line switches to each test file run.
+
+For example, C<HARNESS_PERL_SWITCHES=-T> will turn on taint mode.
+C<HARNESS_PERL_SWITCHES=-MDevel::Cover> will run C<Devel::Cover> for
+each test.
+
+C<-w> is always set. You can turn this off in the test with C<BEGIN {
+$^W = 0 }>.
+
=item C<HARNESS_TIMER>
Setting this to true will make the harness display the number of
my $test_template = <<'END';
#!/usr/bin/perl %s
-use Test::More tests => 2;
+use Test::More tests => 1;
is $INC[0], "wibble", 'basic order of @INC preserved' or diag "\@INC: @INC";
-like $ENV{PERL5LIB}, qr{wibble};
END
+++ /dev/null
-#!perl
-
-use Test::More tests => 1;
-
-# Make sure that warnings are only enabled if we enable them
-# specifically.
-ok !$^W, 'warnings disabled';
-
-# vim:ts=2:sw=2:et:ft=perl
-
unshift @INC, 't/lib';
}
-# Test that options in PERL5OPT are propogated to tainted tests
+# Test that environment options are propagated to tainted tests
use strict;
-use Test::More ( $^O eq 'VMS' ? ( skip_all => 'VMS' ) : ( tests => 1 ) );
+use Test::More ( $^O eq 'VMS' ? ( skip_all => 'VMS' ) : ( tests => 2 ) );
use Config;
use TAP::Parser;
END
}
+
+# Check that PERL5LIB is propagated to -T.
+{
+ my $sentinel_dir = 'i/do/not/exist';
+ local $ENV{PERL5LIB} = join $Config{path_sep}, $ENV{PERL5LIB}, $sentinel_dir;
+ run_test_file(sprintf <<'END', $sentinel_dir);
+#!/usr/bin/perl -T
+
+print "1..1\n";
+my $ok = grep { $_ eq '%s' } @INC;
+print $ok ? "ok 1\n" : "not ok 1\n";
+END
+}
+
1;
=item *
-L<XXX> has been upgraded from version A.xx to B.yy.
+Test::Harness has been upgraded from version 3.26 to 3.28
+
+Memory usage is dramatically reduced. t/harness now uses about 10% of the
+memory used by 3.26 and earlier.
+
+C<PERL5LIB> is always propagated to a test's C<@INC>, even under C<-T>.
=back