Search code examples
javaproperty-based-testingjqwik

Better Arbitrary Number?


I need an Arbitrary java.lang.Number.

Here is what I came up with:

    @Provide
    Arbitrary<Number> numbers(){
        return
        Combinators.combine(
                Arbitraries.integers().between(0, 5),
                Arbitraries.integers(),
                Arbitraries.longs(),
                Arbitraries.bigIntegers(),
                Arbitraries.floats(),
                Arbitraries.doubles(),
                Arbitraries.bigDecimals()
        ).as((i, intA, longA, bigIntegerA, floatA, doubleA, bigDecimalA) ->
          new Number[]{intA, longA, bigIntegerA, floatA, doubleA, bigDecimalA}[i]
        );
    }

This kind of works but causes

STANDARD_ERROR
10:17:38      Aug 24, 2022 2:17:38 PM net.jqwik.engine.properties.RandomizedShrinkablesGenerator logEdgeCasesOutnumberTriesIfApplicable
10:17:38      INFO: Edge case generation exceeds number of tries. Stopped after 1000 generated cases.

Is there a better way to implement an Arbitrary that represents all the possible values of java.lang.Number?

Footnote:

For you set theorists out there:

Yes I know that I am forming a product and extracting a union, which is about the least efficient way to do this. Undoubtedly this confuses the shrinker to no end. This was the best I could do. If there is a way to do this as a simple union instead, please let me know.


Solution

  • There's a simpler solution, assuming that any concrete subtype of Number should be generated:

    @Property
    void test(@ForAll Number aNumber) {
        System.out.println(aNumber.getClass() + " = " + aNumber);
    }
    
    @Property
    void test2(@ForAll("anyNumber") Number aNumber) {
        System.out.println(aNumber.getClass() + " = " + aNumber);
    }
    
    @Provide
    Arbitrary<Number> anyNumber() {
        return Arbitraries.defaultFor(Number.class);
    }
    

    As you can see, trying to generate a Number just works. Under the hood, jqwik checks for all registered arbitrary providers that are compatible with type Number and randomly chooses between them.