Skip to content

Support generating indirectly recursive records consistently #734

@brianrourkeboll

Description

@brianrourkeboll

FsCheck currently has inconsistent support for generating indirectly recursive records.

If a record type is immediately recursive, FsCheck raises an exception. No problem; that makes sense.

#r "nuget: FsCheck,3.3.2"

open FsCheck.FSharp

type R = { R : R }

ArbMap.defaults
|> ArbMap.generate<R>
|> Gen.sample 3
// System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
// ---> System.Exception: Recursive record types cannot be generated automatically: …

But if the record type is not immediately recursive, the user experience is not ideal: the user either sees a stack overflow exception, or, if FsCheck is being run via another test runner (xUnit, NUnit), the test seems simply not to run at all, because the test process crashes.

#r "nuget: FsCheck,3.3.2"

open FsCheck.FSharp

type R = { Rs : R list }

ArbMap.defaults
|> ArbMap.generate<R>
|> Gen.sample 3
// Stack overflow 😭.

FsCheck actually does support generating indirectly recursive records in one scenario: the record is recursive through a mutually-recursive multi-case union:

#r "nuget: FsCheck,3.3.2"

open FsCheck.FSharp

type R = { U : U }
and U = U of R | V of int

ArbMap.defaults
|> ArbMap.generate<R>
|> Gen.sample 3
// [|{ U = V -10 }; { U = U { U = U { U = U { U = V 27 } } } }; { U = V 8 }|]

Is there a good reason for FsCheck not to apply size-control logic similar to what it already does for mutually-recursive unions to all indirectly-recursive records by default, instead of just blowing the stack and forcing the user to write a custom generator? (There could well be a good reason. That's why I'm asking.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions