Closed BennieCopeland closed 4 months ago
Ok, so the sizes actually work, it had to do with how I am writing my generators. I'm not sure why this works
public override Gen<EmailAddress> Generator
{
get
{
return new SizedUnicodeStringGenerator()
.Generator
.Resize(EmailAddress.MaxSize)
.Select(str => (string)str)
.Where(str => !string.IsNullOrEmpty(str) && !str.Contains('\0'))
.Select(EmailAddress.FromString)
.Select(result => result.Value);
}
}
But this doesn't
public override Gen<EmailAddress> Generator
{
get
{
return ArbMap.Default.GeneratorFor<SizedUnicodeString>()
.Resize(EmailAddress.MaxSize)
.Select(str => (string)str)
.Where(str => !string.IsNullOrEmpty(str) && !str.Contains('\0'))
.Select(EmailAddress.FromString)
.Select(result => result.Value);
}
}
The size is interpreted by generators in any way they choose. Most don't interpret it as a lower bound, but as an upper bound - the idea of size is not so much to put a hard constraint on the generated values, but to control how the size evolves through the test run. Tpically as the size gets bigger, the number of possibilities increases exponentially, and so you can only cover a tiny amount of it. So we start with generating "small" values, giving you a good chance of covering those as well as finding any "easy" bugs early in the test run. Then FsCheck increases the size to get some coverage of the bigger cases. It increases the size linearly between StartSize
and EndSize
over the course of however number of test cases you specify (100 by default)
In particular, the string
generator in the end depends on Gen.arrayOf
which does use size: https://github.com/fscheck/FsCheck/blob/master/src/FsCheck/FSharp.Gen.fs#L482 as you can see as an upper bound. That is, for size 50 it'll randomly choose a length between 0 and 50. That is, I assume, why your first code snippet fails.
I don't know exactly what difference you're seeing between the two last snippets, but perhaps Resize
is causing some confusion here. Resize
just overrides the size that is passed down from the runner to each generator, but that still doesn't force the generators to interpret the size any differently. So e.g. you may be at the last test case and FsCheck is setting a size of 100. All you're doing is overriding that to EmailAddress.MaxSize
. That will just make Gen.arrayOf
choose a length between 0 and EmailAddress.MaxSize
.
In conclusion, if you want a guaranteed hard upper bound or fixed size array/list/string, don't rely on size. Build it into your generators directly.
I just migrated my custom generators to 3.0 and I noticed it's ignoring the size requirements.
Edit: I noticed after looking at the code that this never worked to begin with. Only a few numeric types use sizes.