jqwik-team / jqwik

Property-Based Testing on the JUnit Platform
http://jqwik.net
Eclipse Public License 2.0
551 stars 63 forks source link

Bug: Uniform Distribution of Integers does not work if range is >= Integer.MAX_VALUE #544

Closed jlink closed 5 months ago

jlink commented 6 months ago

Testing Problem

Consider the following test:

@Example
void integers() {
    IntegerArbitrary integers = Arbitraries.integers().withDistribution(RandomDistribution.uniform());
    integers.sampleStream().limit(50).forEach(System.out::println);
}

Which will only create three different values:

-2147483647
-2147483648
1

Discussion

The problem is the implementation of SmallUniformGenerator:

class SmallUniformNumericGenerator implements RandomDistribution.RandomNumericGenerator {

    private final int min;
    private final int max;

    SmallUniformNumericGenerator(BigInteger min, BigInteger max) {
        this.min = min.intValueExact();
        this.max = max.intValueExact();
    }

    @Override
    public BigInteger next(Random random) {
        int bound = Math.abs(max - min) + 1;
        int value = random.nextInt(bound >= 0 ? bound : Integer.MAX_VALUE) + min;
        return BigInteger.valueOf(value);
    }
}

which should only be used if max-min < Integer.MAX_VALUE. See:

public class UniformRandomDistribution implements RandomDistribution {

    @Override
    public RandomNumericGenerator createGenerator(
        int genSize,
        BigInteger min,
        BigInteger max,
        BigInteger center
    ) {
        // Small number generation can be faster
        if (isWithinIntegerRange(min, max)) {
            return new SmallUniformNumericGenerator(min, max);
        } else {
            return new BigUniformNumericGenerator(min, max);
        }

    }

    private static boolean isWithinIntegerRange(BigInteger min, BigInteger max) {
        return min.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) >= 0
            && max.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) <= 0;
    }
}
jlink commented 5 months ago

Fixed in https://github.com/jqwik-team/jqwik/commit/0313063d12389aacefd4ed9a2849efb2e8ff31c3

jlink commented 5 months ago

Released in 1.8.3-SNAPSHOT