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