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