Should it be okay for invalid fuzzers to fail mid-test? #243
Description
It seems like the two problems with Fuzz.andThen
mentioned in #161 boil down to:
- Shrinking performance is often bad. However, as Document limitations of nested fuzzers #237 notes,
Fuzz.andThen
is only one of several ways to end up with slow tests when using fuzzers. If we need a general solution to that problem anyway, then removingFuzz.andThen
from the API doesn't solve it. - "Invalid fuzzers" can go unnoticed at runtime if they are hidden behind a
Fuzz.andThen
. They may only sometimes show up as invalid. See Can create a crash by returning an invalid fuzzer fromandThen
#160
It seems that we have only two functions that can potentially return invalid fuzzers:
Fuzz.oneOf
. This doesn't need to use the concept of invalid fuzzers. It can beoneOf : Fuzzer a -> List (Fuzzer a) -> Fuzzer a
so that it always has at least one value to work with.Fuzz.frequency
. Even it did the same "one or more" trick asFuzz.oneOf
, it would still have two invalid cases: if any of its weights aren't positive numbers, or if all the weights do not add up to a positive number.
One potential solution would be if we didn't have Fuzz.frequency
and instead only had Fuzz.oneOf
with the "requires at least one element at compile time" API.
The example in the frequency docs is:
Fuzz.frequency
[ ( 1, Fuzz.constant Leaf )
, ( 2, Fuzz.map2 Branch (tree (i - 1)) (tree (i - 1)) )
]
This could also be written:
Fuzz.oneOf
(Fuzz.constant Leaf)
(List.repeat 2 (Fuzz.map2 Branch (tree (i - 1)) (tree (i - 1)) ))
In my opinion, this is not actually better. It's worse for performance, and List.repeat
has the same problem as List.frequency
: what happens when you pass it negative numbers? We're just shifting the burden elsewhere.
Realizing this made me rethink whether it's such a problem after all that you can get invalid fuzzers midway through a test run. The whole point of fuzzers is to expose edge cases; by using them at all, we accept that some of our tests will fail on some runs and not others - in fact, we're often hoping for that to happen!
Assuming we fixed the error message in #160 to be nice, how bad would it actually be if sometimes fuzzers turned out to be invalid midway through a run, leading to a failed test? It doesn't seem likely to lead to a whole lot of frustration in practice.
Note: If we did this, and kept
andThen
, I'd want to change bothoneOf
andfrequency
to accept the extra argument, so if you're using them in anandThen
it's super clear that you need to provide at least one element in the list. We don't need to bikeshed about that now though!
Thoughts?