Final one tonight! eq_array and eq_hash don't tidy up after themselves. You would have to be very unfortunate to be stung by this problem but potentially you could end up with extra references to some of your variables which could effect tests further on due to DESTROYs not being called or whatever.
use Test::More; for(1..10) { eq_array( [[]], [{}] ) } print join(", ", @Test::More::Data_Stack)."\n"; The solution is to make eq_array and eq_hash wrappers around the original functions. This is needed for the circular structures patch anyway. Actually, I've gone a little further and made them wrappers around a new eq_deeply(). All they do is check that the second argument is of the correct type. This means that all the localling of @Data_Stack is only done in eq_deeply. It also means they won't die anymore if the wrong kind of arguments are passed in. Although, I'm not sure if this is a good idea, maybe dying is preferable. Patch attached. Also attached is a test script that exercises the various comparison functions. It's missing a few cases but it covers a fair bit, F -- Do you need someone with lots of Unix sysadmin and/or lots of OO software development experience? Go on, giz a job. My CV - http://www.fergaldaly.com/cv.html
--- lib/Test/More.pm.orig 2003-02-27 20:54:34.000000000 +0000 +++ lib/Test/More.pm 2003-02-28 00:11:47.000000000 +0000 @@ -25,7 +25,7 @@ cmp_ok skip todo todo_skip pass fail - eq_array eq_hash eq_set + eq_array eq_hash eq_set eq_deeply $TODO plan can_ok isa_ok @@ -996,6 +996,12 @@ return $out; } +sub eq_deeply { + my ($a1, $a2) = @_; + + local @Data_Stack = (); + return _deep_check($a1, $a2); +} =item B<eq_array> @@ -1007,7 +1013,14 @@ =cut #'# -sub eq_array { + +sub eq_array { + my ($a1, $a2) = @_; + + return UNIVERSAL::isa($a2, "ARRAY") ? return eq_deeply($a1, $a2) : 0; +} + +sub _eq_array { my($a1, $a2) = @_; return 1 if !ref $a1 and ! ref $a2 and $a1 eq $a2; @@ -1042,12 +1055,12 @@ if( UNIVERSAL::isa($e1, 'ARRAY') and UNIVERSAL::isa($e2, 'ARRAY') ) { - $ok = eq_array($e1, $e2); + $ok = _eq_array($e1, $e2); } elsif( UNIVERSAL::isa($e1, 'HASH') and UNIVERSAL::isa($e2, 'HASH') ) { - $ok = eq_hash($e1, $e2); + $ok = _eq_hash($e1, $e2); } elsif( UNIVERSAL::isa($e1, 'REF') and UNIVERSAL::isa($e2, 'REF') ) @@ -1084,6 +1097,12 @@ =cut sub eq_hash { + my ($a1, $a2) = @_; + + return UNIVERSAL::isa($a2, "HASH") ? return eq_deeply($a1, $a2) : 0; +} + +sub _eq_hash { my($a1, $a2) = @_; return 1 if !ref $a1 and ! ref $a2 and $a1 eq $a2;
# -*-perl-*- use strict; use Test::More (tests => 18); { my $a = []; my $b = $a.""; ok(! eq_deeply([$a], [$b]), "stringified"); } { # take an array full of a variety of things and break each one my @a1 = an_array(); my @a2 = an_array(); is_deeply([EMAIL PROTECTED], [EMAIL PROTECTED], "is array"); ok(eq_array([EMAIL PROTECTED], [EMAIL PROTECTED]), "eq array"); for (my $i = 0; $i < @a1; $i++) { my @new = an_array(); my $it = $new[$i]; my $broken = break_it($it); $new[$i] = $broken; ok(! eq_array([EMAIL PROTECTED], [EMAIL PROTECTED]), "array broken ref='".ref($broken)."'"); } my @new = an_array(); break_it([EMAIL PROTECTED]); ok(! eq_array([EMAIL PROTECTED], [EMAIL PROTECTED]), "array broken extra"); } { # take a hash full of a variety of things and break each one my %a1 = a_hash(); my %a2 = a_hash(); is_deeply(\%a1, \%a2, "is hash"); ok(eq_hash(\%a1, \%a2), "eq hash"); foreach my $key (keys %a1) { my %new = a_hash(); my $it = $new{$key}; my $broken = break_it($it); $new{$key} = $broken; ok(! eq_hash(\%new, \%a1), "hash broken ref='".ref($broken)."'"); } my %new = a_hash(); break_it(\%new); ok(! eq_hash(\%new, \%a1), "hash broken extra"); } # test a messy complex thing is_deeply(complex_thing(), complex_thing(), "complex"); sub an_array { return ( [], {}, "hello", \"ref", \['hello'] ); } sub a_hash { return ( key1 => [], key2 => {}, key3 => "hello", key4 => \"ref", key5 => \['hello'] ); } sub break_it { my $it = shift; if (UNIVERSAL::isa($it, 'ARRAY')) { push(@$it, "extra elem"); } elsif (UNIVERSAL::isa($it, 'HASH')) { $it->{"extra key"} = "extra value"; } elsif (UNIVERSAL::isa($it, 'REF')) { $it = \['a different ref']; } elsif (UNIVERSAL::isa($it, 'SCALAR')) { $it = \"$$it and something else"; } else { $it = "$it something else"; } return $it } sub complex_thing { my $b = [qw( hello world)]; my $a = [ { key1 => \$b, key2 => [{}], key3 => \'scalarref', key4 => 'scalar', }, [\"scalarref"], ]; return $a; }