Skip to content

Instantly share code, notes, and snippets.

@kurtschelfthout
Last active December 17, 2017 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kurtschelfthout/f8b7397a53f8bd0244178c95511cee3a to your computer and use it in GitHub Desktop.
Save kurtschelfthout/f8b7397a53f8bd0244178c95511cee3a to your computer and use it in GitHub Desktop.
Debunking some hedgehog marketing

Hedgehog in its tutorial provides some marketing that illustrates its "integrated shrinking", claiming that FsCheck cannot do this. There are in fact, a number of ways to rewrite their example so it also shrinks in FsCheck.

The original example hedgehog gives is:

let version =
    Arb.generate<byte>
    |> Gen.map int
    |> Gen.three
    |> Gen.map (fun (ma, mi, bu) -> Version (ma, mi, bu))
    |> Gen.listOf
    |> Arb.fromGen

version
|> Prop.forAll <| fun xs -> xs |> List.rev = xs
|> Check.Quick

Now obviously this does not shrink in FsCheck - because of the Arb.fromGen the shrinker is basically explicitly disabled...

Here's a shorter way to write the Arbitrary which does shrink:

let version =
    Arb.from<list<byte * byte * byte>>
    |> Arb.convert (List.map (fun (ma,mi,bu) -> Version (int ma,int mi,int bu)))
                   (List.map (fun v -> (byte v.Major,byte v.Minor, byte v.Build)))

version
|> Prop.forAll <| fun xs -> xs |> List.rev = xs
|> Check.Quick
Falsifiable, after 2 tests (14 shrinks) (StdGen (1663895886,296389250)):
Original:
[93.69.212; 80.126.246; 69.180.214]
Shrunk:
[0.0.1; 0.0.0]
val it : unit = ()

Here's another way to do it:

Arb.from<list<byte * byte * byte>>
|> Prop.forAll  <| fun xs -> 
    let vs = List.map (fun (ma,mi,bu) -> Version(int ma,int mi,int bu)) xs
    vs |> List.rev = vs 
    |> Prop.label (vs.ToString())
|> Check.Quick

which gives:

Falsifiable, after 2 tests (13 shrinks) (StdGen (1974807201,296389254)):
Label of failing property: [0.0.1; 0.0.0]
Original:
[(89uy, 207uy, 241uy); (8uy, 42uy, 160uy)]
Shrunk:
[(0uy, 0uy, 1uy); (0uy, 0uy, 0uy)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment