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