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.
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." );
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With