Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Overloadding array_each when Unit testing with Test::Deep

by willjones (Sexton)
on Jun 19, 2013 at 19:46 UTC ( #1039836=perlquestion: print w/replies, xml ) Need Help??

willjones has asked for the wisdom of the Perl Monks concerning the following question:

Alright, I've spent way too long trying to figure out a way to make this work like I want. Perhaps the perlmonks can help me. :)

I basically want what array_each does only I want it to support a hash OR an array. If it gets a hash it should just do a standard hash to hash comparison, if it gets an array it should do what array_each normally does.

I at first tried to make my own sub called array_each_orHash that took a comparator value. Here's the code I wrote...

sub array_each_orHash { my $comparator = shift; my $handleArrayOrHash = sub { my $data = shift; return array_each($comparator) if (ref($data) eq "ARRAY"); return $comparator if (ref($data) eq "HASH"); }; return code( \&$handleArrayOrHash ); }

This was mysteriously always resulting in a passed test, until I realized the mystery. I wasn't supposed to return an object when using the "code( ... )" sub I was supposed to return 0 or 1, or an array with 0 and the reason it failed. Okay, so then I modified it a bit...

sub array_each_orHash { my $comparator = shift; my $handleArrayOrHash = sub { my $data = shift; my $result = (0, 'must pass an ARRAY or HASH'); $result = eq_deeply($data, array_each($comparator)) if (ref($data) +eq "ARRAY"); $result = eq_deeply($data, $comparator) if (ref($data) eq "HASH"); return $result; }; return code( \&$handleArrayOrHash ); }

This actually works except I get no useful debugging diagnostic info except that the test failed. And the diagnostic I do get tells me a CODE block was run. I don't really want that to be displayed. The "code" was really just a means to an end so I could try to overload array_each.

I thought about making my own cmp_deeply sub that actually just checks for array_each with a non-array and if found calls the real cmp_deeply without the array_each. If not found then it could call the real cmp_deeply with the array value and array_each. But the problem with this approach is in handling cases where the array_each is embedded deeply within a value's structure. Do I write my own recursive deep diving routine to search for array_each (Test::Deep::ArrayEach) class instances and look for what they are comparing against somehow? No way!

Ok, so what is the correct way to do this? It seems like simply making my own version of Test::Deep::ArrayEach is really the best solution here. Adding something like Test::Deep::ArrayEachOrHash. But I don't know how to make my own ArrayEach like this and haven't found useful information on how to do something like that. I did find the following code here: (Shown below)

But, how do I make my own "array_each_orHash" keyword and connected it to some code in package Test::Deep::ArrayEachOrHash? Am I grossly over-complicating things here or going the wrong direction with this? Any help would be appreciated. Thanks...

use strict; use warnings; package Test::Deep::ArrayEach; use Test::Deep::Cmp; sub init { my $self = shift; my $val = shift; $self->{val} = $val; } sub descend { my $self = shift; my $got = shift; my $exp = [ ($self->{val}) x @$got ]; return Test::Deep::descend($got, $exp); } 1;

Replies are listed 'Best First'.
Re: Overloadding array_each when Unit testing with Test::Deep
by willjones (Sexton) on Jun 20, 2013 at 15:49 UTC

    Actually, I figured out how this could be done on my own.

    I located the following link showing more Test Deep source code which helped:

    Here's the solution for whoever may be interested in what the answer is.

    Create a .pm file with the following contents:

    package Test::Deep; use strict; use warnings; { *{array_each_orHash} = sub { require "Test/Deep/"; my $obj = Test::Deep::ArrayEachOrHash->new(@_); return $obj; }; push(@Test::Deep::EXPORT, "array_each_orHash"); } 1;

    Next create a folder called Test with a subfolder called Deep and then create a new file called and put the following into it:

    package Test::Deep::ArrayEachOrHash; use strict; use warnings; use Test::Deep::Cmp; sub init { my $self = shift; my $val = shift; $self->{val} = $val; } sub descend { my $self = shift; my $got = shift; my $result; if ( ref($got) eq "ARRAY" ) { my $exp = [ ($self->{val}) x @$got ]; $result = Test::Deep::descend($got, $exp); } else { my $exp = $self->{val}; $result = Test::Deep::descend($got, \%$exp); } return $result; } 1;

    Now be sure to use the first pm module, whatever you named it, from your main source file and it should cause a new keyword to be available for Test::Deep to use called "array_each_orHash".

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1039836]
Approved by jfroebe
Front-paged by Old_Gray_Bear
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (8)
As of 2020-07-10 19:38 GMT
Find Nodes?
    Voting Booth?

    No recent polls found