App-SimpleBackuper
view release on metacpan or search on metacpan
local/lib/perl5/Test/Deep.pm view on Meta::CPAN
$cmp = scalref($data);
}
elsif(($reftype eq 'Regexp') or ($reftype eq 'REGEXP'))
{
$cmp = regexpref($data);
}
else
{
$cmp = $Test::Deep::LeafWrapper
? $Test::Deep::LeafWrapper->($data)
: shallow($data);
}
$WrapCache{$addr} = $cmp;
}
return $cmp;
}
sub _td_reftype
{
my $val = shift;
my $reftype = Scalar::Util::reftype($val);
return '' unless defined $reftype;
return $reftype unless $Test::Deep::RegexpVersion::OldStyle;
my $blessed = Scalar::Util::blessed($val);
return $reftype unless defined $blessed;
if ($blessed && $blessed eq "Regexp" and $reftype eq "SCALAR")
{
$reftype = "Regexp"
}
return $reftype;
}
sub render_stack
{
my ($var, $stack) = @_;
return $stack->render($var);
}
sub cmp_methods
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
return cmp_deeply(shift, methods(@{shift()}), shift);
}
sub requireclass
{
require Test::Deep::Class;
my $val = shift;
return Test::Deep::Class->new(1, $val);
}
# docs and export say this is called useclass, doh!
*useclass = \&requireclass;
sub noclass
{
require Test::Deep::Class;
my $val = shift;
return Test::Deep::Class->new(0, $val);
}
sub set
{
require Test::Deep::Set;
return Test::Deep::Set->new(1, "", @_);
}
sub supersetof
{
require Test::Deep::Set;
return Test::Deep::Set->new(1, "sup", @_);
}
sub subsetof
{
require Test::Deep::Set;
return Test::Deep::Set->new(1, "sub", @_);
}
sub noneof
{
require Test::Deep::Set;
return Test::Deep::Set->new(1, "none", @_);
}
sub cmp_set
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
return cmp_deeply(shift, set(@{shift()}), shift);
}
sub bag
{
require Test::Deep::Set;
return Test::Deep::Set->new(0, "", @_);
}
sub superbagof
{
require Test::Deep::Set;
return Test::Deep::Set->new(0, "sup", @_);
}
local/lib/perl5/Test/Deep.pm view on Meta::CPAN
if (ref($hash) eq "HASH")
{
like($hash->{Name}, $name_pat, "name ok");
like($hash->{Phone}, '/^0d{6}$/', "phone ok");
my $cn = $hash->{ChildNames};
if (ref($cn) eq "ARRAY")
{
foreach my $child (@$cn)
{
like($child, $name_pat);
}
}
else
{
fail("child names not an array")
}
}
else
{
fail("person not a hash");
}
This is a horrible mess and because we don't know in advance how many
children's names there will be, we can't make a plan for our test anymore
(actually, we could but it would make things even more complicated).
Test::Deep to the rescue.
=head2 With Test::Deep
my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
cmp_deeply(
$person,
{
Name => $name_re,
Phone => re('^0d{6}$'),
ChildNames => array_each($name_re)
},
"person ok"
);
This will do everything that the messy code above does and it will give a
sensible message telling you exactly what went wrong if it finds a part of
$person that doesn't match the pattern. C<re()> and C<array_each()> are
special function imported from Test::Deep. They create a marker that tells
Test::Deep that something different is happening here. Instead of just doing
a simple comparison and checking are two things exactly equal, it should do
something else.
If a person was asked to check that 2 structures are equal, they could print
them both out and compare them line by line. The markers above are similar
to writing a note in red pen on one of the printouts telling the person that
for this piece of the structure, they should stop doing simple line by line
comparison and do something else.
C<re($regex)> means that Test::Deep should check that the current piece of
data matches the regex in C<$regex>. C<array_each($struct)> means that
Test::Deep should expect the current piece of data to be an array and it
should check that every element of that array matches C<$struct>.
In this case, every element of C<< $person->{ChildNames} >> should look like a
name. If say the 3rd one didn't you would get an error message something
like
Using Regexp on $data->{ChildNames}[3]
got : 'Queen John Paul Sartre'
expect : /^(Mr|Mrs|Miss) \w+ \w+$/
There are lots of other special comparisons available, see
L<SPECIAL COMPARISONS PROVIDED> below for the full list.
=head2 Reusing structures
Test::Deep is good for reusing test structures so you can do this
my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
my $person_cmp = {
Name => $name_re,
Phone => re('^0d{6}$'),
ChildNames => array_each($name_re)
};
cmp_deeply($person1, $person_cmp, "person ok");
cmp_deeply($person2, $person_cmp, "person ok");
cmp_deeply($person3, $person_cmp, "person ok");
You can even put $person_cmp in a module and let other people use it when
they are writing test scripts for modules that use your modules.
To make things a little more difficult, lets change the person data
structure so that instead of a list of ChildNames, it contains a list of
hashes, one for each child. So in fact our person structure will contain
other person structures which may contain other person structures and so on.
This is easy to handle with Test::Deep because Test::Deep structures can
include themselves. Simply do
my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
my $person_cmp = {
Name => $name_re,
Phone => re('^0d{6}$'),
# note no mention of Children here
};
$person_cmp->{Children} = array_each($person_cmp);
cmp_deeply($person, $person_cmp, "person ok");
This will now check that $person->{Children} is an array and that every
element of that array also matches C<$person_cmp>, this includes checking
that its children also match the same pattern and so on.
=head2 Circular data structures
A circular data structure is one which loops back on itself, you can make
one easily by doing
my @b;
my @a = (1, 2, 3, \@b);
push(@b, \@a);
now C<@a> contains a reference to be C<@b> and C<@b> contains a reference to
C<@a>. This causes problems if you have a program that wants to look inside
local/lib/perl5/Test/Deep.pm view on Meta::CPAN
#pod if (ref($hash) eq "HASH")
#pod {
#pod like($hash->{Name}, $name_pat, "name ok");
#pod like($hash->{Phone}, '/^0d{6}$/', "phone ok");
#pod my $cn = $hash->{ChildNames};
#pod if (ref($cn) eq "ARRAY")
#pod {
#pod foreach my $child (@$cn)
#pod {
#pod like($child, $name_pat);
#pod }
#pod }
#pod else
#pod {
#pod fail("child names not an array")
#pod }
#pod }
#pod else
#pod {
#pod fail("person not a hash");
#pod }
#pod
#pod This is a horrible mess and because we don't know in advance how many
#pod children's names there will be, we can't make a plan for our test anymore
#pod (actually, we could but it would make things even more complicated).
#pod
#pod Test::Deep to the rescue.
#pod
#pod =head2 With Test::Deep
#pod
#pod my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
#pod cmp_deeply(
#pod $person,
#pod {
#pod Name => $name_re,
#pod Phone => re('^0d{6}$'),
#pod ChildNames => array_each($name_re)
#pod },
#pod "person ok"
#pod );
#pod
#pod This will do everything that the messy code above does and it will give a
#pod sensible message telling you exactly what went wrong if it finds a part of
#pod $person that doesn't match the pattern. C<re()> and C<array_each()> are
#pod special function imported from Test::Deep. They create a marker that tells
#pod Test::Deep that something different is happening here. Instead of just doing
#pod a simple comparison and checking are two things exactly equal, it should do
#pod something else.
#pod
#pod If a person was asked to check that 2 structures are equal, they could print
#pod them both out and compare them line by line. The markers above are similar
#pod to writing a note in red pen on one of the printouts telling the person that
#pod for this piece of the structure, they should stop doing simple line by line
#pod comparison and do something else.
#pod
#pod C<re($regex)> means that Test::Deep should check that the current piece of
#pod data matches the regex in C<$regex>. C<array_each($struct)> means that
#pod Test::Deep should expect the current piece of data to be an array and it
#pod should check that every element of that array matches C<$struct>.
#pod In this case, every element of C<< $person->{ChildNames} >> should look like a
#pod name. If say the 3rd one didn't you would get an error message something
#pod like
#pod
#pod Using Regexp on $data->{ChildNames}[3]
#pod got : 'Queen John Paul Sartre'
#pod expect : /^(Mr|Mrs|Miss) \w+ \w+$/
#pod
#pod There are lots of other special comparisons available, see
#pod L<SPECIAL COMPARISONS PROVIDED> below for the full list.
#pod
#pod =head2 Reusing structures
#pod
#pod Test::Deep is good for reusing test structures so you can do this
#pod
#pod my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
#pod my $person_cmp = {
#pod Name => $name_re,
#pod Phone => re('^0d{6}$'),
#pod ChildNames => array_each($name_re)
#pod };
#pod
#pod cmp_deeply($person1, $person_cmp, "person ok");
#pod cmp_deeply($person2, $person_cmp, "person ok");
#pod cmp_deeply($person3, $person_cmp, "person ok");
#pod
#pod You can even put $person_cmp in a module and let other people use it when
#pod they are writing test scripts for modules that use your modules.
#pod
#pod To make things a little more difficult, lets change the person data
#pod structure so that instead of a list of ChildNames, it contains a list of
#pod hashes, one for each child. So in fact our person structure will contain
#pod other person structures which may contain other person structures and so on.
#pod This is easy to handle with Test::Deep because Test::Deep structures can
#pod include themselves. Simply do
#pod
#pod my $name_re = re('^(Mr|Mrs|Miss) \w+ \w+$');
#pod my $person_cmp = {
#pod Name => $name_re,
#pod Phone => re('^0d{6}$'),
#pod # note no mention of Children here
#pod };
#pod
#pod $person_cmp->{Children} = array_each($person_cmp);
#pod
#pod cmp_deeply($person, $person_cmp, "person ok");
#pod
#pod This will now check that $person->{Children} is an array and that every
#pod element of that array also matches C<$person_cmp>, this includes checking
#pod that its children also match the same pattern and so on.
#pod
#pod =head2 Circular data structures
#pod
#pod A circular data structure is one which loops back on itself, you can make
#pod one easily by doing
#pod
#pod my @b;
#pod my @a = (1, 2, 3, \@b);
#pod push(@b, \@a);
#pod
#pod now C<@a> contains a reference to be C<@b> and C<@b> contains a reference to
#pod C<@a>. This causes problems if you have a program that wants to look inside
( run in 0.346 second using v1.01-cache-2.11-cpan-5511b514fd6 )