--- a +++ b/tests/generative/generic_strategies.py @@ -0,0 +1,40 @@ +from hypothesis import strategies as st + + +# This is a variable that will normally be set to True, but which shrinking is +# allowed to make False. +# +# Examples of where this is useful: +# +# * Turning off expensive test operations that you want to check but don't care +# about running if they turn out not to be relevant to the error you're +# seeing. +# * Giving the shrinker a place to terminate generation in places where you've +# decided to do it yourself because e.g. the data was getting too large. +usually = st.integers(0, 255).map(lambda n: n > 0) + + +@st.composite +def usually_all_of(draw, options, min_size=1): + """Generates a list of distinct elements drawn from `options`, of size at least + `min_size`. In the normal course of things, this will usually be all of `options`, + but the shrinker is allowed to remove elements from it, which can speed up + test execution during shrinking significantly.""" + flags = draw(st.lists(usually, min_size=len(options), max_size=len(options))) + + # In order to make sure enough of these are set, we set some + # of the flags to true. We do this unconditionally on whether enough + # flags are already set so that when shrinking we don't start to generate + # more data when some of the flags are shrunk to false. + extra_flags = draw( + st.lists( + st.integers(0, len(options) - 1), + min_size=min_size, + max_size=min_size, + unique=True, + ) + ) + n_set = flags.count(True) + for i in extra_flags[: max(min_size - n_set, 0)]: + flags[i] = True + return [option for option, include in zip(options, flags) if include]