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

I hate erroneous error messages. Like benign warnings. They only serve to hide true problems. Like doing a testcover on a module, seeing that you're only getting 63.2% conditional coverage, and then noticing that one of them is for code like this:

my $var = $opts->{foo} || $self->{default_foo};
when $self->{default_foo} is very carefully never allowed to be bad (a default provided in new, and the setter function not allowing bad values, including no value). And then Devel::Cover posits:
86367
ABdec
000
011
1X1
my $var = $opts->{foo} || $self->{default_foo};
(I can't use "style=" attributes, but the 0 0 0 line shows up in red because it's not being tested.) Is there any way to turn off that row, or otherwise tell Devel::Cover to ignore that possibility because I, as the human, have concluded it's not possible to reach?

Update: I guess I should read the TODO file:

- Marking of unreachable code - commandline tool and gui.
Not entirely sure how said tool would work, but that's the basic idea. I kinda like my comment idea better - because I'm much less likely to lose checked-in code than the cover_db database, where I presume the "unreachable code" will be remembered.

Replies are listed 'Best First'.
Re: Devel::Cover and impossible codepaths
by ikegami (Patriarch) on Nov 14, 2009 at 18:39 UTC
    No idea, but using one of the following would satisfy Devel::Cover:
    my $var = $self->{default_foo}; $var = $opts->{foo} if $opts->{foo};
    my $var = $opts->{foo} ? $opts->{foo} : $self->{default_foo};

    Devel::Cover doesn't seem to recognize the common idiom of using "||" where only the LHS is part of the condition.

Re: Devel::Cover and impossible codepaths
by ikegami (Patriarch) on Nov 14, 2009 at 18:42 UTC
    I wonder if it gives a problem for
    my $var = ( $opts->{foo} or $self->{default_foo} );

      Thanks, but this one doesn't solve the issue - I don't think you're surprised by the fact that at the end of the day, || and or probably both use the same opcodes, so they're going to result in the same codepaths to Devel::Cover. The other solutions result in things that look like they might take longer (didn't benchmark yet to be sure), especially since $opts->{foo} really is $self->get_field($opt->{field})->{foo}, so, even if get_field is O(N), it has a significantly higher constant, and so evaluating it twice is an annoyance I'd prefer not to embrace. The || idiom is really perfect here from a readability, maintainability, and speed perspective. It just isn't what Devel::Cover seems to like.

      This is why I was hoping for some generic way to tell Devel::Cover to ignore a certain case. e.g., something like:

      ### Devel::Cover: 0 0 ### I know that $self->{default_foo} is neve +r false. my $var = $opts->{foo} || $self->{default_foo};
      I guess my alternative is to stop initialising default_foo in the constructor, and have that as a fall-back here:
      my $var = $opts->{foo} || $self->{default_foo} || "default value";
      Maybe Devel::Cover will be able to see there is no way for the last option to be false, and omit it. But then if I want to have a get-routine that gets its current default_foo, I'd have this default in two places, and that is one of the evils I am constantly battling at $work already, so I don't want to go down that road.

        my $var = $opts->{foo} || $self->{default_foo} || "PLACATE DEVEL::COVE +R";

        Update: Never mind, that doesn't help. It's still going to expect the second condition to be false in some test.