I have this function which takes an array, counts how often each item occurs, and returns an array of unique items, ordered by count first, then alphabetically sorted, and then alphabetically case-insensitive so that order does not change between runs.
use strict;
use warnings;
sub sorted {
my @elements = @_;
my %counts;
foreach my $e (@elements) {
$counts{$e}++;
}
my @sorted = sort {
$counts{$b} <=> $counts{$a} or $a cmp $b or lc $a cmp lc $b
} keys %counts;
return @sorted;
}
1;
I have this test case for it, and everything works fine:
use strict;
use warnings;
use Test::More;
use module;
is_deeply(['A', 'a', 'c', 'b'], [sorted('a', 'b', 'c', 'a', 'c', 'A', 'A')]);
done_testing();
I run it and use Devel::Cover to collect test coverage numbers. I expected 100% coverage, but branch and condition coverage is short:
HARNESS_PERL_SWITCHES=-MDevel::Cover prove -I. test.t && cover
test.t .. ok
All tests successful.
Files=1, Tests=1, 1 wallclock secs ( 0.03 usr 0.00 sys + 0.22 cusr 0.02 csys = 0.27 CPU)
Result: PASS
Reading database from ./cover_db
--------- ------ ------ ------ ------ ------ ------ ------
File stmt bran cond sub pod time total
--------- ------ ------ ------ ------ ------ ------ ------
module.pm 100.0 50.0 66.6 100.0 n/a 0.2 90.4
test.t 100.0 n/a n/a 100.0 n/a 99.8 100.0
Total 100.0 50.0 66.6 100.0 n/a 100.0 94.8
--------- ------ ------ ------ ------ ------ ------ ------
Checking the HTML report, it shows that some branches and conditions are not covered:
I don't understand why Devel::Cover thinks some branches and conditions were not covered.
It complains that the branch for T F is not covered, which would be the <=> part never being true? I have both 'a' and 'c' twice, so that <=> should return zero for that (F) and non-zero (T) when it compares the 'a' count (2) to the 'b' count (1).
For condition coverage, the report says that the case that both parts of the check are false is not covered. Again, I think I should have that covered because I have both equal counts and equal names.
What test case would I need to add to get 100% branch and condition coverage?
Or, if sort functions like this are tricky for Devel::Cover, how can I tell it to ignore these? I changed the code to
my @sorted = sort {
# uncoverable branch left
# uncoverable condition true
$counts{$b} <=> $counts{$a} or $a cmp $b or lc $a cmp lc $b
} keys %counts;
but that did get the same results.


The problem for the coverage is that it never has both the same count of the two items it compares (the
<=>condition to be0) and that they are the same (the firstcmpcondition to be0).For that we'd need to be comparing an element to itself, but the sorting routine works with keys from the frequency count, not with array elements -- so there is no two of any one element! So an element is never compared to itself and the first two conditons can never both fail.
One resolution: sort by the actual elements, then select unique ones.
As for the branch failure, I can't quite pin it down right now but a practical (working) solution is to disengage those tests. Altogether†
Now I get
(actual path on my system suppressed)
Note -- no condition at all now. FWIW: when I leave that one big, typical
sort-ish multi-or-ed condition (while sorting elements, not frequency-hash keys) then the condition does have 100% coverage. But the branch fails.† In this case of straight consecutive tests and no other processing we can also return in each branch (the block in
sortis an anonymous sub and one canreturn)