Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is_deeply test ignoring array order?

I am looking for a test routine like is_deeply in Test::More. There's cmp_bag from Test::Deep but this only operates on the array itself, not the horribly large hash-of-arrays-of-hashes data structure I'm passing in. Is there something like:

is_deeply $got, $expected, {
    array => cmp_bag,
    # and other configuration...
}, "Ugly data structure should be the same, barring array order.";

Clarification

I could recursively delve into my $expected and $got objects and convert the arrays into bag objects:

sub bagIt {
    my $obj = shift;
    switch (ref($obj)) {
        case "ARRAY"    {
            return bag([
                map { $_ = bagIt($_) }
                @$obj
            ]);
        } case "HASH"   {
            return {
                map { $_ => bagIt( $obj->{$_} ) }
                keys %$obj
            };
        } else {
            return $obj;
        }
    }
}

I'm wondering if there is a way to tell some variant of is_deeply to do this for me.

like image 749
devoid Avatar asked Mar 01 '12 20:03

devoid


3 Answers

Well, from the Test::Deep docs,cmp_bag(\@got, \@bag, $name)is just shorthand for cmp_deeply(\@got, bag(@bag), $name).

is_deeply( $got, {
    array => bag(qw/the values you expect/),
    # and other expected values
}, "Ugly data structure should be the same, barring array order." );
like image 118
wes Avatar answered Oct 31 '22 15:10

wes


Using the bagIt function that you have written, you could always make a wrapper for is_deeply that applies bagIt for you:

sub is_deep_bag {
   splice @_, 1, 1, bagIt($_[1]); 
   goto &is_deeply  # magic goto so that errors are reported on the right line
}
like image 31
Eric Strom Avatar answered Oct 31 '22 17:10

Eric Strom


Looks like there isn't an option in Test::Deep or other Test::* packages to treat each array as a bag-set. The following function works, but is not efficient for testing over large data structures:

sub bagIt {
    my $obj = shift;
    my $ref = ref($obj);
    if ($ref eq 'ARRAY') {
        return Test::Deep::bag(
            map { $_ = bagIt($_) }
            @$obj
        );  
    } elsif ($ref eq 'HASH') {
        return {
            map { $_ => bagIt( $obj->{$_} ) } 
            keys %$obj
        };  
    } else {
        return $obj;
    }   
}

In the end, I ended up refactoring my code to not depend upon such a course-grained test.

like image 1
devoid Avatar answered Oct 31 '22 17:10

devoid