patch to fix mingw32 build under USE_IMP_SYS (from Benjamin Stuhl);
[p5sagit/p5-mst-13.2.git] / lib / Test / Harness.pm
CommitLineData
a0d0e21e 1package Test::Harness;
2
17f410f9 3use 5.005_64;
a0d0e21e 4use Exporter;
5use Benchmark;
4633a7c4 6use Config;
6c31b336 7use FileHandle;
760ac839 8use strict;
9
17f410f9 10our($VERSION, $verbose, $switches, $have_devel_corestack, $curtest,
11 @ISA, @EXPORT, @EXPORT_OK);
c0ee6f5c 12$have_devel_corestack = 0;
4633a7c4 13
0d0c0d42 14$VERSION = "1.1604";
9b0ceca9 15
f19ae7a7 16$ENV{HARNESS_ACTIVE} = 1;
17
9b0ceca9 18# Some experimental versions of OS/2 build have broken $?
19my $ignore_exitcode = $ENV{HARNESS_IGNORE_EXITCODE};
20
17a79f5b 21my $files_in_dir = $ENV{HARNESS_FILELEAK_IN_DIR};
22
9b0ceca9 23my $tests_skipped = 0;
24my $subtests_skipped = 0;
4633a7c4 25
c07a80fd 26@ISA=('Exporter');
cb1a09d0 27@EXPORT= qw(&runtests);
a0d0e21e 28@EXPORT_OK= qw($verbose $switches);
29
760ac839 30format STDOUT_TOP =
31Failed Test Status Wstat Total Fail Failed List of failed
fb73857a 32-------------------------------------------------------------------------------
760ac839 33.
34
35format STDOUT =
fb73857a 36@<<<<<<<<<<<<<< @>> @>>>> @>>>> @>>> ^##.##% ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
760ac839 37{ $curtest->{name},
38 $curtest->{estat},
39 $curtest->{wstat},
40 $curtest->{max},
41 $curtest->{failed},
42 $curtest->{percent},
43 $curtest->{canon}
44}
fb73857a 45~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
46 $curtest->{canon}
760ac839 47.
48
c07a80fd 49
6c31b336 50$verbose = 0;
51$switches = "-w";
a0d0e21e 52
17a79f5b 53sub globdir { opendir DIRH, shift; my @f = readdir DIRH; closedir DIRH; @f }
54
a0d0e21e 55sub runtests {
56 my(@tests) = @_;
57 local($|) = 1;
7b13a3f5 58 my($test,$te,$ok,$next,$max,$pct,$totok,$totbonus,@failed,%failedtests);
6c31b336 59 my $totmax = 0;
60 my $files = 0;
a0d0e21e 61 my $bad = 0;
62 my $good = 0;
63 my $total = @tests;
774d564b 64
65 # pass -I flags to children
81ff29e3 66 my $old5lib = $ENV{PERL5LIB};
774d564b 67
1250aba5 68 # VMS has a 255-byte limit on the length of %ENV entries, so
69 # toss the ones that involve perl_root, the install location
70 # for VMS
71 my $new5lib;
72 if ($^O eq 'VMS') {
73 $new5lib = join($Config{path_sep}, grep {!/perl_root/i;} @INC);
74 $switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g;
75 }
76 else {
77 $new5lib = join($Config{path_sep}, @INC);
78 }
79
80 local($ENV{'PERL5LIB'}) = $new5lib;
a0d0e21e 81
17a79f5b 82 my @dir_files = globdir $files_in_dir if defined $files_in_dir;
a0d0e21e 83 my $t_start = new Benchmark;
84 while ($test = shift(@tests)) {
c07a80fd 85 $te = $test;
86 chop($te);
68dc0745 87 if ($^O eq 'VMS') { $te =~ s/^.*\.t\./[.t./; }
45c0de28 88 my $blank = (' ' x 77);
0d0c0d42 89 my $leader = "$te" . '.' x (20 - length($te));
90 my $ml = "";
23c4718a 91 $ml = "\r$blank\r$leader"
92 if -t STDOUT and not $ENV{HARNESS_NOTTY} and not $verbose;
0d0c0d42 93 print $leader;
6c31b336 94 my $fh = new FileHandle;
aa689395 95 $fh->open($test) or print "can't open $test. $!\n";
96 my $first = <$fh>;
97 my $s = $switches;
da4582cd 98 $s .= join " ", q[ "-T"], map {qq["-I$_"]} @INC
99 if $first =~ /^#!.*\bperl.*-\w*T/;
aa689395 100 $fh->close or print "can't close $test. $!\n";
9636a016 101 my $cmd = ($ENV{'HARNESS_COMPILE_TEST'})
102 ? "./perl -I../lib ../utils/perlcc $test "
103 . "-run 2>> ./compilelog |"
104 : "$^X $s $test|";
a5077310 105 $cmd = "MCR $cmd" if $^O eq 'VMS';
aa689395 106 $fh->open($cmd) or print "can't run $test. $!\n";
c07a80fd 107 $ok = $next = $max = 0;
108 @failed = ();
7b13a3f5 109 my %todo = ();
110 my $bonus = 0;
fac76ed7 111 my $skipped = 0;
c854dc73 112 my $skip_reason;
c07a80fd 113 while (<$fh>) {
6c31b336 114 if( $verbose ){
c07a80fd 115 print $_;
116 }
7b13a3f5 117 if (/^1\.\.([0-9]+) todo([\d\s]+)\;/) {
118 $max = $1;
119 for (split(/\s+/, $2)) { $todo{$_} = 1; }
120 $totmax += $max;
121 $files++;
122 $next = 1;
45c0de28 123 } elsif (/^1\.\.([0-9]+)(\s*\#\s*[Ss]kip\S*(?>\s+)(.+))?/) {
c0ee6f5c 124 $max = $1;
125 $totmax += $max;
126 $files++;
127 $next = 1;
45c0de28 128 $skip_reason = $3 if not $max and defined $3;
c0ee6f5c 129 } elsif ($max && /^(not\s+)?ok\b/) {
130 my $this = $next;
131 if (/^not ok\s*(\d*)/){
132 $this = $1 if $1 > 0;
23c4718a 133 print "${ml}NOK $this" if $ml;
7b13a3f5 134 if (!$todo{$this}) {
135 push @failed, $this;
136 } else {
137 $ok++;
138 $totok++;
139 }
c854dc73 140 } elsif (/^ok\s*(\d*)(\s*\#\s*[Ss]kip\S*(?:(?>\s+)(.+))?)?/) {
c0ee6f5c 141 $this = $1 if $1 > 0;
45c0de28 142 print "${ml}ok $this/$max" if $ml;
c0ee6f5c 143 $ok++;
144 $totok++;
fac76ed7 145 $skipped++ if defined $2;
c854dc73 146 my $reason;
147 $reason = 'unknown reason' if defined $2;
148 $reason = $3 if defined $3;
149 if (defined $reason and defined $skip_reason) {
150 # print "was: '$skip_reason' new '$reason'\n";
151 $skip_reason = 'various reasons'
152 if $skip_reason ne $reason;
153 } elsif (defined $reason) {
154 $skip_reason = $reason;
155 }
7b13a3f5 156 $bonus++, $totbonus++ if $todo{$this};
c07a80fd 157 }
c0ee6f5c 158 if ($this > $next) {
159 # warn "Test output counter mismatch [test $this]\n";
160 # no need to warn probably
161 push @failed, $next..$this-1;
162 } elsif ($this < $next) {
163 #we have seen more "ok" lines than the number suggests
164 warn "Confused test output: test $this answered after test ", $next-1, "\n";
165 $next = $this;
166 }
167 $next = $this + 1;
c07a80fd 168 }
169 }
6c31b336 170 $fh->close; # must close to reap child resource values
9b0ceca9 171 my $wstatus = $ignore_exitcode ? 0 : $?; # Can trust $? ?
395b061e 172 my $estatus;
173 $estatus = ($^O eq 'VMS'
68dc0745 174 ? eval 'use vmsish "status"; $estatus = $?'
175 : $wstatus >> 8);
176 if ($wstatus) {
aa689395 177 my ($failed, $canon, $percent) = ('??', '??');
0d0c0d42 178 printf "${ml}dubious\n\tTest returned status $estatus (wstat %d, 0x%x)\n",
fb73857a 179 $wstatus,$wstatus;
68dc0745 180 print "\t\t(VMS status is $estatus)\n" if $^O eq 'VMS';
c0ee6f5c 181 if (corestatus($wstatus)) { # until we have a wait module
182 if ($have_devel_corestack) {
183 Devel::CoreStack::stack($^X);
184 } else {
185 print "\ttest program seems to have generated a core\n";
186 }
187 }
188 $bad++;
aa689395 189 if ($max) {
190 if ($next == $max + 1 and not @failed) {
191 print "\tafter all the subtests completed successfully\n";
192 $percent = 0;
193 $failed = 0; # But we do not set $canon!
194 } else {
195 push @failed, $next..$max;
196 $failed = @failed;
89d3b7e2 197 (my $txt, $canon) = canonfailed($max,$skipped,@failed);
aa689395 198 $percent = 100*(scalar @failed)/$max;
199 print "DIED. ",$txt;
200 }
201 }
202 $failedtests{$test} = { canon => $canon, max => $max || '??',
203 failed => $failed,
204 name => $test, percent => $percent,
760ac839 205 estat => $estatus, wstat => $wstatus,
206 };
c0ee6f5c 207 } elsif ($ok == $max && $next == $max+1) {
7b13a3f5 208 if ($max and $skipped + $bonus) {
209 my @msg;
45c0de28 210 push(@msg, "$skipped/$max skipped: $skip_reason")
7b13a3f5 211 if $skipped;
45c0de28 212 push(@msg, "$bonus/$max unexpectedly succeeded")
7b13a3f5 213 if $bonus;
45c0de28 214 print "${ml}ok, ".join(', ', @msg)."\n";
fac76ed7 215 } elsif ($max) {
45c0de28 216 print "${ml}ok\n";
217 } elsif (defined $skip_reason) {
218 print "skipped: $skip_reason\n";
219 $tests_skipped++;
c0ee6f5c 220 } else {
45c0de28 221 print "skipped test on this platform\n";
9b0ceca9 222 $tests_skipped++;
c0ee6f5c 223 }
c07a80fd 224 $good++;
6c31b336 225 } elsif ($max) {
226 if ($next <= $max) {
227 push @failed, $next..$max;
228 }
c07a80fd 229 if (@failed) {
89d3b7e2 230 my ($txt, $canon) = canonfailed($max,$skipped,@failed);
760ac839 231 print $txt;
232 $failedtests{$test} = { canon => $canon, max => $max,
233 failed => scalar @failed,
234 name => $test, percent => 100*(scalar @failed)/$max,
235 estat => '', wstat => '',
236 };
c07a80fd 237 } else {
c0ee6f5c 238 print "Don't know which tests failed: got $ok ok, expected $max\n";
760ac839 239 $failedtests{$test} = { canon => '??', max => $max,
240 failed => '??',
241 name => $test, percent => undef,
242 estat => '', wstat => '',
243 };
c07a80fd 244 }
245 $bad++;
6c31b336 246 } elsif ($next == 0) {
247 print "FAILED before any test output arrived\n";
248 $bad++;
760ac839 249 $failedtests{$test} = { canon => '??', max => '??',
250 failed => '??',
251 name => $test, percent => undef,
252 estat => '', wstat => '',
253 };
6c31b336 254 }
9b0ceca9 255 $subtests_skipped += $skipped;
17a79f5b 256 if (defined $files_in_dir) {
257 my @new_dir_files = globdir $files_in_dir;
258 if (@new_dir_files != @dir_files) {
259 my %f;
260 @f{@new_dir_files} = (1) x @new_dir_files;
261 delete @f{@dir_files};
262 my @f = sort keys %f;
263 print "LEAKED FILES: @f\n";
264 @dir_files = @new_dir_files;
265 }
266 }
a0d0e21e 267 }
268 my $t_total = timediff(new Benchmark, $t_start);
c07a80fd 269
774d564b 270 if ($^O eq 'VMS') {
271 if (defined $old5lib) {
272 $ENV{PERL5LIB} = $old5lib;
b876d4a6 273 } else {
774d564b 274 delete $ENV{PERL5LIB};
275 }
276 }
7b13a3f5 277 my $bonusmsg = '';
278 $bonusmsg = (" ($totbonus subtest".($totbonus>1?'s':'').
279 " UNEXPECTEDLY SUCCEEDED)")
280 if $totbonus;
9b0ceca9 281 if ($tests_skipped) {
c4f6c246 282 $bonusmsg .= ", $tests_skipped test" . ($tests_skipped != 1 ? 's' : '');
283 if ($subtests_skipped) {
284 $bonusmsg .= " and $subtests_skipped subtest"
285 . ($subtests_skipped != 1 ? 's' : '');
286 }
287 $bonusmsg .= ' skipped';
9b0ceca9 288 }
c4f6c246 289 elsif ($subtests_skipped) {
290 $bonusmsg .= ", $subtests_skipped subtest"
291 . ($subtests_skipped != 1 ? 's' : '')
292 . " skipped";
9b0ceca9 293 }
6c31b336 294 if ($bad == 0 && $totmax) {
7b13a3f5 295 print "All tests successful$bonusmsg.\n";
6c31b336 296 } elsif ($total==0){
297 die "FAILED--no tests were run for some reason.\n";
298 } elsif ($totmax==0) {
299 my $blurb = $total==1 ? "script" : "scripts";
c0ee6f5c 300 die "FAILED--$total test $blurb could be run, alas--no output ever seen\n";
c07a80fd 301 } else {
302 $pct = sprintf("%.2f", $good / $total * 100);
6c31b336 303 my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
304 $totmax - $totok, $totmax, 100*$totok/$totmax;
760ac839 305 my $script;
306 for $script (sort keys %failedtests) {
307 $curtest = $failedtests{$script};
308 write;
309 }
b876d4a6 310 if ($bad) {
9b0ceca9 311 $bonusmsg =~ s/^,\s*//;
312 print "$bonusmsg.\n" if $bonusmsg;
6c31b336 313 die "Failed $bad/$total test scripts, $pct% okay.$subpct\n";
c07a80fd 314 }
315 }
5603f27d 316 printf("Files=%d, Tests=%d, %s\n", $files, $totmax, timestr($t_total, 'nop'));
f0a9308e 317
318 return ($bad == 0 && $totmax) ;
c07a80fd 319}
320
aa689395 321my $tried_devel_corestack;
c0ee6f5c 322sub corestatus {
323 my($st) = @_;
324 my($ret);
325
326 eval {require 'wait.ph'};
327 if ($@) {
328 SWITCH: {
329 $ret = ($st & 0200); # Tim says, this is for 90%
330 }
331 } else {
332 $ret = WCOREDUMP($st);
333 }
334
aa689395 335 eval { require Devel::CoreStack; $have_devel_corestack++ }
336 unless $tried_devel_corestack++;
c0ee6f5c 337
338 $ret;
339}
340
c07a80fd 341sub canonfailed ($@) {
89d3b7e2 342 my($max,$skipped,@failed) = @_;
6c31b336 343 my %seen;
344 @failed = sort {$a <=> $b} grep !$seen{$_}++, @failed;
c07a80fd 345 my $failed = @failed;
346 my @result = ();
347 my @canon = ();
348 my $min;
349 my $last = $min = shift @failed;
760ac839 350 my $canon;
c07a80fd 351 if (@failed) {
352 for (@failed, $failed[-1]) { # don't forget the last one
353 if ($_ > $last+1 || $_ == $last) {
354 if ($min == $last) {
355 push @canon, $last;
356 } else {
357 push @canon, "$min-$last";
358 }
359 $min = $_;
360 }
361 $last = $_;
362 }
363 local $" = ", ";
364 push @result, "FAILED tests @canon\n";
760ac839 365 $canon = "@canon";
a0d0e21e 366 } else {
c07a80fd 367 push @result, "FAILED test $last\n";
760ac839 368 $canon = $last;
a0d0e21e 369 }
c07a80fd 370
371 push @result, "\tFailed $failed/$max tests, ";
89d3b7e2 372 push @result, sprintf("%.2f",100*(1-$failed/$max)), "% okay";
373 my $ender = 's' x ($skipped > 1);
374 my $good = $max - $failed - $skipped;
375 my $goodper = sprintf("%.2f",100*($good/$max));
376 push @result, " (-$skipped skipped test$ender: $good okay, $goodper%)" if $skipped;
377 push @result, "\n";
760ac839 378 my $txt = join "", @result;
379 ($txt, $canon);
a0d0e21e 380}
381
3821;
cb1a09d0 383__END__
384
385=head1 NAME
386
387Test::Harness - run perl standard test scripts with statistics
388
389=head1 SYNOPSIS
390
391use Test::Harness;
392
393runtests(@tests);
394
395=head1 DESCRIPTION
396
7b13a3f5 397(By using the L<Test> module, you can write test scripts without
398knowing the exact output this module expects. However, if you need to
399know the specifics, read on!)
400
cb1a09d0 401Perl test scripts print to standard output C<"ok N"> for each single
402test, where C<N> is an increasing sequence of integers. The first line
c0ee6f5c 403output by a standard test script is C<"1..M"> with C<M> being the
cb1a09d0 404number of tests that should be run within the test
c0ee6f5c 405script. Test::Harness::runtests(@tests) runs all the testscripts
cb1a09d0 406named as arguments and checks standard output for the expected
407C<"ok N"> strings.
408
c0ee6f5c 409After all tests have been performed, runtests() prints some
cb1a09d0 410performance statistics that are computed by the Benchmark module.
411
6c31b336 412=head2 The test script output
413
414Any output from the testscript to standard error is ignored and
415bypassed, thus will be seen by the user. Lines written to standard
c0ee6f5c 416output containing C</^(not\s+)?ok\b/> are interpreted as feedback for
417runtests(). All other lines are discarded.
6c31b336 418
419It is tolerated if the test numbers after C<ok> are omitted. In this
420case Test::Harness maintains temporarily its own counter until the
421script supplies test numbers again. So the following test script
422
423 print <<END;
424 1..6
425 not ok
426 ok
427 not ok
428 ok
429 ok
430 END
431
432will generate
433
434 FAILED tests 1, 3, 6
435 Failed 3/6 tests, 50.00% okay
436
437The global variable $Test::Harness::verbose is exportable and can be
c0ee6f5c 438used to let runtests() display the standard output of the script
6c31b336 439without altering the behavior otherwise.
440
fb73857a 441The global variable $Test::Harness::switches is exportable and can be
442used to set perl command line options used for running the test
443script(s). The default value is C<-w>.
444
fac76ed7 445If the standard output line contains substring C< # Skip> (with
446variations in spacing and case) after C<ok> or C<ok NUMBER>, it is
447counted as a skipped test. If the whole testscript succeeds, the
448count of skipped tests is included in the generated output.
449
45c0de28 450C<Test::Harness> reports the text after C< # Skip(whatever)> as a
451reason for skipping. Similarly, one can include a similar explanation
452in a C<1..0> line emitted if the test is skipped completely:
453
454 1..0 # Skipped: no leverage found
455
cb1a09d0 456=head1 EXPORT
457
c0ee6f5c 458C<&runtests> is exported by Test::Harness per default.
cb1a09d0 459
460=head1 DIAGNOSTICS
461
462=over 4
463
464=item C<All tests successful.\nFiles=%d, Tests=%d, %s>
465
466If all tests are successful some statistics about the performance are
467printed.
468
6c31b336 469=item C<FAILED tests %s\n\tFailed %d/%d tests, %.2f%% okay.>
470
471For any single script that has failing subtests statistics like the
472above are printed.
473
474=item C<Test returned status %d (wstat %d)>
475
81ff29e3 476Scripts that return a non-zero exit status, both C<$? E<gt>E<gt> 8> and C<$?> are
6c31b336 477printed in a message similar to the above.
478
479=item C<Failed 1 test, %.2f%% okay. %s>
cb1a09d0 480
6c31b336 481=item C<Failed %d/%d tests, %.2f%% okay. %s>
cb1a09d0 482
483If not all tests were successful, the script dies with one of the
484above messages.
485
486=back
487
9b0ceca9 488=head1 ENVIRONMENT
489
17a79f5b 490Setting C<HARNESS_IGNORE_EXITCODE> makes harness ignore the exit status
9b0ceca9 491of child processes.
492
0d0c0d42 493Setting C<HARNESS_NOTTY> to a true value forces it to behave as though
494STDOUT were not a console. You may need to set this if you don't want
495harness to output more frequent progress messages using carriage returns.
496Some consoles may not handle carriage returns properly (which results
497in a somewhat messy output).
498
9636a016 499Setting C<HARNESS_COMPILE_TEST> to a true value will make harness attempt
500to compile the test using C<perlcc> before running it.
501
17a79f5b 502If C<HARNESS_FILELEAK_IN_DIR> is set to the name of a directory, harness
503will check after each test whether new files appeared in that directory,
504and report them as
505
506 LEAKED FILES: scr.tmp 0 my.db
507
508If relative, directory name is with respect to the current directory at
509the moment runtests() was called. Putting absolute path into
510C<HARNESS_FILELEAK_IN_DIR> may give more predicatable results.
511
f19ae7a7 512Harness sets C<HARNESS_ACTIVE> before executing the individual tests.
513This allows the tests to determine if they are being executed through the
514harness or by any other means.
515
cb1a09d0 516=head1 SEE ALSO
517
7b13a3f5 518L<Test> for writing test scripts and also L<Benchmark> for the
519underlying timing routines.
c07a80fd 520
521=head1 AUTHORS
522
523Either Tim Bunce or Andreas Koenig, we don't know. What we know for
524sure is, that it was inspired by Larry Wall's TEST script that came
b876d4a6 525with perl distributions for ages. Numerous anonymous contributors
526exist. Current maintainer is Andreas Koenig.
cb1a09d0 527
528=head1 BUGS
529
530Test::Harness uses $^X to determine the perl binary to run the tests
6c31b336 531with. Test scripts running via the shebang (C<#!>) line may not be
532portable because $^X is not consistent for shebang scripts across
cb1a09d0 533platforms. This is no problem when Test::Harness is run with an
6c31b336 534absolute path to the perl binary or when $^X can be found in the path.
cb1a09d0 535
536=cut