Upgrade to Test-Harness-3.08
[p5sagit/p5-mst-13.2.git] / lib / Test / Harness.pm
CommitLineData
a0d0e21e 1package Test::Harness;
2
3c87ea76 3require 5.00405;
b965d173 4
760ac839 5use strict;
6
b965d173 7use constant IS_WIN32 => ( $^O =~ /^(MS)?Win32$/ );
8use constant IS_VMS => ( $^O eq 'VMS' );
9
10use TAP::Harness ();
11use TAP::Parser::Aggregator ();
12use TAP::Parser::Source::Perl ();
ca09b021 13
b965d173 14use Config;
15use Exporter;
16
17# TODO: Emulate at least some of these
e4fc8a1e 18use vars qw(
b965d173 19 $VERSION
20 @ISA @EXPORT @EXPORT_OK
21 $Verbose $Switches $Debug
22 $verbose $switches $debug
23 $Columns
53bc175b 24 $Color
b965d173 25 $Directives
26 $Timer
27 $Strap
28 $has_time_hires
e4fc8a1e 29);
30
b965d173 31# $ML $Last_ML_Print
32
43ef773b 33BEGIN {
5b1ebecd 34 eval q{use Time::HiRes 'time'};
43ef773b 35 $has_time_hires = !$@;
36}
37
e4fc8a1e 38=head1 NAME
39
40Test::Harness - Run Perl standard test scripts with statistics
41
42=head1 VERSION
43
41d86c6b 44Version 3.08
e4fc8a1e 45
46=cut
47
41d86c6b 48$VERSION = '3.08';
4633a7c4 49
9c5c68c8 50# Backwards compatibility for exportable variable names.
5c0604c3 51*verbose = *Verbose;
52*switches = *Switches;
e4fc8a1e 53*debug = *Debug;
9c5c68c8 54
b965d173 55$ENV{HARNESS_ACTIVE} = 1;
c0c1f8c2 56$ENV{HARNESS_VERSION} = $VERSION;
f19ae7a7 57
13287dd5 58END {
b965d173 59
13287dd5 60 # For VMS.
61 delete $ENV{HARNESS_ACTIVE};
c0c1f8c2 62 delete $ENV{HARNESS_VERSION};
13287dd5 63}
64
b965d173 65@ISA = ('Exporter');
9c5c68c8 66@EXPORT = qw(&runtests);
20f9f807 67@EXPORT_OK = qw(&execute_tests $verbose $switches);
4633a7c4 68
b965d173 69$Verbose = $ENV{HARNESS_VERBOSE} || 0;
70$Debug = $ENV{HARNESS_DEBUG} || 0;
5b1ebecd 71$Switches = '-w';
b965d173 72$Columns = $ENV{HARNESS_COLUMNS} || $ENV{COLUMNS} || 80;
73$Columns--; # Some shells have trouble with a full line of text.
74$Timer = $ENV{HARNESS_TIMER} || 0;
53bc175b 75$Color = $ENV{HARNESS_COLOR} || 0;
b82fa0b7 76
b82fa0b7 77=head1 SYNOPSIS
78
79 use Test::Harness;
80
81 runtests(@test_files);
82
83=head1 DESCRIPTION
a0d0e21e 84
b965d173 85Although, for historical reasons, the L<Test::Harness> distribution
86takes its name from this module it now exists only to provide
87L<TAP::Harness> with an interface that is somewhat backwards compatible
88with L<Test::Harness> 2.xx. If you're writing new code consider using
89L<TAP::Harness> directly instead.
b82fa0b7 90
b965d173 91Emulation is provided for C<runtests> and C<execute_tests> but the
92pluggable 'Straps' interface that previous versions of L<Test::Harness>
93supported is not reproduced here. Straps is now available as a stand
94alone module: L<Test::Harness::Straps>.
b82fa0b7 95
b965d173 96See L<TAP::Parser> for the main documentation for this distribution.
13287dd5 97
b965d173 98=head1 FUNCTIONS
13287dd5 99
b965d173 100The following functions are available.
13287dd5 101
b965d173 102=head2 runtests( @test_files )
13287dd5 103
b965d173 104This runs all the given I<@test_files> and divines whether they passed
105or failed based on their output to STDOUT (details above). It prints
106out each individual test which failed along with a summary report and
107a how long it all took.
13287dd5 108
b965d173 109It returns true if everything was ok. Otherwise it will C<die()> with
110one of the messages in the DIAGNOSTICS section.
13287dd5 111
b965d173 112=cut
13287dd5 113
b965d173 114sub _has_taint {
115 my $test = shift;
116 return TAP::Parser::Source::Perl->get_taint(
117 TAP::Parser::Source::Perl->shebang($test) );
118}
13287dd5 119
b965d173 120sub _aggregate {
121 my ( $harness, $aggregate, @tests ) = @_;
13287dd5 122
b965d173 123 # Don't propagate to our children
124 local $ENV{HARNESS_OPTIONS};
13287dd5 125
b965d173 126 if (IS_VMS) {
43ef773b 127
b965d173 128 # Jiggery pokery doesn't appear to work on VMS - so disable it
129 # pending investigation.
53bc175b 130 _aggregate_tests( $harness, $aggregate, @tests );
b965d173 131 }
132 else {
133 my $path_sep = $Config{path_sep};
134 my $path_pat = qr{$path_sep};
135 my @extra_inc = _filtered_inc();
136
137 # Supply -I switches in taint mode
138 $harness->callback(
139 parser_args => sub {
140 my ( $args, $test ) = @_;
141 if ( _has_taint( $test->[0] ) ) {
142 push @{ $args->{switches} }, map {"-I$_"} _filtered_inc();
143 }
144 }
145 );
43ef773b 146
b965d173 147 my $previous = $ENV{PERL5LIB};
148 local $ENV{PERL5LIB};
13287dd5 149
b965d173 150 if ($previous) {
151 push @extra_inc, split( $path_pat, $previous );
152 }
13287dd5 153
b965d173 154 if (@extra_inc) {
155 $ENV{PERL5LIB} = join( $path_sep, @extra_inc );
156 }
b82fa0b7 157
53bc175b 158 _aggregate_tests( $harness, $aggregate, @tests );
b965d173 159 }
160}
b82fa0b7 161
53bc175b 162sub _aggregate_tests {
163 my ( $harness, $aggregate, @tests ) = @_;
164 $aggregate->start();
165 $harness->aggregate_tests( $aggregate, @tests );
166 $aggregate->stop();
167
168}
169
b965d173 170sub runtests {
171 my @tests = @_;
b82fa0b7 172
b965d173 173 # shield against -l
174 local ( $\, $, );
b82fa0b7 175
b965d173 176 my $harness = _new_harness();
177 my $aggregate = TAP::Parser::Aggregator->new();
b82fa0b7 178
b965d173 179 _aggregate( $harness, $aggregate, @tests );
b82fa0b7 180
b965d173 181 $harness->formatter->summary($aggregate);
b82fa0b7 182
b965d173 183 my $total = $aggregate->total;
184 my $passed = $aggregate->passed;
185 my $failed = $aggregate->failed;
b82fa0b7 186
b965d173 187 my @parsers = $aggregate->parsers;
b82fa0b7 188
b965d173 189 my $num_bad = 0;
190 for my $parser (@parsers) {
191 $num_bad++ if $parser->has_problems;
192 }
b82fa0b7 193
b965d173 194 die(sprintf(
195 "Failed %d/%d test programs. %d/%d subtests failed.\n",
196 $num_bad, scalar @parsers, $failed, $total
197 )
198 ) if $num_bad;
b82fa0b7 199
b965d173 200 return $total && $total == $passed;
201}
b82fa0b7 202
b965d173 203sub _canon {
204 my @list = sort { $a <=> $b } @_;
205 my @ranges = ();
206 my $count = scalar @list;
207 my $pos = 0;
208
209 while ( $pos < $count ) {
210 my $end = $pos + 1;
211 $end++ while $end < $count && $list[$end] <= $list[ $end - 1 ] + 1;
212 push @ranges, ( $end == $pos + 1 )
213 ? $list[$pos]
214 : join( '-', $list[$pos], $list[ $end - 1 ] );
215 $pos = $end;
216 }
b82fa0b7 217
b965d173 218 return join( ' ', @ranges );
219}
b82fa0b7 220
b965d173 221sub _new_harness {
41d86c6b 222 my $sub_args = shift || {};
b82fa0b7 223
b965d173 224 if ( defined( my $env_sw = $ENV{HARNESS_PERL_SWITCHES} ) ) {
225 $Switches .= ' ' . $env_sw if ( length($env_sw) );
226 }
b82fa0b7 227
b965d173 228 # This is a bit crufty. The switches have all been joined into a
229 # single string so we have to try and recover them.
230 my ( @lib, @switches );
231 for my $opt ( split( /\s+(?=-)/, $Switches ) ) {
232 if ( $opt =~ /^ -I (.*) $ /x ) {
233 push @lib, $1;
234 }
235 else {
236 push @switches, $opt;
237 }
238 }
b82fa0b7 239
b965d173 240 # Do things the old way on VMS...
241 push @lib, _filtered_inc() if IS_VMS;
242
53bc175b 243 # If $Verbose isn't numeric default to 1. This helps core.
244 my $verbosity = ( $Verbose ? ( $Verbose !~ /\d/ ) ? 1 : $Verbose : 0 );
245
b965d173 246 my $args = {
247 timer => $Timer,
248 directives => $Directives,
249 lib => \@lib,
250 switches => \@switches,
53bc175b 251 color => $Color,
252 verbosity => $verbosity,
b965d173 253 };
254
41d86c6b 255 $args->{stdout} = $sub_args->{out}
256 if exists $sub_args->{out};
257
b965d173 258 if ( defined( my $env_opt = $ENV{HARNESS_OPTIONS} ) ) {
259 for my $opt ( split /:/, $env_opt ) {
260 if ( $opt =~ /^j(\d*)$/ ) {
261 $args->{jobs} = $1 || 9;
262 }
263 elsif ( $opt eq 'f' ) {
264 $args->{fork} = 1;
265 }
53bc175b 266 elsif ( $opt eq 'c' ) {
267 $args->{color} = 1;
268 }
b965d173 269 else {
270 die "Unknown HARNESS_OPTIONS item: $opt\n";
271 }
272 }
273 }
b82fa0b7 274
b965d173 275 return TAP::Harness->new($args);
276}
b82fa0b7 277
b965d173 278# Get the parts of @INC which are changed from the stock list AND
279# preserve reordering of stock directories.
280sub _filtered_inc {
281 my @inc = grep { !ref } @INC; #28567
b82fa0b7 282
b965d173 283 if (IS_VMS) {
b82fa0b7 284
b965d173 285 # VMS has a 255-byte limit on the length of %ENV entries, so
286 # toss the ones that involve perl_root, the install location
287 @inc = grep !/perl_root/i, @inc;
b82fa0b7 288
b965d173 289 }
290 elsif (IS_WIN32) {
b82fa0b7 291
b965d173 292 # Lose any trailing backslashes in the Win32 paths
293 s/[\\\/+]$// foreach @inc;
294 }
b82fa0b7 295
b965d173 296 my @default_inc = _default_inc();
b82fa0b7 297
b965d173 298 my @new_inc;
299 my %seen;
300 for my $dir (@inc) {
301 next if $seen{$dir}++;
17a79f5b 302
b965d173 303 if ( $dir eq ( $default_inc[0] || '' ) ) {
304 shift @default_inc;
305 }
306 else {
307 push @new_inc, $dir;
308 }
9c5c68c8 309
b965d173 310 shift @default_inc while @default_inc and $seen{ $default_inc[0] };
311 }
b82fa0b7 312
b965d173 313 return @new_inc;
314}
9c5c68c8 315
b965d173 316{
b82fa0b7 317
b965d173 318 # Cache this to avoid repeatedly shelling out to Perl.
319 my @inc;
b82fa0b7 320
b965d173 321 sub _default_inc {
322 return @inc if @inc;
323 my $perl = $ENV{HARNESS_PERL} || $^X;
324 chomp( @inc = `$perl -le "print join qq[\\n], \@INC"` );
325 return @inc;
d1ef75db 326 }
b82fa0b7 327}
328
b965d173 329sub _check_sequence {
330 my @list = @_;
331 my $prev;
332 while ( my $next = shift @list ) {
333 return if defined $prev && $next <= $prev;
334 $prev = $next;
335 }
2fe373ce 336
b965d173 337 return 1;
2fe373ce 338}
339
b965d173 340sub execute_tests {
341 my %args = @_;
b82fa0b7 342
41d86c6b 343 my $harness = _new_harness( \%args );
b965d173 344 my $aggregate = TAP::Parser::Aggregator->new();
345
346 my %tot = (
347 bonus => 0,
348 max => 0,
349 ok => 0,
350 bad => 0,
351 good => 0,
352 files => 0,
353 tests => 0,
354 sub_skipped => 0,
355 todo => 0,
356 skipped => 0,
357 bench => undef,
358 );
359
360 # Install a callback so we get to see any plans the
361 # harness executes.
362 $harness->callback(
363 made_parser => sub {
364 my $parser = shift;
365 $parser->callback(
366 plan => sub {
367 my $plan = shift;
368 if ( $plan->directive eq 'SKIP' ) {
369 $tot{skipped}++;
370 }
371 }
372 );
373 }
374 );
375
376 _aggregate( $harness, $aggregate, @{ $args{tests} } );
377
378 $tot{bench} = $aggregate->elapsed;
379 my @tests = $aggregate->descriptions;
380
381 # TODO: Work out the circumstances under which the files
382 # and tests totals can differ.
383 $tot{files} = $tot{tests} = scalar @tests;
384
385 my %failedtests = ();
386 my %todo_passed = ();
387
388 for my $test (@tests) {
389 my ($parser) = $aggregate->parsers($test);
390
391 my @failed = $parser->failed;
392
393 my $wstat = $parser->wait;
394 my $estat = $parser->exit;
395 my $planned = $parser->tests_planned;
396 my @errors = $parser->parse_errors;
397 my $passed = $parser->passed;
398 my $actual_passed = $parser->actual_passed;
399
400 my $ok_seq = _check_sequence( $parser->actual_passed );
401
402 # Duplicate exit, wait status semantics of old version
403 $estat ||= '' unless $wstat;
404 $wstat ||= '';
405
406 $tot{max} += ( $planned || 0 );
407 $tot{bonus} += $parser->todo_passed;
408 $tot{ok} += $passed > $actual_passed ? $passed : $actual_passed;
409 $tot{sub_skipped} += $parser->skipped;
410 $tot{todo} += $parser->todo;
411
412 if ( @failed || $estat || @errors ) {
413 $tot{bad}++;
414
415 my $huh_planned = $planned ? undef : '??';
416 my $huh_errors = $ok_seq ? undef : '??';
417
418 $failedtests{$test} = {
419 'canon' => $huh_planned
420 || $huh_errors
421 || _canon(@failed)
422 || '??',
423 'estat' => $estat,
424 'failed' => $huh_planned
425 || $huh_errors
426 || scalar @failed,
427 'max' => $huh_planned || $planned,
428 'name' => $test,
429 'wstat' => $wstat
430 };
431 }
432 else {
433 $tot{good}++;
434 }
b82fa0b7 435
b965d173 436 my @todo = $parser->todo_passed;
437 if (@todo) {
438 $todo_passed{$test} = {
439 'canon' => _canon(@todo),
440 'estat' => $estat,
441 'failed' => scalar @todo,
442 'max' => scalar $parser->todo,
443 'name' => $test,
444 'wstat' => $wstat
445 };
446 }
447 }
b82fa0b7 448
b965d173 449 return ( \%tot, \%failedtests, \%todo_passed );
9c5c68c8 450}
451
20f9f807 452=head2 execute_tests( tests => \@test_files, out => \*FH )
b82fa0b7 453
20f9f807 454Runs all the given C<@test_files> (just like C<runtests()>) but
455doesn't generate the final report. During testing, progress
456information will be written to the currently selected output
457filehandle (usually C<STDOUT>), or to the filehandle given by the
458C<out> parameter. The I<out> is optional.
b82fa0b7 459
20f9f807 460Returns a list of two values, C<$total> and C<$failed>, describing the
461results. C<$total> is a hash ref summary of all the tests run. Its
462keys and values are this:
b82fa0b7 463
464 bonus Number of individual todo tests unexpectedly passed
465 max Number of individual tests ran
466 ok Number of individual tests passed
467 sub_skipped Number of individual tests skipped
2fe373ce 468 todo Number of individual todo tests
b82fa0b7 469
470 files Number of test files ran
471 good Number of test files passed
472 bad Number of test files failed
473 tests Number of test files originally given
474 skipped Number of test files skipped
475
e4fc8a1e 476If C<< $total->{bad} == 0 >> and C<< $total->{max} > 0 >>, you've
477got a successful test.
b82fa0b7 478
20f9f807 479C<$failed> is a hash ref of all the test scripts that failed. Each key
b82fa0b7 480is the name of a test script, each value is another hash representing
481how that script failed. Its keys are these:
9c5c68c8 482
b82fa0b7 483 name Name of the test which failed
484 estat Script's exit value
485 wstat Script's wait status
486 max Number of individual tests
487 failed Number which failed
b82fa0b7 488 canon List of tests which failed (as string).
489
e4fc8a1e 490C<$failed> should be empty if everything passed.
b82fa0b7 491
b82fa0b7 492=cut
493
b82fa0b7 4941;
495__END__
9c5c68c8 496
cb1a09d0 497=head1 EXPORT
498
b965d173 499C<&runtests> is exported by C<Test::Harness> by default.
cb1a09d0 500
20f9f807 501C<&execute_tests>, C<$verbose>, C<$switches> and C<$debug> are
502exported upon request.
9c5c68c8 503
b965d173 504=head1 ENVIRONMENT VARIABLES THAT TAP::HARNESS::COMPATIBLE SETS
c0c1f8c2 505
b965d173 506C<Test::Harness> sets these before executing the individual tests.
9b0ceca9 507
37ce32a7 508=over 4
509
356733da 510=item C<HARNESS_ACTIVE>
37ce32a7 511
c0c1f8c2 512This is set to a true value. It allows the tests to determine if they
513are being executed through the harness or by any other means.
514
515=item C<HARNESS_VERSION>
516
b965d173 517This is the version of C<Test::Harness>.
c0c1f8c2 518
519=back
520
521=head1 ENVIRONMENT VARIABLES THAT AFFECT TEST::HARNESS
522
523=over 4
37ce32a7 524
ea5423ed 525=item C<HARNESS_TIMER>
526
527Setting this to true will make the harness display the number of
528milliseconds each test took. You can also use F<prove>'s C<--timer>
529switch.
530
356733da 531=item C<HARNESS_VERBOSE>
37ce32a7 532
b965d173 533If true, C<Test::Harness> will output the verbose results of running
5b1ebecd 534its tests. Setting C<$Test::Harness::verbose> will override this,
535or you can use the C<-v> switch in the F<prove> utility.
536
b965d173 537=item C<HARNESS_OPTIONS>
5b1ebecd 538
b965d173 539Provide additional options to the harness. Currently supported options are:
5b1ebecd 540
b965d173 541=over
5b1ebecd 542
b965d173 543=item C<< j<n> >>
5b1ebecd 544
b965d173 545Run <n> (default 9) parallel jobs.
b82fa0b7 546
b965d173 547=item C<< f >>
37ce32a7 548
b965d173 549Use forked parallelism.
b82fa0b7 550
b965d173 551=back
cf2ab31a 552
b965d173 553Multiple options may be separated by colons:
cf2ab31a 554
b965d173 555 HARNESS_OPTIONS=j9:f make test
cf2ab31a 556
b965d173 557=back
cf2ab31a 558
b965d173 559=head1 SEE ALSO
b82fa0b7 560
b965d173 561L<TAP::Harness>
cb1a09d0 562
563=head1 BUGS
564
20f9f807 565Please report any bugs or feature requests to
566C<bug-test-harness at rt.cpan.org>, or through the web interface at
b965d173 567L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness>. I will be
568notified, and then you'll automatically be notified of progress on your bug
569as I make changes.
e4fc8a1e 570
571=head1 AUTHORS
572
b965d173 573Andy Armstrong C<< <andy@hexten.net> >>
3c87ea76 574
b965d173 575L<Test::Harness> (on which this module is based) has this attribution:
e4fc8a1e 576
b965d173 577 Either Tim Bunce or Andreas Koenig, we don't know. What we know for
578 sure is, that it was inspired by Larry Wall's F<TEST> script that came
579 with perl distributions for ages. Numerous anonymous contributors
580 exist. Andreas Koenig held the torch for many years, and then
581 Michael G Schwern.
e4fc8a1e 582
b965d173 583=head1 LICENCE AND COPYRIGHT
e4fc8a1e 584
53bc175b 585Copyright (c) 2007-2008, Andy Armstrong C<< <andy@hexten.net> >>. All rights reserved.
e4fc8a1e 586
b965d173 587This module is free software; you can redistribute it and/or
588modify it under the same terms as Perl itself. See L<perlartistic>.
e4fc8a1e 589