Reputation: 499
I'm having some trouble figuring out how to suppress / correct what is causing the warning "Use of uninitialized value $_ in pattern match"
in my perl script.
Here is the unit testing script where the warnings are being produced
Interview.t
#!/usr/bin/perl
use warnings;
use strict;
use Test::More tests => 16;
use v5.10;
use Data::Dumper;
require_ok('Interview');
# Test URLs
my $test_urls = {
'http://www.reddit.com' => 1,
'hurrdurrimasheep' => 0
};
my $interview = new Interview;
# Test $interview to see if it's an instance of our 'Interview' class
isa_ok($interview, 'Interview');
# Test to see if $interview has the member functions 'a' and 'b'
can_ok($interview, qw/a b/);
eval { $interview->a; };
cmp_ok($@, '=~', /Oh boy, thats blown to bits/, 'Interview->a dies as expected when no url argument is given.');
eval { $interview->b; };
cmp_ok($@, '=~', /Rubbish/, "Interview->b dies as expected when there are no results in Interview->{'r'}");
# Test to see if the return value from $interview's 'a' member function
# will either be '1' or '0'.
foreach my $url (keys $test_urls) {
cmp_ok($interview->a($url), 'eq', $test_urls->{$url}, "Got expected result for Interview->a($url): [ $test_urls->{$url} ]");
}
open(STDOUT, ">/dev/null") || die "Can't redirect stdout";
my $interview_url_results = $interview->b;
close(STDOUT);
my $num_test_urls = keys scalar $test_urls;
my $num_interview_urls = keys scalar $interview_url_results;
cmp_ok($num_test_urls, '==', $num_interview_urls, "Got expected number of urls returned from Interview->b(): [ $num_test_urls ]");
# The following test ensures that the Interview->b() member function
# is storing the codes returned from Interview->a() correctly.
foreach my $url (keys $interview_url_results) {
my $expected_code = $test_urls->{$url};
my $returned_code = $interview->{'r'}->{$url};
cmp_ok($expected_code, '==', ($returned_code == 200 ? 1 : 0), "Got expected http code from Interview->b() for $url");
}
done_testing;
Interview.pm
package Interview;
use strict;
use warnings;
sub new {
my $c = shift;
return bless {}, $c;
}
sub a {
my ($self, $u) = @_;
die 'Oh boy, thats blown to bits' if ! $u;
my $c = "curl -sL -w '%{http_code} %{url_effective}' '$u' -o /dev/null";
`$c` =~ /^(\d+)\s/;
$self->{'r'}->{$u} = $1;
return $self->{'r'}->{$u} == 200 ? 1 : 0;
}
sub b {
my $self = shift;
die 'Rubbish' if ! $self->{'r'};
foreach my $u (keys %{$self->{'r'}}) {
print "Results: $u -- $self->{'r'}->{$u}\n";
}
return $self->{'r'};
}
1;
Output:
[ ¯\_(ツ)_/¯ ~/Development/Interview ]: perl Interview.t
1..10
ok 1 - require Interview;
ok 2 - The object isa Interview
ok 3 - Interview->can(...)
Use of uninitialized value $_ in pattern match (m//) at Interview.t line 27.
ok 4 - Interview->a dies as expected when no url argument is given.
Use of uninitialized value $_ in pattern match (m//) at Interview.t line 31.
ok 5 - Interview->b dies as expected when there are no results in Interview->{'r'}
ok 6 - Got expected result for Interview->a(hurrdurrimasheep): [ 0 ]
ok 7 - Got expected result for Interview->a(http://www.reddit.com): [ 1 ]
ok 8 - Got expected number of urls returned from Interview->b(): [ 2 ]
ok 9 - Got expected http code from Interview->b() for hurrdurrimasheep
ok 10 - Got expected http code from Interview->b() for http://www.reddit.com
You can see the warnings right after test 3 and 4. What am I missing here?
Upvotes: 1
Views: 3399
Reputation: 386386
The warning is coming from the following line:
cmp_ok($@, '=~', /Oh boy, thats blown to bits/, ...);
You want to pass a regex pattern to cmp_ok
, but instead, you pass a value indicating whether $_
contains Oh boy, thats blown to bits
or not. The warning comes from the fact that you never assigned anything to $_
. But the real problem is that you should have used
cmp_ok($@, '=~', qr/Oh boy, thats blown to bits/, ...);
But that still suffers from a second problem. When no exceptions occur, $@
will be undef
, so cmp_ok
will issue a warning when it checks the pattern against $@
. like
is not only simpler in this case, but it handles undef
without a warning.
like($@, qr/Oh boy, thats blown to bits/, ...);
Upvotes: 6
Reputation: 2935
You need to use the qr
operator to define a regex and not a match. If you use /regex/
, you want to match it immediately, but you want the operator =~
to be used with the two arguments. This line would give the wanted result:
cmp_ok($@, '=~', qr/Oh boy, thats blown to bits/, 'Interview->a dies as expected when no url argument is given.');
Upvotes: 0
Reputation: 93735
Like @ikegami points out, this line:
cmp_ok($@, '=~', /Oh boy, thats blown to bits/);
should actually be:
cmp_ok($@, '=~', qr/Oh boy, thats blown to bits/);
because qr/xxx/
is a regex scalar, but /xxx/
actually evaluates the regex against $_
.
However, an even better solution is to use the like()
function rather than cmp_ok()
.
like($@, qr/Oh boy, thats blown to bits/);
Upvotes: 5
Reputation: 53498
Line 27 is:
cmp_ok($@, '=~', /Oh boy, thats blown to bits/, 'Interview->a dies as expected when no url argument is given.');
So, what's in $@
at this point? I would guess - eval { $interview->a; };
is returning undef. So you might want to test if it's defined
first.
Upvotes: 2