Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing FsCheck from generating NaN and infinities

I have a deeply nested datastructure with floats all over the place. I'm using FsCheck to check if the data is unchanged after serializing and then deserializing.

This property fails, when a float is either NaN or +/- infinity, however, such a case doesn't interest me, since I don't expect these values to occur in the actual data.

Is there a way to prevent FsCheck from generating NaN and infinities?

I have tried discarding generated data that contains said values, but this makes the test incredibly slow, so slow in fact, that the test is still running while I'm writing this, and I have my doubts it will actually finish...

like image 434
phaz Avatar asked Jul 30 '14 00:07

phaz


2 Answers

For reflectively generated types that contain floats (as I suspect you're using) you can overwrite the default generator for floats by writing a class as follows:

type Overrides() =
    static member Float() =
        Arb.Default.Float()
        |> filter (fun f -> not <| System.Double.IsNaN(f) &&
                            not <| System.Double.IsInfinity(f)) 

And then calling:

Arb.register<Overrides>()

Before FsCheck tries to generate the types; e.g. in your test setup or before calling Check.Quick.

You can check the result of the register method to see how it merged the default arbitrary instances with the new ones; it should have overridden them.

If you are using the xUnit extension you can avoid calling the Arb.register by using the Arbitraries argument of PropertyAttribute:

[<Property(Arbitraries=Overides)>]
like image 110
Kurt Schelfthout Avatar answered Oct 03 '22 08:10

Kurt Schelfthout


As Mauricio Scheffer said, you can use NormalFloat type in test parameter.

Simple example for list of floats:

open FsCheck

let f (x : float list) = x |> List.map id

let propFloat (x : float list) = x = (f x)

let propNormalFloat (xn : NormalFloat list) = 
    let x = xn |> List.map NormalFloat.get
    x = f x

Check.Quick propFloat
//Falsifiable, after 18 tests (13 shrinks) (StdGen (761688149,295892075)):
//[nan]

Check.Quick propNormalFloat
//Ok, passed 100 tests.
like image 41
jindraivanek Avatar answered Oct 03 '22 08:10

jindraivanek