7 use constant IS_WIN32 => ( $^O =~ /^(MS)?Win32$/ );
8 use constant IS_VMS => ( $^O eq 'VMS' );
11 use TAP::Parser::Aggregator ();
12 use TAP::Parser::Source::Perl ();
17 # TODO: Emulate at least some of these
20 @ISA @EXPORT @EXPORT_OK
21 $Verbose $Switches $Debug
22 $verbose $switches $debug
33 eval q{use Time::HiRes 'time'};
34 $has_time_hires = !$@;
39 Test::Harness - Run Perl standard test scripts with statistics
49 # Backwards compatibility for exportable variable names.
51 *switches = *Switches;
54 $ENV{HARNESS_ACTIVE} = 1;
55 $ENV{HARNESS_VERSION} = $VERSION;
60 delete $ENV{HARNESS_ACTIVE};
61 delete $ENV{HARNESS_VERSION};
65 @EXPORT = qw(&runtests);
66 @EXPORT_OK = qw(&execute_tests $verbose $switches);
68 $Verbose = $ENV{HARNESS_VERBOSE} || 0;
69 $Debug = $ENV{HARNESS_DEBUG} || 0;
71 $Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
72 $Columns--; # Some shells have trouble with a full line of text.
73 $Timer = $ENV{HARNESS_TIMER} || 0;
79 runtests(@test_files);
83 Although, for historical reasons, the L<Test::Harness> distribution
84 takes its name from this module it now exists only to provide
85 L<TAP::Harness> with an interface that is somewhat backwards compatible
86 with L<Test::Harness> 2.xx. If you're writing new code consider using
87 L<TAP::Harness> directly instead.
89 Emulation is provided for C<runtests> and C<execute_tests> but the
90 pluggable 'Straps' interface that previous versions of L<Test::Harness>
91 supported is not reproduced here. Straps is now available as a stand
92 alone module: L<Test::Harness::Straps>.
94 See L<TAP::Parser> for the main documentation for this distribution.
98 The following functions are available.
100 =head2 runtests( @test_files )
102 This runs all the given I<@test_files> and divines whether they passed
103 or failed based on their output to STDOUT (details above). It prints
104 out each individual test which failed along with a summary report and
105 a how long it all took.
107 It returns true if everything was ok. Otherwise it will C<die()> with
108 one of the messages in the DIAGNOSTICS section.
114 return TAP::Parser::Source::Perl->get_taint(
115 TAP::Parser::Source::Perl->shebang($test) );
119 my ( $harness, $aggregate, @tests ) = @_;
121 # Don't propagate to our children
122 local $ENV{HARNESS_OPTIONS};
126 # Jiggery pokery doesn't appear to work on VMS - so disable it
127 # pending investigation.
128 $harness->aggregate_tests( $aggregate, @tests );
131 my $path_sep = $Config{path_sep};
132 my $path_pat = qr{$path_sep};
133 my @extra_inc = _filtered_inc();
135 # Supply -I switches in taint mode
138 my ( $args, $test ) = @_;
139 if ( _has_taint( $test->[0] ) ) {
140 push @{ $args->{switches} }, map {"-I$_"} _filtered_inc();
145 my $previous = $ENV{PERL5LIB};
146 local $ENV{PERL5LIB};
149 push @extra_inc, split( $path_pat, $previous );
153 $ENV{PERL5LIB} = join( $path_sep, @extra_inc );
156 $harness->aggregate_tests( $aggregate, @tests );
166 my $harness = _new_harness();
167 my $aggregate = TAP::Parser::Aggregator->new();
169 _aggregate( $harness, $aggregate, @tests );
171 $harness->formatter->summary($aggregate);
173 my $total = $aggregate->total;
174 my $passed = $aggregate->passed;
175 my $failed = $aggregate->failed;
177 my @parsers = $aggregate->parsers;
180 for my $parser (@parsers) {
181 $num_bad++ if $parser->has_problems;
185 "Failed %d/%d test programs. %d/%d subtests failed.\n",
186 $num_bad, scalar @parsers, $failed, $total
190 return $total && $total == $passed;
194 my @list = sort { $a <=> $b } @_;
196 my $count = scalar @list;
199 while ( $pos < $count ) {
201 $end++ while $end < $count && $list[$end] <= $list[ $end - 1 ] + 1;
202 push @ranges, ( $end == $pos + 1 )
204 : join( '-', $list[$pos], $list[ $end - 1 ] );
208 return join( ' ', @ranges );
213 if ( defined( my $env_sw = $ENV{HARNESS_PERL_SWITCHES} ) ) {
214 $Switches .= ' ' . $env_sw if ( length($env_sw) );
217 # This is a bit crufty. The switches have all been joined into a
218 # single string so we have to try and recover them.
219 my ( @lib, @switches );
220 for my $opt ( split( /\s+(?=-)/, $Switches ) ) {
221 if ( $opt =~ /^ -I (.*) $ /x ) {
225 push @switches, $opt;
229 # Do things the old way on VMS...
230 push @lib, _filtered_inc() if IS_VMS;
234 directives => $Directives,
236 switches => \@switches,
237 verbosity => $Verbose,
240 if ( defined( my $env_opt = $ENV{HARNESS_OPTIONS} ) ) {
241 for my $opt ( split /:/, $env_opt ) {
242 if ( $opt =~ /^j(\d*)$/ ) {
243 $args->{jobs} = $1 || 9;
245 elsif ( $opt eq 'f' ) {
249 die "Unknown HARNESS_OPTIONS item: $opt\n";
254 return TAP::Harness->new($args);
257 # Get the parts of @INC which are changed from the stock list AND
258 # preserve reordering of stock directories.
260 my @inc = grep { !ref } @INC; #28567
264 # VMS has a 255-byte limit on the length of %ENV entries, so
265 # toss the ones that involve perl_root, the install location
266 @inc = grep !/perl_root/i, @inc;
271 # Lose any trailing backslashes in the Win32 paths
272 s/[\\\/+]$// foreach @inc;
275 my @default_inc = _default_inc();
280 next if $seen{$dir}++;
282 if ( $dir eq ( $default_inc[0] || '' ) ) {
289 shift @default_inc while @default_inc and $seen{ $default_inc[0] };
297 # Cache this to avoid repeatedly shelling out to Perl.
302 my $perl = $ENV{HARNESS_PERL} || $^X;
303 chomp( @inc = `$perl -le "print join qq[\\n], \@INC"` );
308 sub _check_sequence {
311 while ( my $next = shift @list ) {
312 return if defined $prev && $next <= $prev;
322 # TODO: Handle out option
324 my $harness = _new_harness();
325 my $aggregate = TAP::Parser::Aggregator->new();
341 # Install a callback so we get to see any plans the
349 if ( $plan->directive eq 'SKIP' ) {
357 _aggregate( $harness, $aggregate, @{ $args{tests} } );
359 $tot{bench} = $aggregate->elapsed;
360 my @tests = $aggregate->descriptions;
362 # TODO: Work out the circumstances under which the files
363 # and tests totals can differ.
364 $tot{files} = $tot{tests} = scalar @tests;
366 my %failedtests = ();
367 my %todo_passed = ();
369 for my $test (@tests) {
370 my ($parser) = $aggregate->parsers($test);
372 my @failed = $parser->failed;
374 my $wstat = $parser->wait;
375 my $estat = $parser->exit;
376 my $planned = $parser->tests_planned;
377 my @errors = $parser->parse_errors;
378 my $passed = $parser->passed;
379 my $actual_passed = $parser->actual_passed;
381 my $ok_seq = _check_sequence( $parser->actual_passed );
383 # Duplicate exit, wait status semantics of old version
384 $estat ||= '' unless $wstat;
387 $tot{max} += ( $planned || 0 );
388 $tot{bonus} += $parser->todo_passed;
389 $tot{ok} += $passed > $actual_passed ? $passed : $actual_passed;
390 $tot{sub_skipped} += $parser->skipped;
391 $tot{todo} += $parser->todo;
393 if ( @failed || $estat || @errors ) {
396 my $huh_planned = $planned ? undef : '??';
397 my $huh_errors = $ok_seq ? undef : '??';
399 $failedtests{$test} = {
400 'canon' => $huh_planned
405 'failed' => $huh_planned
408 'max' => $huh_planned || $planned,
417 my @todo = $parser->todo_passed;
419 $todo_passed{$test} = {
420 'canon' => _canon(@todo),
422 'failed' => scalar @todo,
423 'max' => scalar $parser->todo,
430 return ( \%tot, \%failedtests, \%todo_passed );
433 =head2 execute_tests( tests => \@test_files, out => \*FH )
435 Runs all the given C<@test_files> (just like C<runtests()>) but
436 doesn't generate the final report. During testing, progress
437 information will be written to the currently selected output
438 filehandle (usually C<STDOUT>), or to the filehandle given by the
439 C<out> parameter. The I<out> is optional.
441 Returns a list of two values, C<$total> and C<$failed>, describing the
442 results. C<$total> is a hash ref summary of all the tests run. Its
443 keys and values are this:
445 bonus Number of individual todo tests unexpectedly passed
446 max Number of individual tests ran
447 ok Number of individual tests passed
448 sub_skipped Number of individual tests skipped
449 todo Number of individual todo tests
451 files Number of test files ran
452 good Number of test files passed
453 bad Number of test files failed
454 tests Number of test files originally given
455 skipped Number of test files skipped
457 If C<< $total->{bad} == 0 >> and C<< $total->{max} > 0 >>, you've
458 got a successful test.
460 C<$failed> is a hash ref of all the test scripts that failed. Each key
461 is the name of a test script, each value is another hash representing
462 how that script failed. Its keys are these:
464 name Name of the test which failed
465 estat Script's exit value
466 wstat Script's wait status
467 max Number of individual tests
468 failed Number which failed
469 canon List of tests which failed (as string).
471 C<$failed> should be empty if everything passed.
480 C<&runtests> is exported by C<Test::Harness> by default.
482 C<&execute_tests>, C<$verbose>, C<$switches> and C<$debug> are
483 exported upon request.
485 =head1 ENVIRONMENT VARIABLES THAT TAP::HARNESS::COMPATIBLE SETS
487 C<Test::Harness> sets these before executing the individual tests.
491 =item C<HARNESS_ACTIVE>
493 This is set to a true value. It allows the tests to determine if they
494 are being executed through the harness or by any other means.
496 =item C<HARNESS_VERSION>
498 This is the version of C<Test::Harness>.
502 =head1 ENVIRONMENT VARIABLES THAT AFFECT TEST::HARNESS
506 =item C<HARNESS_TIMER>
508 Setting this to true will make the harness display the number of
509 milliseconds each test took. You can also use F<prove>'s C<--timer>
512 =item C<HARNESS_VERBOSE>
514 If true, C<Test::Harness> will output the verbose results of running
515 its tests. Setting C<$Test::Harness::verbose> will override this,
516 or you can use the C<-v> switch in the F<prove> utility.
518 =item C<HARNESS_OPTIONS>
520 Provide additional options to the harness. Currently supported options are:
526 Run <n> (default 9) parallel jobs.
530 Use forked parallelism.
534 Multiple options may be separated by colons:
536 HARNESS_OPTIONS=j9:f make test
546 Please report any bugs or feature requests to
547 C<bug-test-harness at rt.cpan.org>, or through the web interface at
548 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness>. I will be
549 notified, and then you'll automatically be notified of progress on your bug
554 Andy Armstrong C<< <andy@hexten.net> >>
556 L<Test::Harness> (on which this module is based) has this attribution:
558 Either Tim Bunce or Andreas Koenig, we don't know. What we know for
559 sure is, that it was inspired by Larry Wall's F<TEST> script that came
560 with perl distributions for ages. Numerous anonymous contributors
561 exist. Andreas Koenig held the torch for many years, and then
564 =head1 LICENCE AND COPYRIGHT
566 Copyright (c) 2007, Andy Armstrong C<< <andy@hexten.net> >>. All rights reserved.
568 This module is free software; you can redistribute it and/or
569 modify it under the same terms as Perl itself. See L<perlartistic>.