File Coverage

blib/lib/Test/Unit/Assert.pm
Criterion Covered Total %
statement 209 229 91.2
branch 96 114 84.2
condition 45 61 73.7
subroutine 34 36 94.4
pod 7 14 50.0
total 391 454 86.1


line stmt bran cond sub pod time code
1             package Test::Unit::Assert;
2              
3              
4 2     2   52 use strict;
  2         4  
  2         110  
5              
6 2     2   24 use Test::Unit::Debug qw(debug);
  2         5  
  2         100  
7 2     2   10 use Test::Unit::Failure;
  2         3  
  2         18  
8 2     2   88 use Test::Unit::Error;
  2         3  
  2         11  
9 2     2   71 use Test::Unit::Exception;
  2         4  
  2         17  
10              
11 2     2   1700 use Test::Unit::Assertion::CodeRef;
  2         4  
  2         54  
12              
13 2     2   11 use Error qw/:try/;
  2         4  
  2         11  
14 2     2   332 use Carp;
  2         4  
  2         8513  
15              
16             sub assert {
17 94     94 1 1732 my $self = shift;
18 94         419 my $assertion = $self->normalize_assertion(shift);
19 94         942 $self->do_assertion($assertion, (caller($Error::Depth))[0 .. 2], @_);
20             }
21              
22             sub normalize_assertion {
23 94     94 0 131 my $self = shift;
24 94         148 my $assertion = shift;
25              
26 94 100 100     370 if (!ref($assertion) || ref($assertion) =~ 'ARRAY') {
27 77 100       360 debug((defined $assertion ? $assertion : '_undef_') .
28             " normalized as boolean\n");
29 77         2002 require Test::Unit::Assertion::Boolean;
30 77         421 return Test::Unit::Assertion::Boolean->new($assertion);
31             }
32              
33             # If we're this far, we must have a reference.
34              
35 17 100       36 if (eval {$assertion->isa('Regexp')}) {
  17         146  
36 10         48 debug("$assertion normalized as Regexp\n");
37 10         2053 require Test::Unit::Assertion::Regexp;
38 10         65 return Test::Unit::Assertion::Regexp->new($assertion);
39             }
40              
41 7 100       28 if (ref($assertion) eq 'CODE') {
42 6         30 debug("$assertion normalized as coderef\n");
43 6         53 require Test::Unit::Assertion::CodeRef;
44 6         123 return Test::Unit::Assertion::CodeRef->new($assertion);
45             }
46              
47             # if (ref($assertion) eq 'SCALAR') {
48             # debug("$assertion normalized as scalar ref\n");
49             # require Test::Unit::Assertion::Scalar;
50             # return Test::Unit::Assertion::Scalar->new($assertion);
51             # }
52              
53 1 50       8 if (ref($assertion) !~ /^(GLOB|LVALUE|REF|SCALAR)$/) {
54 1         6 debug("$assertion already an object\n");
55 1         5 require Test::Unit::Assertion::Boolean;
56 1 50       11 return $assertion->can('do_assertion') ? $assertion :
57             Test::Unit::Assertion::Boolean->new($assertion);
58             }
59             else {
60 0         0 die "Don't know how to normalize $assertion (ref ", ref($assertion), ")\n";
61             }
62             }
63              
64             sub assert_raises {
65 4     4 1 383 my $self = shift;
66 4         877 require Test::Unit::Assertion::Exception;
67 4         19 my $assertion = Test::Unit::Assertion::Exception->new(shift);
68 4         25 my ($asserter, $file, $line) = caller($Error::Depth);
69 4         38 my $exception =
70             $self->do_assertion($assertion, (caller($Error::Depth))[0 .. 2], @_);
71             }
72              
73             sub do_assertion {
74 98     98 0 148 my $self = shift;
75 98         114 my $assertion = shift;
76 98         148 my $asserter = shift;
77 98         122 my $file = shift;
78 98         121 my $line = shift;
79 98         741 debug("Asserting [$assertion] from $asserter in $file line $line\n");
80 98         221 my @args = @_;
81 98     98   2699 try { $assertion->do_assertion(@args) }
82             catch Test::Unit::Exception with {
83 16     16   1199 my $e = shift;
84 16         68 debug(" Caught $e, rethrowing from $asserter, $file line $line\n");
85 16         101 $e->throw_new(-package => $asserter,
86             -file => $file,
87             -line => $line,
88             -object => $self);
89             }
90 98         1224 }
91              
92             sub multi_assert {
93 3     3 1 491 my $self = shift;
94 3         8 my ($assertion, @argsets) = @_;
95 3         20 my ($asserter, $file, $line) = caller($Error::Depth);
96 3         10 foreach my $argset (@argsets) {
97             try {
98 5     5   261 $self->assert($assertion, @$argset);
99             }
100             catch Test::Unit::Exception with {
101 2     2   247 my $e = shift;
102 2         8 debug(" Caught $e, rethrowing from $asserter, $file line $line\n");
103 2         14 $e->throw_new(-package => $asserter,
104             -file => $file,
105             -line => $line,
106             -object => $self);
107             }
108 5         177 }
109             }
110              
111             sub is_numeric {
112 86     86 0 248 my $str = shift;
113 86         327 local $^W;
114 86   66     1748 return defined $str && ! ($str == 0 && $str !~ /^\s*[+-]?0(e0)?\s*$/i);
115             }
116              
117             # First argument determines the comparison type.
118             sub assert_equals {
119 52     52 1 1295 my $self = shift;
120 52         626 my($asserter, $file, $line) = caller($Error::Depth);
121 52         167 my @args = @_;
122             try {
123 52 100 100 52   3460 if (! defined($args[0]) and ! defined($args[1])) {
    100 75        
    100          
    50          
124             # pass
125             }
126             elsif (defined($args[0]) xor defined($args[1])) {
127 2         16 $self->fail('one arg was not defined');
128             }
129 16 50       92 elsif (is_numeric($args[0])) {
130 30         304 $self->assert_num_equals(@args);
131             }
132             elsif (eval {ref($args[0]) && $args[0]->isa('UNIVERSAL')}) {
133 0         0 require overload;
134 0 0       0 if (overload::Method($args[0], '==')) {
135 0         0 $self->assert_num_equals(@args);
136             }
137             else {
138 0         0 $self->assert_str_equals(@args);
139             }
140             }
141             else {
142 16         210 $self->assert_str_equals(@args);
143             }
144             }
145             catch Test::Unit::Exception with {
146 24     24   2322 my $e = shift;
147 24         226 $e->throw_new(-package => $asserter,
148             -file => $file,
149             -line => $line,
150             -object => $self);
151             }
152 52         845 }
153              
154             sub ok { # To make porting from Test easier
155 39     39 1 6463 my $self = shift;
156 39         102 my @args = @_;
157 39         79 local $Error::Depth = $Error::Depth + 1;
158 39 100 100     322 if (@args == 1) {
    100          
159 4         16 $self->assert($args[0]); # boolean assertion
160             }
161             elsif (@args >= 2 && @args <= 3) {
162 33 100       125 if (ref($args[0]) eq 'CODE') {
  29 100       335  
163 4         10 my $code = shift @args;
164 4         11 my $expected = shift @args;
165 4         17 $self->assert_equals($expected, $code->(), @args);
166             }
167             elsif (eval {$args[1]->isa('Regexp')}) {
168 3         7 my $got = shift @args;
169 3         8 my $re = shift @args;
170 3         34 $self->assert($re, $got, @args);
171             }
172             else {
173 26         57 my $got = shift @args;
174 26         52 my $expected = shift @args;
175 26         113 $self->assert_equals($expected, $got, @args);
176             }
177             }
178             else {
179 2         16 $self->error('ok() called with wrong number of args');
180             }
181             }
182              
183             sub assert_not_equals {
184 37     37 1 7072 my $self = shift;
185 37         280 my($asserter,$file,$line) = caller($Error::Depth);
186 37         140 my @args = @_;
187             try {
188 37 100 100 37   1258 if (! defined($args[0]) && ! defined($args[1])) {
    100 75        
    100          
    50          
189 2         5 my $first = shift @args;
190 2         2 my $second = shift @args;
191 2 100       22 $self->fail(@args ? join('', @args) : 'both args were undefined');
192             }
193             elsif (defined($args[0]) xor defined($args[1])) {
194             # succeed
195             }
196 5 50       25 elsif (is_numeric($args[0])) {
197 26         111 $self->assert_num_not_equals(@args);
198             }
199             elsif (eval {ref($args[0]) && $args[0]->isa('UNIVERSAL')}) {
200 0         0 require overload;
201 0 0       0 if (overload::Method($args[0], '==')) {
202 0         0 $self->assert_num_not_equals(@args);
203             }
204             else {
205 0         0 $self->assert_str_not_equals(@args);
206             }
207             }
208             else {
209 5         45 $self->assert_str_not_equals(@args);
210             }
211             }
212             catch Test::Unit::Exception with {
213 24     24   1865 my $e = shift;
214 24         211 $e->throw_new(-package => $asserter,
215             -file => $file,
216             -line => $line,
217             -object => $self,);
218 37         303 };
219             }
220              
221             # Shamelessly pinched from Test::More and adapted to Test::Unit.
222             our %Seen_Refs = ();
223             our @Data_Stack;
224             my $DNE = bless [], 'Does::Not::Exist';
225             sub assert_deep_equals {
226 38     38 1 6199 my $self = shift;
227 38         44 my $this = shift;
228 38         42 my $that = shift;
229              
230 38         50 local $Error::Depth = $Error::Depth + 1;
231              
232 38 100 66     130 if (! ref $this || ! ref $that) {
233 10 100       47 Test::Unit::Failure->throw(
234             -text => @_ ? join('', @_)
235             : 'Both arguments were not references'
236             );
237             }
238              
239 28         54 local @Data_Stack = ();
240 28         43 local %Seen_Refs = ();
241 28 100       71 if (! $self->_deep_check($this, $that)) {
242 21 100       109 Test::Unit::Failure->throw(
243             -text => @_ ? join('', @_)
244             : $self->_format_stack(@Data_Stack)
245             );
246             }
247             }
248              
249             sub _deep_check {
250 117     117   148 my $self = shift;
251 117         145 my ($e1, $e2) = @_;
252              
253 117 100 66     446 if ( ! defined $e1 || ! defined $e2 ) {
254 11 100 66     35 return 1 if !defined $e1 && !defined $e2;
255 8         25 push @Data_Stack, { vals => [$e1, $e2] };
256 8         18 return 0;
257             }
258              
259 106 100 66     876 return 0 if ( (defined $e1 && $e1 eq $DNE)
      66        
      66        
260             || (defined $e2 && $e2 eq $DNE ));
261              
262 100 100       264 return 1 if $e1 eq $e2;
263 58 100 66     321 if ( ref $e1 && ref $e2 ) {
264 55         109 my $e2_ref = "$e2";
265 55 100 66     172 return 1 if defined $Seen_Refs{$e1} && $Seen_Refs{$e1} eq $e2_ref;
266 51         162 $Seen_Refs{$e1} = $e2_ref;
267             }
268              
269 54 100 100     363 if (UNIVERSAL::isa($e1, 'ARRAY') and UNIVERSAL::isa($e2, 'ARRAY')) {
    100 66        
    50 33        
    50 33        
270 24         97 return $self->_eq_array($e1, $e2);
271             }
272             elsif (UNIVERSAL::isa($e1, 'HASH') and UNIVERSAL::isa($e2, 'HASH')) {
273 23         131 return $self->_eq_hash($e1, $e2);
274             }
275             elsif (UNIVERSAL::isa($e1, 'REF') and UNIVERSAL::isa($e2, 'REF')) {
276 0         0 push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
277 0         0 my $ok = $self->_deep_check($$e1, $$e2);
278 0 0       0 pop @Data_Stack if $ok;
279 0         0 return $ok;
280             }
281             elsif (UNIVERSAL::isa($e1, 'SCALAR') and UNIVERSAL::isa($e2, 'SCALAR')) {
282 0         0 push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
283 0         0 return $self->_deep_check($$e1, $$e2);
284             }
285             else {
286 7         34 push @Data_Stack, { vals => [$e1, $e2] };
287 7         24 return 0;
288             }
289             }
290              
291             sub _eq_array {
292 24     24   28 my $self = shift;
293 24         32 my($a1, $a2) = @_;
294 24 50       61 return 1 if $a1 eq $a2;
295              
296 24         24 my $ok = 1;
297 24 100       55 my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2;
298 24         51 for (0..$max) {
299 44 100       94 my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_];
300 44 100       81 my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_];
301              
302 44         180 push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] };
303 44         113 $ok = $self->_deep_check($e1,$e2);
304 44 100       96 pop @Data_Stack if $ok;
305              
306 44 100       137 last unless $ok;
307             }
308 24         81 return $ok;
309             }
310              
311             sub _eq_hash {
312 23     23   30 my $self = shift;
313 23         30 my($a1, $a2) = @_;
314 23 50       67 return 1 if $a1 eq $a2;
315              
316 23         23 my $ok = 1;
317 23 100       61 my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2;
318 23         53 foreach my $k (keys %$bigger) {
319 45 50       168 my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE;
320 45 100       87 my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE;
321              
322 45         186 push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] };
323 45         102 $ok = $self->_deep_check($e1, $e2);
324 45 100       178 pop @Data_Stack if $ok;
325              
326 45 100       145 last unless $ok;
327             }
328              
329 23         99 return $ok;
330             }
331              
332             sub _format_stack {
333 11     11   12 my $self = shift;
334 11         29 my @Stack = @_;
335              
336 11         22 my $var = '$FOO';
337 11         11 my $did_arrow = 0;
338 11         15 foreach my $entry (@Stack) {
339 22   100     64 my $type = $entry->{type} || '';
340 22         23 my $idx = $entry->{'idx'};
341 22 100       75 if( $type eq 'HASH' ) {
    100          
    50          
342 8 100       21 $var .= "->" unless $did_arrow++;
343 8         18 $var .= "{$idx}";
344             }
345             elsif( $type eq 'ARRAY' ) {
346 6 100       25 $var .= "->" unless $did_arrow++;
347 6         15 $var .= "[$idx]";
348             }
349             elsif( $type eq 'REF' ) {
350 0         0 $var = "\${$var}";
351             }
352             }
353              
354 11         15 my @vals = @{$Stack[-1]{vals}}[0,1];
  11         34  
355            
356 11         15 my @vars = ();
357 11         46 ($vars[0] = $var) =~ s/\$FOO/ \$a/;
358 11         29 ($vars[1] = $var) =~ s/\$FOO/ \$b/;
359              
360 11         15 my $out = "Structures begin differing at:\n";
361 11         25 foreach my $idx (0..$#vals) {
362 22         30 my $val = $vals[$idx];
363 22 100       92 $vals[$idx] = !defined $val ? 'undef' :
    100          
364             $val eq $DNE ? "Does not exist"
365             : "'$val'";
366             }
367              
368 11         33 $out .= "$vars[0] = $vals[0]\n";
369 11         21 $out .= "$vars[1] = $vals[1]\n";
370              
371 11         64 return $out;
372             }
373              
374             {
375             my %assert_subs = (
376             str_equals => sub {
377             my $str1 = shift;
378             my $str2 = shift;
379             defined $str1 or
380             Test::Unit::Failure->throw(
381             -text => @_ ? join('',@_) :
382             "expected value was undef; should be using assert_null?"
383             );
384             defined $str2 or
385             Test::Unit::Failure->throw(
386             -text => @_ ? join('',@_) : "expected '$str1', got undef"
387             );
388             $str1 eq $str2 or
389             Test::Unit::Failure->throw(
390             -text => @_ ? join('',@_) : "expected '$str1', got '$str2'"
391             );
392             },
393             str_not_equals => sub {
394             my $str1 = shift;
395             my $str2 = shift;
396             defined $str1 or
397             Test::Unit::Failure->throw(
398             -text => @_ ? join('',@_) :
399             "expected value was undef; should be using assert_not_null?"
400             );
401             defined $str2 or
402             Test::Unit::Failure->throw(
403             -text => @_ ? join('',@_) :
404             "expected a string ne '$str1', got undef"
405             );
406             $str1 ne $str2 or
407             Test::Unit::Failure->throw(
408             -text => @_ ? join('',@_) : "'$str1' and '$str2' should differ"
409             );
410             },
411             num_equals => sub {
412             my $num1 = shift;
413             my $num2 = shift;
414             defined $num1 or
415             Test::Unit::Failure->throw(
416             -text => @_ ? join('',@_) :
417             "expected value was undef; should be using assert_null?"
418             );
419             defined $num2 or
420             Test::Unit::Failure->throw(
421             -text => @_ ? join('',@_) : "expected '$num1', got undef"
422             );
423             # silence `Argument "" isn't numeric in numeric eq (==)' warnings
424             local $^W;
425             $num1 == $num2 or
426             Test::Unit::Failure->throw(
427             -text => @_ ? join('', @_) : "expected $num1, got $num2"
428             );
429             },
430             num_not_equals => sub {
431             my $num1 = shift;
432             my $num2 = shift;
433             defined $num1 or
434             Test::Unit::Failure->throw(
435             -text => @_ ? join('',@_) :
436             "expected value was undef; should be using assert_not_null?"
437             );
438             defined $num2 or
439             Test::Unit::Failure->throw(
440             -text => @_ ? join('',@_) :
441             "expected a number != '$num1', got undef"
442             );
443             # silence `Argument "" isn't numeric in numeric ne (!=)' warnings
444             local $^W;
445             $num1 != $num2 or
446             Test::Unit::Failure->throw(
447             -text => @_ ? join('', @_) : "$num1 and $num2 should differ"
448             );
449             },
450             matches => sub {
451             my $regexp = shift;
452             eval { $regexp->isa('Regexp') } or
453             Test::Unit::Error->throw(
454             -text => "arg 1 to assert_matches() must be a regexp"
455             );
456             my $string = shift;
457             $string =~ $regexp or
458             Test::Unit::Failure->throw
459             (-text => @_ ? join('', @_) :
460             "$string didn't match /$regexp/");
461             },
462             does_not_match => sub {
463             my $regexp = shift;
464             eval { $regexp->isa('Regexp') } or
465             Test::Unit::Error->throw(
466             -text => "arg 1 to assert_does_not_match() must be a regexp"
467             );
468             my $string = shift;
469             $string !~ $regexp or
470             Test::Unit::Failure->throw
471             (-text => @_ ? join('', @_) :
472             "$string matched /$regexp/");
473             },
474             null => sub {
475             my $arg = shift;
476             !defined($arg) or
477             Test::Unit::Failure->throw
478             (-text => @_ ? join('',@_) : "$arg is defined");
479             },
480             not_null => sub {
481             my $arg = shift;
482             defined($arg) or
483             Test::Unit::Failure->throw
484             (-text => @_ ? join('', @_) : " unexpected");
485             },
486             );
487             foreach my $type (keys %assert_subs) {
488             my $assertion = Test::Unit::Assertion::CodeRef->new($assert_subs{$type});
489 2     2   24 no strict 'refs';
  2         3  
  2         820  
490             *{"Test::Unit::Assert::assert_$type"} =
491             sub {
492 183     183   6757 local $Error::Depth = $Error::Depth + 3;
493 183         1265 my $self = shift;
494 183         895 $assertion->do_assertion(@_);
495             };
496             }
497             }
498              
499             sub fail {
500 11     11 0 343 my $self = shift;
501 11         52 debug(ref($self) . "::fail() called\n");
502 11         64 my($asserter,$file,$line) = caller($Error::Depth);
503 11         33 my $message = join '', @_;
504 11         77 Test::Unit::Failure->throw(-text => $message,
505             -object => $self,
506             -file => $file,
507             -line => $line);
508             }
509              
510             sub error {
511 2     2 0 4 my $self = shift;
512 2         9 debug(ref($self) . "::error() called\n");
513 2         11 my($asserter,$file,$line) = caller($Error::Depth);
514 2         7 my $message = join '', @_;
515 2         18 Test::Unit::Error->throw(-text => $message,
516             -object => $self,
517             -file => $file,
518             -line => $line);
519             }
520              
521             sub quell_backtrace {
522 0     0 0   my $self = shift;
523 0           carp "quell_backtrace deprecated";
524             }
525              
526             sub get_backtrace_on_fail {
527 0     0 0   my $self = shift;
528 0           carp "get_backtrace_on_fail deprecated";
529             }
530              
531              
532              
533             1;
534             __END__