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