Test::Deep is a great module if you need to test deep and/or fuzzy data structures, but sometimes it does not give the correct error messages. Recently I've encountered such a case when I got tons of warnings like this:

Use of uninitialized value $got in pattern match (m//) at Test/Deep/Regexp.pm line 57.

Unfortunately the warning did not say what really caused it, but after patching the Test::Deep::Regexp I could solve the riddle.

The problem was that in my test I had something like this:

cmp_deeply \@data, array_each({
    fname => re('^.*$'),
    lname => re('^.*$'),
    ...
    email => re('^.*$'),
    address => re('^.*$')
});

with about 25 fields, each one with its own regex.

Getting a warning that one of them is undef was not really useful.

The source code of Test/Deep/Regexp.pm looked like this:

sub descend
{
        my $self = shift;
        my $got = shift;
 
        my $re = $self->{val};
        if (my $match_exp = $self->{matches})
        {
                my $flags = $self->{flags};
                my @match_got;
                if ($flags eq "g")
                {
                        @match_got = $got =~ /$re/g;
                }
                else
                {
                        @match_got = $got =~ /$re/;
                }
 
                if (@match_got)
                {
                        return Test::Deep::descend(\@match_got, $match_exp);
                }
                else
                {
                        return 0;
                }
        }
        else
        {
                return ($got =~ $re) ? 1 : 0;
        }
}

Line 57 in the original code, that generated the warning was this line: return ($got =~ $re) ? 1 : 0;.

A quick glance at the return value gave me the impression that this would indicate the success or failure of the regex.

So I changed the code and added

return 0 if not defined $got; right after copying the second parameter to the $got variable on the 2nd row of the function. So I had

sub descend
{
        my $self = shift;
        my $got = shift;
        return 0 if not defined $got;
...

Then I ran my tests again. This time the test failed and told me exactly which key in my hash was undef.

At this point I had two choices:

If having and undef there was incorrect then I'd need to fix my code, or if the undef was acceptable I could change my test to be:

     field => any(undef, re('...')),

with the appropriate regex. This expression will only try to run the regex if the value is not undef.

A full example of the problem

The following script can demonstrate the issue:

examples/undef_in_test_deep_regex.pl

use Test::More;
use Test::Deep;

plan tests => 1;

my @data = (
    {
        name => 'Foo',
    },
    {
        name => undef,
    },
);

cmp_deeply \@data, array_each({
    name => re('^.*$')
});

I have even opened a ticket with this issue, but I am not sure if my recommended solution is acceptable at all. In any case this little change helped me figuring out the source of the warnings.

Screenshots

Test::Deep example