# -*- Mode: cperl; cperl-indent-level: 4 -*-
-# $Id: Harness.pm,v 1.11 2001/05/23 18:24:41 schwern Exp $
+# $Id: Harness.pm,v 1.17 2001/09/07 06:20:29 schwern Exp $
package Test::Harness;
$Have_Devel_Corestack = 0;
-$VERSION = "1.21";
+$VERSION = 1.26;
$ENV{HARNESS_ACTIVE} = 1;
It will happen, your tests will fail. After you mop up your ego, you
can begin examining the summary report:
- t/base..............ok
- t/nonumbers.........ok
- t/ok................ok
- t/test-harness......ok
- t/waterloo..........dubious
+ t/base..............ok
+ t/nonumbers.........ok
+ t/ok................ok
+ t/test-harness......ok
+ t/waterloo..........dubious
Test returned status 3 (wstat 768, 0x300)
DIED. FAILED tests 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
Failed 10/20 tests, 50.00% okay
my($tot, $failedtests) = _run_all_tests(@tests);
_show_results($tot, $failedtests);
- my $ok = ($tot->{bad} == 0 && $tot->{max});
+ my $ok = _all_ok($tot);
die q{Assert '$ok xor keys %$failedtests' failed!}
unless $ok xor keys %$failedtests;
=begin _private
+=item B<_all_ok>
+
+ my $ok = _all_ok(\%tot);
+
+Tells you if this test run is overall successful or not.
+
+=cut
+
+sub _all_ok {
+ my($tot) = shift;
+
+ return $tot->{bad} == 0 && ($tot->{max} || $tot->{skipped}) ? 1 : 0;
+}
+
=item B<_globdir>
my @files = _globdir $dir;
max Number of individual tests ran
ok Number of individual tests passed
sub_skipped Number of individual tests skipped
+ todo Number of individual todo tests
files Number of test files ran
good Number of test files passed
good => 0,
tests => scalar @tests,
sub_skipped => 0,
+ todo => 0,
skipped => 0,
- bench => 0
+ bench => 0,
);
# pass -I flags to children
# for VMS
my $new5lib;
if ($^O eq 'VMS') {
- $new5lib = join($Config{path_sep}, grep {!/perl_root/i;} @INC);
- $Switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g;
+ $new5lib = join($Config{path_sep}, grep {!/perl_root/i;} @INC);
+ $Switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g;
}
else {
$new5lib = join($Config{path_sep}, @INC);
my $maxlen = 0;
my $maxsuflen = 0;
foreach (@tests) { # The same code in t/TEST
- my $suf = /\.(\w+)$/ ? $1 : '';
- my $len = length;
- my $suflen = length $suf;
- $maxlen = $len if $len > $maxlen;
- $maxsuflen = $suflen if $suflen > $maxsuflen;
+ my $suf = /\.(\w+)$/ ? $1 : '';
+ my $len = length;
+ my $suflen = length $suf;
+ $maxlen = $len if $len > $maxlen;
+ $maxsuflen = $suflen if $suflen > $maxsuflen;
}
# + 3 : we want three dots between the test name and the "ok"
my $width = $maxlen + 3 - $maxsuflen;
+
foreach my $tfile (@tests) {
my($leader, $ml) = _mk_leader($tfile, $width);
print $leader;
);
my($seen_header, $tests_seen) = (0,0);
- while (<$fh>) {
+ while (<$fh>) {
if( _parse_header($_, \%test, \%tot) ) {
warn "Test header seen twice!\n" if $seen_header;
$tests_seen++;
}
# else, ignore it.
- }
+ }
my($estatus, $wstatus) = _close_fh($fh);
my $allok = $test{ok} == $test{max} && $test{'next'} == $test{max}+1;
- if ($wstatus) {
+ if ($wstatus) {
$failedtests{$tfile} = _dubious_return(\%test, \%tot,
$estatus, $wstatus);
$failedtests{$tfile}{name} = $tfile;
- }
+ }
elsif ($allok) {
- if ($test{max} and $test{skipped} + $test{bonus}) {
- my @msg;
- push(@msg, "$test{skipped}/$test{max} skipped: $test{skip_reason}")
- if $test{skipped};
- push(@msg, "$test{bonus}/$test{max} unexpectedly succeeded")
- if $test{bonus};
- print "$test{ml}ok, ".join(', ', @msg)."\n";
- } elsif ($test{max}) {
- print "$test{ml}ok\n";
- } elsif (defined $test{skip_reason}) {
- print "skipped: $test{skip_reason}\n";
- $tot{skipped}++;
- } else {
- print "skipped test on this platform\n";
- $tot{skipped}++;
- }
- $tot{good}++;
- }
+ if ($test{max} and $test{skipped} + $test{bonus}) {
+ my @msg;
+ push(@msg, "$test{skipped}/$test{max} skipped: $test{skip_reason}")
+ if $test{skipped};
+ push(@msg, "$test{bonus}/$test{max} unexpectedly succeeded")
+ if $test{bonus};
+ print "$test{ml}ok, ".join(', ', @msg)."\n";
+ } elsif ($test{max}) {
+ print "$test{ml}ok\n";
+ } elsif (defined $test{skip_reason}) {
+ print "skipped: $test{skip_reason}\n";
+ $tot{skipped}++;
+ } else {
+ print "skipped test on this platform\n";
+ $tot{skipped}++;
+ }
+ $tot{good}++;
+ }
else {
if ($test{max}) {
if ($test{'next'} <= $test{max}) {
}
}
- $tot{sub_skipped} += $test{skipped};
-
- if (defined $Files_In_Dir) {
- my @new_dir_files = _globdir $Files_In_Dir;
- if (@new_dir_files != @dir_files) {
- my %f;
- @f{@new_dir_files} = (1) x @new_dir_files;
- delete @f{@dir_files};
- my @f = sort keys %f;
- print "LEAKED FILES: @f\n";
- @dir_files = @new_dir_files;
- }
- }
+ $tot{sub_skipped} += $test{skipped};
+
+ if (defined $Files_In_Dir) {
+ my @new_dir_files = _globdir $Files_In_Dir;
+ if (@new_dir_files != @dir_files) {
+ my %f;
+ @f{@new_dir_files} = (1) x @new_dir_files;
+ delete @f{@dir_files};
+ my @f = sort keys %f;
+ print "LEAKED FILES: @f\n";
+ @dir_files = @new_dir_files;
+ }
+ }
}
$tot{bench} = timediff(new Benchmark, $t_start);
if ($^O eq 'VMS') {
- if (defined $old5lib) {
- $ENV{PERL5LIB} = $old5lib;
- } else {
- delete $ENV{PERL5LIB};
- }
+ if (defined $old5lib) {
+ $ENV{PERL5LIB} = $old5lib;
+ } else {
+ delete $ENV{PERL5LIB};
+ }
}
return(\%tot, \%failedtests);
Generates the 't/foo........' $leader for the given $test_file as well
as a similar version which will overwrite the current line (by use of
\r and such). $ml may be empty if Test::Harness doesn't think you're
-on TTY. The width is the width of the "yada/blah..." string.
+on TTY.
+
+The $width is the width of the "yada/blah.." string.
=cut
sub _mk_leader {
- my ($te, $width) = @_;
-
+ my($te, $width) = @_;
+ chomp($te);
$te =~ s/\.\w+$/./;
if ($^O eq 'VMS') { $te =~ s/^.*\.t\./\[.t./s; }
my $pct;
my $bonusmsg = _bonusmsg($tot);
- if ($tot->{bad} == 0 && $tot->{max}) {
-# print "All tests successful$bonusmsg.\n";
- print "All tests successful.\n";
- } elsif ($tot->{tests}==0){
- die "FAILED--no tests were run for some reason.\n";
- } elsif ($tot->{max} == 0) {
- my $blurb = $tot->{tests}==1 ? "script" : "scripts";
- die "FAILED--$tot->{tests} test $blurb could be run, ".
+ if (_all_ok($tot)) {
+ print "All tests successful$bonusmsg.\n";
+ } elsif (!$tot->{tests}){
+ die "FAILED--no tests were run for some reason.\n";
+ } elsif (!$tot->{max}) {
+ my $blurb = $tot->{tests}==1 ? "script" : "scripts";
+ die "FAILED--$tot->{tests} test $blurb could be run, ".
"alas--no output ever seen\n";
} else {
- $pct = sprintf("%.2f", $tot->{good} / $tot->{tests} * 100);
- my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
- $tot->{max} - $tot->{ok}, $tot->{max},
- 100*$tot->{ok}/$tot->{max};
+ $pct = sprintf("%.2f", $tot->{good} / $tot->{tests} * 100);
+ my $percent_ok = 100*$tot->{ok}/$tot->{max};
+ my $subpct = sprintf " %d/%d subtests failed, %.2f%% okay.",
+ $tot->{max} - $tot->{ok}, $tot->{max},
+ $percent_ok;
my($fmt_top, $fmt) = _create_fmts($failedtests);
- # Now write to formats
- for my $script (sort keys %$failedtests) {
- $Curtest = $failedtests->{$script};
- write;
- }
- if ($tot->{bad}) {
- $bonusmsg =~ s/^,\s*//;
- print "$bonusmsg.\n" if $bonusmsg;
- die "Failed $tot->{bad}/$tot->{tests} test scripts, $pct% okay.".
+ # Now write to formats
+ for my $script (sort keys %$failedtests) {
+ $Curtest = $failedtests->{$script};
+ write;
+ }
+ if ($tot->{bad}) {
+ $bonusmsg =~ s/^,\s*//;
+ print "$bonusmsg.\n" if $bonusmsg;
+ die "Failed $tot->{bad}/$tot->{tests} test scripts, $pct% okay.".
"$subpct\n";
- }
+ }
}
printf("Files=%d, Tests=%d, %s\n",
# XXX This is WAY too core specific!
my $cmd = ($ENV{'HARNESS_COMPILE_TEST'})
? "./perl -I../lib ../utils/perlcc $test "
- . "-r 2>> ./compilelog |"
- : "$^X $s $test|";
+ . "-r 2>> ./compilelog |"
+ : "$^X $s $test|";
$cmd = "MCR $cmd" if $^O eq 'VMS';
if( open(PERL, $cmd) ) {
my($line, $test, $tot) = @_;
if ($line =~ /^(not\s+)?ok\b/i) {
- my $this = $test->{'next'} || 1;
+ $test->{'next'} ||= 1;
+ my $this = $test->{'next'};
# "not ok 23"
- if ($line =~ /^(not )?ok\s*(\d*)(\s*#.*)?/) {
- my($not, $tnum, $extra) = ($1, $2, $3);
-
- $this = $tnum if $tnum;
-
- my($type, $reason) = $extra =~ /^\s*#\s*([Ss]kip\S*|TODO)(\s+.+)?/
- if defined $extra;
-
- my($istodo, $isskip);
- if( defined $type ) {
- $istodo = $type =~ /TODO/;
- $isskip = $type =~ /skip/i;
- }
-
- $test->{todo}{$tnum} = 1 if $istodo;
-
- if( $not ) {
- print "$test->{ml}NOK $this" if $test->{ml};
- if (!$test->{todo}{$this}) {
- push @{$test->{failed}}, $this;
- } else {
- $test->{ok}++;
- $tot->{ok}++;
- }
- }
- else {
- print "$test->{ml}ok $this/$test->{max}" if $test->{ml};
- $test->{ok}++;
- $tot->{ok}++;
- $test->{skipped}++ if $isskip;
-
- $reason = '[no reason given]'
- if $isskip and not defined $reason;
- if (defined $reason and defined $test->{skip_reason}) {
- # print "was: '$skip_reason' new '$reason'\n";
- $test->{skip_reason} = 'various reasons'
- if $test->{skip_reason} ne $reason;
- } elsif (defined $reason) {
- $test->{skip_reason} = $reason;
- }
-
- $test->{bonus}++, $tot->{bonus}++ if $test->{todo}{$this};
- }
+ if ($line =~ /^(not )?ok\s*(\d*)[^#]*(\s*#.*)?/) {
+ my($not, $tnum, $extra) = ($1, $2, $3);
+
+ $this = $tnum if $tnum;
+
+ my($type, $reason) = $extra =~ /^\s*#\s*([Ss]kip\S*|TODO)(\s+.+)?/
+ if defined $extra;
+
+ my($istodo, $isskip);
+ if( defined $type ) {
+ $istodo = 1 if $type =~ /TODO/;
+ $isskip = 1 if $type =~ /skip/i;
+ }
+
+ $test->{todo}{$this} = 1 if $istodo;
+
+ $tot->{todo}++ if $test->{todo}{$this};
+
+ if( $not ) {
+ print "$test->{ml}NOK $this" if $test->{ml};
+ if (!$test->{todo}{$this}) {
+ push @{$test->{failed}}, $this;
+ } else {
+ $test->{ok}++;
+ $tot->{ok}++;
+ }
+ }
+ else {
+ print "$test->{ml}ok $this/$test->{max}" if $test->{ml};
+ $test->{ok}++;
+ $tot->{ok}++;
+ $test->{skipped}++ if $isskip;
+
+ $reason = '[no reason given]'
+ if $isskip and not defined $reason;
+ if (defined $reason and defined $test->{skip_reason}) {
+ # print "was: '$skip_reason' new '$reason'\n";
+ $test->{skip_reason} = 'various reasons'
+ if $test->{skip_reason} ne $reason;
+ } elsif (defined $reason) {
+ $test->{skip_reason} = $reason;
+ }
+
+ $test->{bonus}++, $tot->{bonus}++ if $test->{todo}{$this};
+ }
}
# XXX ummm... dunno
elsif ($line =~ /^ok\s*(\d*)\s*\#([^\r]*)$/) { # XXX multiline ok?
}
if ($this > $test->{'next'}) {
- # print "Test output counter mismatch [test $this]\n";
- # no need to warn probably
+ print "Test output counter mismatch [test $this]\n";
push @{$test->{failed}}, $test->{'next'}..$this-1;
}
elsif ($this < $test->{'next'}) {
my $bonusmsg = '';
$bonusmsg = (" ($tot->{bonus} subtest".($tot->{bonus} > 1 ? 's' : '').
- " UNEXPECTEDLY SUCCEEDED)")
- if $tot->{bonus};
+ " UNEXPECTEDLY SUCCEEDED)")
+ if $tot->{bonus};
if ($tot->{skipped}) {
- $bonusmsg .= ", $tot->{skipped} test"
+ $bonusmsg .= ", $tot->{skipped} test"
. ($tot->{skipped} != 1 ? 's' : '');
- if ($tot->{sub_skipped}) {
- $bonusmsg .= " and $tot->{sub_skipped} subtest"
- . ($tot->{sub_skipped} != 1 ? 's' : '');
- }
- $bonusmsg .= ' skipped';
+ if ($tot->{sub_skipped}) {
+ $bonusmsg .= " and $tot->{sub_skipped} subtest"
+ . ($tot->{sub_skipped} != 1 ? 's' : '');
+ }
+ $bonusmsg .= ' skipped';
}
elsif ($tot->{sub_skipped}) {
- $bonusmsg .= ", $tot->{sub_skipped} subtest"
- . ($tot->{sub_skipped} != 1 ? 's' : '')
- . " skipped";
+ $bonusmsg .= ", $tot->{sub_skipped} subtest"
+ . ($tot->{sub_skipped} != 1 ? 's' : '')
+ . " skipped";
}
return $bonusmsg;
close($fh); # must close to reap child resource values
- my $wstatus = $Ignore_Exitcode ? 0 : $?; # Can trust $? ?
+ my $wstatus = $Ignore_Exitcode ? 0 : $?; # Can trust $? ?
my $estatus;
$estatus = ($^O eq 'VMS'
? eval 'use vmsish "status"; $estatus = $?'
my $s = $Switches;
$s .= " $ENV{'HARNESS_PERL_SWITCHES'}"
if exists $ENV{'HARNESS_PERL_SWITCHES'};
- $s .= join " ", q[ "-T"], map {qq["-I$_"]} @INC
- if $first =~ /^#!.*\bperl.*-\w*T/;
+ $s .= join " ", qq[ "-$1"], map {qq["-I$_"]} @INC
+ if $first =~ /^#!.*\bperl.*-\w*([tT])/;
close(TEST) or print "can't close $test. $!\n";
if ($test->{'next'} == $test->{max} + 1 and not @{$test->{failed}}) {
print "\tafter all the subtests completed successfully\n";
$percent = 0;
- $failed = 0; # But we do not set $canon!
+ $failed = 0; # But we do not set $canon!
}
else {
push @{$test->{failed}}, $test->{'next'}..$test->{max};
my $fmt_top = "format STDOUT_TOP =\n"
. sprintf("%-${max_namelen}s", $failed_str)
. $middle_str
- . $list_str . "\n"
- . "-" x $Columns
- . "\n.\n";
+ . $list_str . "\n"
+ . "-" x $Columns
+ . "\n.\n";
my $fmt = "format STDOUT =\n"
- . "@" . "<" x ($max_namelen - 1)
+ . "@" . "<" x ($max_namelen - 1)
. " @>> @>>>> @>>>> @>>> ^##.##% "
- . "^" . "<" x ($list_len - 1) . "\n"
- . '{ $Curtest->{name}, $Curtest->{estat},'
- . ' $Curtest->{wstat}, $Curtest->{max},'
- . ' $Curtest->{failed}, $Curtest->{percent},'
- . ' $Curtest->{canon}'
- . "\n}\n"
- . "~~" . " " x ($Columns - $list_len - 2) . "^"
- . "<" x ($list_len - 1) . "\n"
- . '$Curtest->{canon}'
- . "\n.\n";
+ . "^" . "<" x ($list_len - 1) . "\n"
+ . '{ $Curtest->{name}, $Curtest->{estat},'
+ . ' $Curtest->{wstat}, $Curtest->{max},'
+ . ' $Curtest->{failed}, $Curtest->{percent},'
+ . ' $Curtest->{canon}'
+ . "\n}\n"
+ . "~~" . " " x ($Columns - $list_len - 2) . "^"
+ . "<" x ($list_len - 1) . "\n"
+ . '$Curtest->{canon}'
+ . "\n.\n";
eval $fmt_top;
die $@ if $@;
my $last = $min = shift @failed;
my $canon;
if (@failed) {
- for (@failed, $failed[-1]) { # don't forget the last one
- if ($_ > $last+1 || $_ == $last) {
- if ($min == $last) {
- push @canon, $last;
- } else {
- push @canon, "$min-$last";
- }
- $min = $_;
- }
- $last = $_;
- }
- local $" = ", ";
- push @result, "FAILED tests @canon\n";
- $canon = join ' ', @canon;
+ for (@failed, $failed[-1]) { # don't forget the last one
+ if ($_ > $last+1 || $_ == $last) {
+ if ($min == $last) {
+ push @canon, $last;
+ } else {
+ push @canon, "$min-$last";
+ }
+ $min = $_;
+ }
+ $last = $_;
+ }
+ local $" = ", ";
+ push @result, "FAILED tests @canon\n";
+ $canon = join ' ', @canon;
} else {
- push @result, "FAILED test $last\n";
- $canon = $last;
+ push @result, "FAILED test $last\n";
+ $canon = $last;
}
push @result, "\tFailed $failed/$max tests, ";