Use of uninitialized value $got in pattern match (m//) at Test/Deep/Regexp.pm line 57.
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
Published on 2016-06-03