File Coverage

blib/lib/Test/Unit/Assert.pm
Criterion Covered Total %
statement 215 232 92.6
branch 100 116 86.2
condition 49 64 76.5
subroutine 35 37 94.5
pod 7 14 50.0
total 406 463 87.6


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