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