I am doing some property testing in F# using FsCheck. I therefore wish to guarantee that certain conditions always hold, regardless of input arguments.
Consider I define a trivial identity function for float
values.
let floatId (x : float) = x
I then define a test of this function which I know should always hold:
let ``floatId returns input float`` x = floatId x = x
This is a trivial test, I am just checking that calling my float identity function returns the same as the input float.
I then plug this function into FsCheck:
Check.Quick ``floatId returns input float``
Unfortunately, this property test fails!
Falsifiable, after 21 tests (0 shrinks) (StdGen (1872424299,296201373)): Original: nan
Of course, looking back, it was pretty obvious this was going to happen, we know that nan <> nan
.
Due to structural comparison in F#, this can plague (slightly) more complex test cases involving collections too.
If I design a similar function for float lists:
let listFloatId (lst : float list) = lst
let ``listFloatId returns input float list`` lst = listFloatId lst = lst
Falsifiable, after 6 tests (3 shrinks) (StdGen (1874889363,296201373)): Original: [nan; 2.0; 2.25; 4.940656458e-324] Shrunk: [nan]
Same problem again!
Obviously I can engineer around this problem by creating my own equality testing functions, that's fine for float
values but it becomes more complex to extend to collections like list
since I have to start using List.forall2
with my custom equality function and generally specialising my code to each individual collection type.
Is there a general way of solving this problem in F#?