Is there a way to generate a string in FsCheck by selecting just one item from each of a list of strings and then concatenating the result?
I'm just completely stuck and can't seem to figure it out. I've looked at the docs and in the github repo for something similar. And I've done most of my reading on FsCheck from FSharpForFunAndProfit.
This is something like what I would be thinking of:
let rand = System.Random()
let randInt max = rand.Next(0, max)
let selectLetter (string: string) =
let whichLettersIndex = String.length string |> randInt
string.Substring(whichLettersIndex, 1)
let generateOddlySpelledWord listOfStrings =
List.map selectLetter listOfStrings
|> String.concat ""
let usingGenerateOddlySpelledWord =
generateOddlySpelledWord ["zZ"; "oO0Ò"; "eEê"]
That should generate something like "Z0ê" or "zÒE".
Does this do what you want?
open FsCheck
let createGenerators (l : string seq) =
l |> Seq.map Gen.elements |> Seq.toList
type OddlySpelledWords =
static member String() =
["zZ"; "oO0Ò"; "eEê"]
|> createGenerators
|> Gen.sequence
|> Gen.map (List.map string >> String.concat "")
|> Arb.fromGen
Ad-hoc test:
open FsCheck.Xunit
[<Property(Arbitrary = [| typeof<OddlySpelledWords> |])>]
let test (s : string) =
printfn "%s" s
Output (truncated):
z0ê
ZÒe
ZOe
zoê
ZÒe
zoê
Z0e
zoê
z0ê
ZOe
zÒê
z0E
zoe
Explanation
The createGenerators
function has the type seq string -> Gen<char> list
, and it creates a Gen
from each string using Gen.elements
, because a string is also a char seq
; Gen.elements
creates a Gen
that will pick one of these char
values from each string.
Then it uses Gen.sequence
to convert the Gen<char> list
into a Gen <char list>
, and then maps from there.
BTW, you can also inline createGenerators
:
type OddlySpelledWords =
static member String() =
["zZ"; "oO0Ò"; "eEê"]
|> List.map Gen.elements
|> Gen.sequence
|> Gen.map (List.map string >> String.concat "")
|> Arb.fromGen
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With