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