This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
integrate changes#2978,2979 from mainline
[perl5.git] / lib / Test / Harness.pm
CommitLineData
a0d0e21e
LW
1package Test::Harness;
2
b876d4a6 3BEGIN {require 5.002;}
a0d0e21e
LW
4use Exporter;
5use Benchmark;
4633a7c4 6use Config;
6c31b336 7use FileHandle;
760ac839
LW
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
IZ
14$VERSION = "1.1602";
15
16# Some experimental versions of OS/2 build have broken $?
17my $ignore_exitcode = $ENV{HARNESS_IGNORE_EXITCODE};
18
17a79f5b
IZ
19my $files_in_dir = $ENV{HARNESS_FILELEAK_IN_DIR};
20
9b0ceca9
IZ
21my $tests_skipped = 0;
22my $subtests_skipped = 0;
4633a7c4 23
c07a80fd 24@ISA=('Exporter');
cb1a09d0 25@EXPORT= qw(&runtests);
a0d0e21e
LW
26@EXPORT_OK= qw($verbose $switches);
27
760ac839
LW
28format STDOUT_TOP =
29Failed Test Status Wstat Total Fail Failed List of failed
fb73857a 30-------------------------------------------------------------------------------
760ac839
LW
31.
32
33format STDOUT =
fb73857a 34@<<<<<<<<<<<<<< @>> @>>>> @>>>> @>>> ^##.##% ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
760ac839
LW
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
LW
45.
46
c07a80fd 47
6c31b336
A
48$verbose = 0;
49$switches = "-w";
a0d0e21e 50
17a79f5b
IZ
51sub globdir { opendir DIRH, shift; my @f = readdir DIRH; closedir DIRH; @f }
52
a0d0e21e
LW
53sub runtests {
54 my(@tests) = @_;
55 local($|) = 1;
7b13a3f5 56 my($test,$te,$ok,$next,$max,$pct,$totok,$totbonus,@failed,%failedtests);
6c31b336
A
57 my $totmax = 0;
58 my $files = 0;
a0d0e21e
LW
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
LW
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
EP
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
JP
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
JP
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
JP
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
TB
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;
333fe645 163 (my $txt, $canon) = canonfailed($max,$skipped,@failed);
aa689395 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
LW
171 estat => $estatus, wstat => $wstatus,
172 };
c0ee6f5c 173 } elsif ($ok == $max && $next == $max+1) {
7b13a3f5
JP
174 if ($max and $skipped + $bonus) {
175 my @msg;
333fe645 176 push(@msg, "$skipped/$max subtest".($skipped>1?'s':'')." skipped")
7b13a3f5
JP
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
A
189 } elsif ($max) {
190 if ($next <= $max) {
191 push @failed, $next..$max;
192 }
c07a80fd 193 if (@failed) {
333fe645 194 my ($txt, $canon) = canonfailed($max,$skipped,@failed);
760ac839
LW
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
LW
203 $failedtests{$test} = { canon => '??', max => $max,
204 failed => '??',
205 name => $test, percent => undef,
206 estat => '', wstat => '',
207 };
c07a80fd 208 }
209 $bad++;
6c31b336
A
210 } elsif ($next == 0) {
211 print "FAILED before any test output arrived\n";
212 $bad++;
760ac839
LW
213 $failedtests{$test} = { canon => '??', max => '??',
214 failed => '??',
215 name => $test, percent => undef,
216 estat => '', wstat => '',
217 };
6c31b336 218 }
9b0ceca9 219 $subtests_skipped += $skipped;
17a79f5b
IZ
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
LW
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
JP
241 my $bonusmsg = '';
242 $bonusmsg = (" ($totbonus subtest".($totbonus>1?'s':'').
243 " UNEXPECTEDLY SUCCEEDED)")
244 if $totbonus;
9b0ceca9
IZ
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
A
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
A
264 my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
265 $totmax - $totok, $totmax, 100*$totok/$totmax;
760ac839
LW
266 my $script;
267 for $script (sort keys %failedtests) {
268 $curtest = $failedtests{$script};
269 write;
270 }
b876d4a6 271 if ($bad) {
9b0ceca9
IZ
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 ($@) {
333fe645 303 my($max,$skipped,@failed) = @_;
6c31b336
A
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, ";
333fe645
IZ
333 push @result, sprintf("%.2f",100*(1-$failed/$max)), "% okay";
334 my $ender = 's' x ($skipped > 1);
335 my $good = $max - $failed - $skipped;
336 my $goodper = sprintf("%.2f",100*($good/$max));
337 push @result, " (-$skipped skipped test$ender: $good okay, $goodper%)" if $skipped;
338 push @result, "\n";
760ac839
LW
339 my $txt = join "", @result;
340 ($txt, $canon);
a0d0e21e
LW
341}
342
3431;
cb1a09d0
AD
344__END__
345
346=head1 NAME
347
348Test::Harness - run perl standard test scripts with statistics
349
350=head1 SYNOPSIS
351
352use Test::Harness;
353
354runtests(@tests);
355
356=head1 DESCRIPTION
357
7b13a3f5
JP
358(By using the L<Test> module, you can write test scripts without
359knowing the exact output this module expects. However, if you need to
360know the specifics, read on!)
361
cb1a09d0
AD
362Perl test scripts print to standard output C<"ok N"> for each single
363test, where C<N> is an increasing sequence of integers. The first line
c0ee6f5c 364output by a standard test script is C<"1..M"> with C<M> being the
cb1a09d0 365number of tests that should be run within the test
c0ee6f5c 366script. Test::Harness::runtests(@tests) runs all the testscripts
cb1a09d0
AD
367named as arguments and checks standard output for the expected
368C<"ok N"> strings.
369
c0ee6f5c 370After all tests have been performed, runtests() prints some
cb1a09d0
AD
371performance statistics that are computed by the Benchmark module.
372
6c31b336
A
373=head2 The test script output
374
375Any output from the testscript to standard error is ignored and
376bypassed, thus will be seen by the user. Lines written to standard
c0ee6f5c 377output containing C</^(not\s+)?ok\b/> are interpreted as feedback for
378runtests(). All other lines are discarded.
6c31b336
A
379
380It is tolerated if the test numbers after C<ok> are omitted. In this
381case Test::Harness maintains temporarily its own counter until the
382script supplies test numbers again. So the following test script
383
384 print <<END;
385 1..6
386 not ok
387 ok
388 not ok
389 ok
390 ok
391 END
392
393will generate
394
395 FAILED tests 1, 3, 6
396 Failed 3/6 tests, 50.00% okay
397
398The global variable $Test::Harness::verbose is exportable and can be
c0ee6f5c 399used to let runtests() display the standard output of the script
6c31b336
A
400without altering the behavior otherwise.
401
fb73857a 402The global variable $Test::Harness::switches is exportable and can be
403used to set perl command line options used for running the test
404script(s). The default value is C<-w>.
405
fac76ed7
MB
406If the standard output line contains substring C< # Skip> (with
407variations in spacing and case) after C<ok> or C<ok NUMBER>, it is
408counted as a skipped test. If the whole testscript succeeds, the
409count of skipped tests is included in the generated output.
410
cb1a09d0
AD
411=head1 EXPORT
412
c0ee6f5c 413C<&runtests> is exported by Test::Harness per default.
cb1a09d0
AD
414
415=head1 DIAGNOSTICS
416
417=over 4
418
419=item C<All tests successful.\nFiles=%d, Tests=%d, %s>
420
421If all tests are successful some statistics about the performance are
422printed.
423
6c31b336
A
424=item C<FAILED tests %s\n\tFailed %d/%d tests, %.2f%% okay.>
425
426For any single script that has failing subtests statistics like the
427above are printed.
428
429=item C<Test returned status %d (wstat %d)>
430
81ff29e3 431Scripts that return a non-zero exit status, both C<$? E<gt>E<gt> 8> and C<$?> are
6c31b336
A
432printed in a message similar to the above.
433
434=item C<Failed 1 test, %.2f%% okay. %s>
cb1a09d0 435
6c31b336 436=item C<Failed %d/%d tests, %.2f%% okay. %s>
cb1a09d0
AD
437
438If not all tests were successful, the script dies with one of the
439above messages.
440
441=back
442
9b0ceca9
IZ
443=head1 ENVIRONMENT
444
17a79f5b 445Setting C<HARNESS_IGNORE_EXITCODE> makes harness ignore the exit status
9b0ceca9
IZ
446of child processes.
447
17a79f5b
IZ
448If C<HARNESS_FILELEAK_IN_DIR> is set to the name of a directory, harness
449will check after each test whether new files appeared in that directory,
450and report them as
451
452 LEAKED FILES: scr.tmp 0 my.db
453
454If relative, directory name is with respect to the current directory at
455the moment runtests() was called. Putting absolute path into
456C<HARNESS_FILELEAK_IN_DIR> may give more predicatable results.
457
cb1a09d0
AD
458=head1 SEE ALSO
459
7b13a3f5
JP
460L<Test> for writing test scripts and also L<Benchmark> for the
461underlying timing routines.
c07a80fd 462
463=head1 AUTHORS
464
465Either Tim Bunce or Andreas Koenig, we don't know. What we know for
466sure is, that it was inspired by Larry Wall's TEST script that came
b876d4a6
A
467with perl distributions for ages. Numerous anonymous contributors
468exist. Current maintainer is Andreas Koenig.
cb1a09d0
AD
469
470=head1 BUGS
471
472Test::Harness uses $^X to determine the perl binary to run the tests
6c31b336
A
473with. Test scripts running via the shebang (C<#!>) line may not be
474portable because $^X is not consistent for shebang scripts across
cb1a09d0 475platforms. This is no problem when Test::Harness is run with an
6c31b336 476absolute path to the perl binary or when $^X can be found in the path.
cb1a09d0
AD
477
478=cut