Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force FsCheck to generate NonEmptyString for discriminating union fields of type string

I'm trying to achieve the following behaviour with FsCheck: I'd like to create a generator that will generate a instance of MyUnion type, with every string field being non-null/empty.

type MyNestedUnion =
    | X of string
    | Y of int * string

type MyUnion =
    | A of int * int * string * string
    | B of MyNestedUnion

My 'real' type is much larger/deeper than the MyUnion, and FsCheck is able to generate a instance without any problem, but the string fields of the union cases are sometimes empty. (For example it might generate B (Y (123, "")))

Perhaps there's some obvious way of combining FsCheck's NonEmptyString and its support for generating arbitrary union types that I'm missing?

Any tips/pointers in the right direction greatly appreciated.

Thanks!

like image 721
Edward Dewhurst Avatar asked Aug 15 '17 13:08

Edward Dewhurst


1 Answers

This goes against the grain of property based testing (in that you explicitly prevent valid test cases from being generated), but you could wire up the non-empty string generator to be used for all strings:

type Alt =
    static member NonEmptyString () : Arbitrary<string> =
        Arb.Default.NonEmptyString()
        |> Arb.convert
            (fun (nes : NonEmptyString) -> nes.Get)
            NonEmptyString.NonEmptyString

Arb.register<Alt>()

let g = Arb.generate<MyUnion>

Gen.sample 1 10 g

Note that you'd need to re-register the default generator after the test since the mappings are global.

A more by-the-book solution would be to use the default derived generator and then filter values that contain invalid strings (i.e. use ==>), but you might find it not feasible for particularly deep nested types.

like image 104
scrwtp Avatar answered Oct 17 '22 03:10

scrwtp