Zero entries were skipped, fix from Adrian Goalby
[p5sagit/p5-mst-13.2.git] / lib / Test.pm
CommitLineData
7b13a3f5 1use strict;
2package Test;
17f410f9 3use 5.005_64;
7b13a3f5 4use Test::Harness 1.1601 ();
5use Carp;
17f410f9 6our($VERSION, @ISA, @EXPORT, @EXPORT_OK, $ntest, $TestLevel); #public-ish
7our($TESTOUT, $ONFAIL, %todo, %history, $planned, @FAILDETAIL); #private-ish
59e80644 8$VERSION = '1.13';
7b13a3f5 9require Exporter;
10@ISA=('Exporter');
f2ac83ee 11@EXPORT=qw(&plan &ok &skip);
12@EXPORT_OK=qw($ntest $TESTOUT);
7b13a3f5 13
3238f5fe 14$TestLevel = 0; # how many extra stack frames to skip
7b13a3f5 15$|=1;
16#$^W=1; ?
17$ntest=1;
f2ac83ee 18$TESTOUT = *STDOUT{IO};
7b13a3f5 19
3238f5fe 20# Use of this variable is strongly discouraged. It is set mainly to
21# help test coverage analyzers know which test is running.
7b13a3f5 22$ENV{REGRESSION_TEST} = $0;
23
24sub plan {
25 croak "Test::plan(%args): odd number of arguments" if @_ & 1;
8b3be1d1 26 croak "Test::plan(): should not be called more than once" if $planned;
7b13a3f5 27 my $max=0;
28 for (my $x=0; $x < @_; $x+=2) {
29 my ($k,$v) = @_[$x,$x+1];
30 if ($k =~ /^test(s)?$/) { $max = $v; }
31 elsif ($k eq 'todo' or
32 $k eq 'failok') { for (@$v) { $todo{$_}=1; }; }
8b3be1d1 33 elsif ($k eq 'onfail') {
34 ref $v eq 'CODE' or croak "Test::plan(onfail => $v): must be CODE";
35 $ONFAIL = $v;
36 }
7b13a3f5 37 else { carp "Test::plan(): skipping unrecognized directive '$k'" }
38 }
39 my @todo = sort { $a <=> $b } keys %todo;
40 if (@todo) {
f2ac83ee 41 print $TESTOUT "1..$max todo ".join(' ', @todo).";\n";
7b13a3f5 42 } else {
f2ac83ee 43 print $TESTOUT "1..$max\n";
7b13a3f5 44 }
8b3be1d1 45 ++$planned;
7b13a3f5 46}
47
3238f5fe 48sub to_value {
49 my ($v) = @_;
50 (ref $v or '') eq 'CODE' ? $v->() : $v;
51}
52
8b3be1d1 53sub ok ($;$$) {
54 croak "ok: plan before you test!" if !$planned;
3238f5fe 55 my ($pkg,$file,$line) = caller($TestLevel);
56 my $repetition = ++$history{"$file:$line"};
57 my $context = ("$file at line $line".
8b3be1d1 58 ($repetition > 1 ? " fail \#$repetition" : ''));
3238f5fe 59 my $ok=0;
8b3be1d1 60 my $result = to_value(shift);
61 my ($expected,$diag);
3238f5fe 62 if (@_ == 0) {
8b3be1d1 63 $ok = $result;
3238f5fe 64 } else {
8b3be1d1 65 $expected = to_value(shift);
8b3be1d1 66 my ($regex,$ignore);
59e80644 67 if (!defined $expected) {
68 $ok = !defined $result;
69 } elsif (!defined $result) {
70 $ok = 0;
71 } elsif ((ref($expected)||'') eq 'Regexp') {
f2ac83ee 72 $ok = $result =~ /$expected/;
73 } elsif (($regex) = ($expected =~ m,^ / (.+) / $,sx) or
8b3be1d1 74 ($ignore, $regex) = ($expected =~ m,^ m([^\w\s]) (.+) \1 $,sx)) {
75 $ok = $result =~ /$regex/;
3238f5fe 76 } else {
3238f5fe 77 $ok = $result eq $expected;
78 }
8b3be1d1 79 }
f2ac83ee 80 my $todo = $todo{$ntest};
81 if ($todo and $ok) {
82 $context .= ' TODO?!' if $todo;
83 print $TESTOUT "ok $ntest # ($context)\n";
8b3be1d1 84 } else {
f2ac83ee 85 print $TESTOUT "not " if !$ok;
86 print $TESTOUT "ok $ntest\n";
8b3be1d1 87
88 if (!$ok) {
89 my $detail = { 'repetition' => $repetition, 'package' => $pkg,
f2ac83ee 90 'result' => $result, 'todo' => $todo };
8b3be1d1 91 $$detail{expected} = $expected if defined $expected;
92 $diag = $$detail{diagnostic} = to_value(shift) if @_;
f2ac83ee 93 $context .= ' *TODO*' if $todo;
8b3be1d1 94 if (!defined $expected) {
3238f5fe 95 if (!$diag) {
f2ac83ee 96 print $TESTOUT "# Failed test $ntest in $context\n";
3238f5fe 97 } else {
f2ac83ee 98 print $TESTOUT "# Failed test $ntest in $context: $diag\n";
3238f5fe 99 }
8b3be1d1 100 } else {
101 my $prefix = "Test $ntest";
59e80644 102 print $TESTOUT "# $prefix got: ".
103 (defined $result? "'$result'":'<UNDEF>')." ($context)\n";
8b3be1d1 104 $prefix = ' ' x (length($prefix) - 5);
f63ceb1c 105 if ((ref($expected)||'') eq 'Regexp') {
f2ac83ee 106 $expected = 'qr/'.$expected.'/'
107 } else {
108 $expected = "'$expected'";
109 }
8b3be1d1 110 if (!$diag) {
f2ac83ee 111 print $TESTOUT "# $prefix Expected: $expected\n";
3238f5fe 112 } else {
f2ac83ee 113 print $TESTOUT "# $prefix Expected: $expected ($diag)\n";
3238f5fe 114 }
115 }
8b3be1d1 116 push @FAILDETAIL, $detail;
7b13a3f5 117 }
7b13a3f5 118 }
119 ++ $ntest;
120 $ok;
121}
122
8b3be1d1 123sub skip ($$;$$) {
f2ac83ee 124 my $whyskip = to_value(shift);
125 if ($whyskip) {
126 $whyskip = 'skip' if $whyskip =~ m/^\d+$/;
127 print $TESTOUT "ok $ntest # $whyskip\n";
7b13a3f5 128 ++ $ntest;
129 1;
130 } else {
8b3be1d1 131 local($TestLevel) = $TestLevel+1; #ignore this stack frame
132 &ok;
7b13a3f5 133 }
134}
135
8b3be1d1 136END {
137 $ONFAIL->(\@FAILDETAIL) if @FAILDETAIL && $ONFAIL;
138}
139
7b13a3f5 1401;
141__END__
142
143=head1 NAME
144
145 Test - provides a simple framework for writing test scripts
146
147=head1 SYNOPSIS
148
149 use strict;
150 use Test;
f2ac83ee 151
152 # use a BEGIN block so we print our plan before MyModule is loaded
153 BEGIN { plan tests => 14, todo => [3,4] }
154
155 # load your module...
156 use MyModule;
3238f5fe 157
158 ok(0); # failure
159 ok(1); # success
160
161 ok(0); # ok, expected failure (see todo list, above)
162 ok(1); # surprise success!
163
164 ok(0,1); # failure: '0' ne '1'
165 ok('broke','fixed'); # failure: 'broke' ne 'fixed'
166 ok('fixed','fixed'); # success: 'fixed' eq 'fixed'
f2ac83ee 167 ok('fixed',qr/x/); # success: 'fixed' =~ qr/x/
7b13a3f5 168
3238f5fe 169 ok(sub { 1+1 }, 2); # success: '2' eq '2'
170 ok(sub { 1+1 }, 3); # failure: '2' ne '3'
59e80644 171 ok(0, int(rand(2)); # (just kidding :-)
7b13a3f5 172
3238f5fe 173 my @list = (0,0);
8b3be1d1 174 ok @list, 3, "\@list=".join(',',@list); #extra diagnostics
175 ok 'segmentation fault', '/(?i)success/'; #regex match
7b13a3f5 176
3238f5fe 177 skip($feature_is_missing, ...); #do platform specific test
7b13a3f5 178
179=head1 DESCRIPTION
180
f2ac83ee 181L<Test::Harness> expects to see particular output when it executes
182tests. This module aims to make writing proper test scripts just a
183little bit easier (and less error prone :-).
7b13a3f5 184
3238f5fe 185=head1 TEST TYPES
7b13a3f5 186
187=over 4
188
189=item * NORMAL TESTS
190
f2ac83ee 191These tests are expected to succeed. If they don't something's
3238f5fe 192screwed up!
7b13a3f5 193
194=item * SKIPPED TESTS
195
f2ac83ee 196Skip is for tests that might or might not be possible to run depending
197on the availability of platform specific features. The first argument
198should evaluate to true (think "yes, please skip") if the required
199feature is not available. After the first argument, skip works
3238f5fe 200exactly the same way as do normal tests.
7b13a3f5 201
202=item * TODO TESTS
203
f2ac83ee 204TODO tests are designed for maintaining an B<executable TODO list>.
205These tests are expected NOT to succeed. If a TODO test does succeed,
206the feature in question should not be on the TODO list, now should it?
7b13a3f5 207
f2ac83ee 208Packages should NOT be released with succeeding TODO tests. As soon
7b13a3f5 209as a TODO test starts working, it should be promoted to a normal test
f2ac83ee 210and the newly working feature should be documented in the release
211notes or change log.
7b13a3f5 212
213=back
214
f2ac83ee 215=head1 RETURN VALUE
216
217Both C<ok> and C<skip> return true if their test succeeds and false
218otherwise in a scalar context.
219
8b3be1d1 220=head1 ONFAIL
221
222 BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } }
223
f2ac83ee 224While test failures should be enough, extra diagnostics can be
225triggered at the end of a test run. C<onfail> is passed an array ref
226of hash refs that describe each test failure. Each hash will contain
227at least the following fields: C<package>, C<repetition>, and
228C<result>. (The file, line, and test number are not included because
f610777f 229their correspondence to a particular test is tenuous.) If the test
f2ac83ee 230had an expected value or a diagnostic string, these will also be
231included.
232
233The B<optional> C<onfail> hook might be used simply to print out the
234version of your package and/or how to report problems. It might also
235be used to generate extremely sophisticated diagnostics for a
236particularly bizarre test failure. However it's not a panacea. Core
237dumps or other unrecoverable errors prevent the C<onfail> hook from
238running. (It is run inside an C<END> block.) Besides, C<onfail> is
239probably over-kill in most cases. (Your test code should be simpler
8b3be1d1 240than the code it is testing, yes?)
241
7b13a3f5 242=head1 SEE ALSO
243
f2ac83ee 244L<Test::Harness> and, perhaps, test coverage analysis tools.
7b13a3f5 245
246=head1 AUTHOR
247
59e80644 248Copyright (c) 1998-1999 Joshua Nathaniel Pritikin. All rights reserved.
7b13a3f5 249
250This package is free software and is provided "as is" without express
251or implied warranty. It may be used, redistributed and/or modified
252under the terms of the Perl Artistic License (see
253http://www.perl.com/perl/misc/Artistic.html)
254
255=cut