1

I'm writting some generators and an Arbitrary, but is too slow (see the GC numbers also). I think I have an error on my code, but I can't figure out where. Or my approach (map2 (fold)) is "weird"?.

Generators:

type Generators () =

    static let notAllowed = Array.append [| '0'..'9' |] [| '\n'; '\r'; '['; ']'; '/'; |] 

    static let containsInvalidValues (s : string)  = s.IndexOfAny(notAllowed) <> -1

    static member positiveIntsGen() = Arb.generate<PositiveInt> |> Gen.map int

    static member separatorStringGen() =                         
        Arb.generate<NonEmptyString> 
        |> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))

Arbitrary:

let manyNumbersNewLineCustomDelimiterStrInput = 
    Gen.map2 (fun (ints : int[]) (nes : NonEmptyString) ->             
        Array.fold (fun acc num ->                 
            if num % 2 = 0 then acc + "," + num.ToString()
            else if num % 3 = 0 then acc + "\n" + num.ToString()
            else acc + "\n" + num.ToString()) ("//[" + nes.Get + "]\n") ints ) 
        (Generators.array12OfIntsGen()) 
        (Generators.separatorStringGen())
    |> Arb.fromGen

The configuration have the MaxTest = 500 and it takes ~5 minutes to complete.

Output (using #timer):

StrCalcTest.get_When pass an string that starts with "//[" and contains "]\n" use the multicharacter value between them as separator-Ok, passed 500 tests.

Real: 00:07:03.467, CPU: 00:07:03.296, GC gen0: 75844, gen1: 71968, gen2: 4

1 Answers1

2

Without actually testing anything, my guess would be that the problematic part is this:

Arb.generate<NonEmptyString> 
|> Gen.suchThat (fun s -> s.Get.Length < 5 && not (s.Get |> containsInvalidValues))

This means that you will generate strings and filtering out all those that satisfy certain conditions. But if the conditions are too restrictive, FsCheck might need to generate a very large number of strings until you actually get some that pass the test.

If you can express the rule so that you are generating the strings so that everything you generate is a valid string, then I think it should be faster.

Could you, for example, generate a number n (for the string length) followed by n values of type char (that satisfy your conditions) and then append them to form the separator string? (I think FsCheck's gen { .. } computation might be a nice way of writing that.)

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • You were right, thx! I ended up with something like [this](http://stackoverflow.com/questions/26255550/fscheck-generating-string-with-size-between-min-max). A final quick-question: do you know if is possible to create `Generators` out of an static type on a fsx file? I can't :( –  May 22 '16 at 01:10
  • I don't know - sorry! – Tomas Petricek May 22 '16 at 01:35