File Coverage

inc/TyeTest.pm
Criterion Covered Total %
statement 85 136 62.5
branch 27 60 45.0
condition 3 30 10.0
subroutine 14 16 87.5
pod 0 10 0.0
total 129 252 51.1


line stmt bran cond sub pod time code
1             package TyeTest;
2 3     3   10235 use strict;
  3         8  
  3         128  
3              
4 3     3   1711 use Test qw< plan ok skip >;
  3         9555  
  3         241  
5 3     3   21 use Carp qw< croak >;
  3         9  
  3         125  
6 3     3   38 use vars qw< @EXPORT_OK >;
  3         5  
  3         206  
7              
8             BEGIN {
9 3     3   13 @EXPORT_OK = qw<
10             plan ok skip
11             Okay True False
12             Note Dump SkipIf
13             Lives Dies Warns LinesLike
14             >;
15 3         12 require Exporter;
16 3         5248 *import = \&Exporter::import;
17             }
18              
19             $| = 1;
20              
21             return 1; # Just subroutines below here.
22              
23              
24             # Okay( $expect, codeToTest(), 'Description of test' );
25             # Okay( $boolean ); # But don't use it this way (much)
26              
27             sub Okay($;$$) {
28 30     30 0 726 my( $expect, $got, $desc ) = @_;
29 30         45 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
30 30 50       71 return ok( $expect ) if 1 == @_;
31 30 50       47 return ok( $got, $expect ) if ! $desc;
32 30         93 return ok( $got, $expect, $desc );
33             }
34              
35              
36             # True( codeToTest(), 'Description of test' );
37              
38             sub True($;$) {
39 10     10 0 70 my( $got, $desc ) = @_;
40 10         33 my $expect = qr/^([^0]|..)/s;
41 10 50       43 $expect = $got # Pass test if got a 'true' value.
42             if $got;
43 10         27 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
44 10         20 return Okay( $expect, $got, $desc );
45             }
46              
47              
48             # False( codeToTest(), 'Description of test' );
49              
50             sub False($;$) {
51 4     4 0 21 my( $got, $desc ) = @_;
52 4         24 my $expect = qr/^0?\z/; # Explain what we expected.
53 4 100       14 $expect = $got # Pass test if got 0, '', or undef()...
54             if ! $got; # (any 'false' value).
55 4         13 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
56 4         77 return Okay( $expect, $got, $desc );
57             }
58              
59              
60             # Note( $string, ... );
61              
62             sub Note {
63             # Note: Ignores trailing newlines per string
64 8     8 0 1234 for my $line ( map { split /\n/, $_ } @_ ) {
  8         47  
65 8         75 print "#$line\n";
66             }
67             }
68              
69              
70             # Dump( $data, ... );
71              
72             sub Dump {
73 0     0 0 0 require Data::Dumper;
74 0 0       0 my $dd = Data::Dumper->new(
75             1 == @_ ? [@_] : [[@_]],
76             );
77 0         0 $dd->Indent(1)->Useqq(1)->Terse(1)->Sortkeys(1);
78 0         0 Note( $dd->Dump() );
79             }
80              
81              
82             # SkipIf( $skipReason, $expect, sub { codeToMaybeTest() }, 'Description of test' );
83             # SkipIf(
84             # ! Okay( $expect1, codeToTest(), 'Description of first test' ),
85             # $expect2, sub { codeToTestIfFirstTestPasses() }, 'Description of 2nd test',
86             # )
87             #
88             # my $skip = $ENV{TESTSERVER} ? '' : 'TESTSERVER not set in environment';
89             # SkipIf( $skip, sub { codeThatNeedsTestServer() }, 'Description of test' );
90             #
91             # Give $skipReason as a false value to have the test run (not skipped).
92             # A $skipReason of '1' becomes "Prior test failed"
93              
94             sub SkipIf($;$$$) {
95 4     4 0 5 my( $skip, $expect, $sub, $desc ) = @_;
96 4 50 33     23 croak( "Can't not skip a non-test" )
97             if ! $skip && @_ <= 1;
98 4 50 33     8 $skip = 'Prior test failed'
99             if $skip && '1' eq $skip;
100 4         20 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
101 4 50       7 return skip( $skip ) if 1 == @_;
102 4 50       12 return skip( $skip, $expect ) if 2 == @_;
103 4 50       10 return skip( $skip, $sub, $expect ) if 3 == @_;
104 4         14 return skip( $skip, $sub, $expect, $desc );
105             }
106              
107              
108             # Lives( $stringOfPerlCodeToTest, 'Description of test' );
109             # Lives( \&subToCallThatMightDie, 'Description of test' );
110             # Lives( sub { ... }, 'Description of test' );
111             #
112             # "Should not die:\n" gets prepended to the description.
113              
114             sub Lives {
115 0     0 0 0 my( $code, $desc ) = @_;
116              
117 0         0 my( $pkg, $file, $line ) = caller( $Test::TestLevel );
118 0         0 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
119              
120 0 0       0 if( ref $code ) {
121 0 0       0 if( ! $desc ) {
122 0         0 ( $desc ) = $file =~ m{([^/]+)$};
123 0   0     0 $desc ||= $file;
124 0         0 $desc .= " line $line";
125             }
126 0         0 return Okay( 1, eval { $code->(); 1 }, "Should not die: $desc\nError: $@" );
  0         0  
  0         0  
127             }
128 0   0     0 $desc &&= " $desc";
129 0   0     0 $desc ||= "\n$code";
130 0         0 my $eval = join "\n",
131             "package $pkg;",
132             qq<#line $line "$file">,
133             "# your code:",
134             $code,
135             ";1\n";
136 0         0 return Okay( 1, eval $eval, "Should not die:$desc\nError: $@" );
137             }
138              
139              
140             # Dies( 'Test desc', $stringOfPerlCodeToTest, qr/expected error/, qr/.../... )
141             # Dies( 'Test desc', \&subThatShouldDie, qr/expected error/, qr/.../... )
142             # Dies( 'Test desc', sub { ... }, qr/expected error/, qr/.../... )
143             #
144             # Counts as 1+@regexes when counting what to tell plan().
145             # Description defaults to the code if it is a string.
146             # Prepends "Should die:" then "Error from:" or "Error $n from:" to desc.
147             # If you give a string instead of a regex, then index() ignoring case is done.
148             # Format your code as follows if you want accurate display of line numbers:
149             # Dies( 'Test desc',
150             # $code,
151             # qr/test/,
152              
153             sub Dies {
154 3     3 0 44 my( $desc, $code, @omens ) = @_;
155              
156 3         10 my( $pkg, $file, $line ) = caller( $Test::TestLevel );
157 3         7 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
158              
159 3         2 my $skip;
160 3   33     13 $desc &&= " $desc";
161 3 50       5 if( ref $code ) {
162 3         3 --$line;
163 3 50       5 if( ! $desc ) {
164 0         0 ( $desc ) = $file =~ m{([^/]+)$};
165 0   0     0 $desc ||= $file;
166 0         0 $desc .= " line $line";
167             }
168 3         4 $skip = ! Okay( undef, eval { $code->(); 1 }, "Should die: $desc" );
  3         5  
  0         0  
169             } else {
170 0 0 0     0 $desc ||= "\n" . join '', $code, $code =~ /\n$/ ? '' : "\n";
171 0         0 my $eval = join "\n",
172             "package $pkg;",
173             qq<#line $line "$file">,
174             "# your code:",
175             $code,
176             ";1\n";
177 0         0 $skip = ! Okay( undef, eval $eval, "Should die:$desc" ),
178             }
179 3         170 my $got = $@;
180 3 100       10 my $idx = 1 == @omens ? '' : 1;
181 3 100       6 my $sp = $idx ? ' ' : '';
182 3         4 my $fail = $skip;
183 3         6 for my $omen ( @omens ) {
184 4 50       11 $omen = $omen->()
185             if 'CODE' eq ref $omen;
186 4 50       403 $omen = qr/\Q$omen/i
187             if ! ref $omen;
188 4 50       18 $fail = 1
189             if ! SkipIf( $skip, $omen, $got, "Error$sp$idx from:$desc" );
190 4         201 $idx++;
191             }
192 3         8 return ! $fail;
193             }
194              
195              
196             # Warns( 'Test desc', \&subThatShouldNotWarn )
197             # Warns( 'Test desc', \&subThatShouldWarn, qr/expected error/, qr/.../... )
198             # Warns( 'Test desc', sub {...}, qr/expected error/, qr/.../... )
199             # Warns( 'Desc', sub {...}, [ qr/first/, ... ], [ qr/2nd/ ], ... )
200             #
201             # Counts as 1+@regexes tests when counting what to tell plan().
202             # Giving no regexes actually asserts that no warnings are generated (1 test).
203             # Giving 1 or more array refs means you expect a precise number of warnings
204             # and the first array of regexes is tested against the 1st warning, etc.
205             # Else, don't use array refs and each regex must match at least one warning.
206             # If you give a string instead of a regex, then index() ignoring case is done.
207             # Various strings get prepended to the test description.
208             # Description defaults to a file and line number.
209              
210             sub Warns {
211 2     2 0 82 my( $desc, $sub, @omens ) = @_;
212 2 50       8 if( ! $desc ) {
213 0         0 my( $pkg, $file, $line ) = caller( $Test::TestLevel );
214 0         0 ++$line;
215 0         0 ( $desc ) = $file =~ m{([^/]+)$};
216 0   0     0 $desc ||= $file;
217 0         0 $desc .= " line $line";
218             }
219              
220             # Collect any warnings from running the code:
221 2         4 my @warns;
222             {
223 2     2   4 local( $SIG{__WARN__} ) = sub { push @warns, $_[0] };
  2         14  
  2         8  
224 2         6 $sub->();
225             }
226 2         4 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
227 2         8 return LinesLike( $desc, 'warning', \@warns, @omens );
228             }
229              
230              
231             sub LinesLike {
232 2     2 0 6 my( $desc, $what, $lines_av, @omens ) = @_;
233 2 50       6 if( ! $desc ) {
234 0         0 my( $pkg, $file, $line ) = caller( $Test::TestLevel );
235 0         0 ++$line;
236 0         0 ( $desc ) = $file =~ m{([^/]+)$};
237 0   0     0 $desc ||= $file;
238 0         0 $desc .= " line $line";
239             }
240              
241 2         4 local( $Test::TestLevel ) = 1 + $Test::TestLevel;
242              
243             # We expected no lines:
244 2 50       8 if( ! @omens ) {
245 0         0 $desc = "No $what from: $desc";
246 0 0       0 $desc .= "\n$lines_av->[0]"
247             if @$lines_av;
248 0         0 return Okay( 0, 0+@$lines_av, $desc );
249             }
250              
251 2         2 my $fail;
252 2 50       8 if( "ARRAY" eq ref $omens[0] ) {
253             # We expected a specific list of lines:
254 0         0 $fail = ! Okay( 0+@omens, 0+@$lines_av, "\u$what(s) from: $desc" );
255 0 0       0 if( ! $fail ) { # Got expected number, so test each:
256 0         0 for my $i ( 1 .. @omens ) {
257 0         0 my $line = $lines_av->[$i-1];
258 0         0 for my $omen ( @{ $omens[$i-1] } ) {
  0         0  
259 0 0       0 $omen = qr/\Q$omen/i
260             if ! ref $omen;
261 0         0 $fail += ! Okay( $omen, $line, "\u$what $i from: $desc" );
262             }
263             }
264 0         0 return ! $fail;
265             }
266             # Got unexpected number; fall back to just checking each omen:
267 0         0 @omens = map @$_, @omens;
268             } else {
269             # We expected at least one line:
270 2         14 $fail = ! Okay(
271             1, 0+!!@$lines_av,
272             join( ' ', "Got", 0+@$lines_av, "$what(s) from: $desc" ),
273             );
274             }
275              
276 2 50       166 if( ! @$lines_av ) {
277             skip( "Expected $what; got none; $_" )
278 0         0 for @omens;
279 0         0 return 0;
280             }
281              
282             s/\n?$/\n/
283 2         26 for @$lines_av;
284 2         4 my $all = join '', @$lines_av;
285 2 50       8 my $s = 1 == @$lines_av ? '' : 's';
286 2         4 for my $omen ( @omens ) {
287 4 100       156 $omen = qr/\Q$omen/i
288             if ! ref $omen;
289 4         26 $fail += ! Okay( $omen, $all, "\u$what$s from: $desc" );
290             }
291 2         98 return ! $fail;
292             }