Subject: | Test::Builder::expected_tests should handle numbers that stringify to an integer |
Running under 5.8.5 built for i686-linux, the following test script:
use Test::More;
my $num_tests = 100.0000000000001;
plan tests => $num_tests;
for (1..100) {
ok(1);
}
causes the following error:
# Looks like you planned 100 tests but only ran 100
If I change $num_tests to 99.99999999999999, I get the following error:
# Looks like you planned 100 tests but ran 1.4210854715202e-14 extra.
This is because in both cases, $num_tests stringifies to 100, but the
full decimal value gets stored internally.
Test::Builder::expected_tests (line 298) verifies that a test passed in
matches /^\+?\d+$/ but it doesn't account for the possibility that a
non-integer value could serialize to an integer.
I encountered this bug while working on a set of tests where I was
automatically generating $num_tests based on a set of mathematical
calculations. I had no idea that the number of tests I was feeding to
plan wasn't an integer.
It would be optimal as an end-user if Test::Builder could ignore the
incredibly minute non-stringifiable decimal difference. I recommend
fixing this problem by changing line 300 of Test::Builder 0.70 from:
$self->{Expected_Tests} = $max;
to this:
$self->{Expected_Tests} = "$max" + 0;
A less end-user-friendly alternative would be to add something line this
around line 299:
if ($max != int $max) {
$self->croak("Number of tests must be a positive integer. You
gave it a number that stringifies to '$max', but is actually not a
positive integer, possibly because of a tiny decimal expansion")
}
Another less user-friendly alternative would be to change line 298 to:
unless $max =~ /^\+?\d+$/ and $max > 0 and $max == int $max;
I think either of these would be poor choices to make; it's confusing to
an end-user why a number that stringifies to an integer would secretly
not be an integer.