Howdy!

I'm using Test::More in my module test scripts. In testing the ways one can create a copy of an object, I use the eq_hash utility function to compare two objects (since they are hash based objects). This works fine except for one niggling detail.

A couple of the attributes are computed on the fly as needed and cached in the object. Other operations invalidate that cache as appropriate. One of the copy methods is a full copy, but the other only copies the data that must be saved, ignoring the cached data.

I'm thinking that it would be useful to have a version of eq_hash that takes a list of hash keys to ignore in the comparison.

I envision something like:

ok eq_hash($hashref1, $hashref2, [qw/key1 key2/]), 'partial hash compa +rison';

I'm open to suggestions, etc.

yours,
Michael

Replies are listed 'Best First'.
Re: Test::More extension idea
by chromatic (Archbishop) on Oct 16, 2001 at 07:52 UTC
    Yeah, that would be useful. You also could build up a temporary hash and compare that... something like:
    my %clean = %$hashref1; delete @clean{qw( key1 key2 )}; eq_hash( \%clean, $hashref2, 'partial hash comparison' );
    I dunno how Schwern would react to wanting ignorable keys... it kinda breaks the pattern of 'result, 'expected', 'test name'.

    Another approach is to add a new function. Test::More is built around Test::Builder, and it's pretty easy to add new features. Of course, I'm a *little* biased. :)

      Howdy!

      I've hacked my copy of Test::More to add eq_hash_skip.

      =item B<eq_hash_skip> eq_hash_skip(\%this, \%that, \@keys_to_ignore); Determines if the two hashes contain the same keys and values, not counting any hash keys in the list of keys to ignore. This is a deep c +heck. Note that the list of keys to ignore is only considered against the top level hashes. Deeper structures must match exactly. If the list of keys to ignore is missing or empty, this is identical to eq_hash. =cut sub eq_hash_skip { my ($a1, $a2, $skip) = @_; return eq_hash($a1, $a2) unless (defined($skip) && @$skip); return 1 if $a1 eq $a2; my %keys_of_interest = map {($_, 1)} keys %$a1, keys %$a2; delete @keys_of_interest{@$skip}; my $ok = 1; foreach my $k (keys %keys_of_interest) { return 0 unless exists $a1->{$k}; return 0 unless exists $a2->{$k}; my($e1, $e2) = ($a1->{$k}, $a2->{$k}); $ok = _deep_check($e1, $e2); last unless $ok; } return $ok; }

      I've also added some tests to More.t to test this out :)

      I'll be corresponding with Schwern, but for the instant, I am using it this way:

      <CODE> ok eq_hash(\%hash1, \%hash2, qw/ key1 key2 / ), 'test name'; <CODE>

      yours,
      Michael