proper-testing / proper

PropEr: a QuickCheck-inspired property-based testing tool for Erlang
http://proper-testing.github.io
GNU General Public License v3.0
880 stars 168 forks source link

Need fuzzy preconditions #134

Open ijt opened 7 years ago

ijt commented 7 years ago

For example if a key isn't defined in my key-value store, I may not want to rule out trying to get it since that's still a valid thing to do, but I also want that to be a smaller set of the cases tried.

robertoaloi commented 5 years ago

Hi! I am not sure this feature should be built-in in the framework. It sounds more like a custom generator could help achieving the same functionality. Something like:


%% Define a ratio of 10:1 between existing and non-existing keys
-define(DEFAULT_EXISTING_FREQUENCY, 10).
-define(DEFAULT_NON_EXISTING_FREQUENCY, 1).

%% Return one of the existing keys from the state. Crash if no keys are available.
existing_key(S) ->
  elements(maps:get(keys, S)).

%% Return a key which is not in the state
non_existing_key(S) ->
  ?SUCHTHAT(Key, term(), not lists:member(Key, maps:get(keys,  S))).

%% Return either an existing or non-existing key, according to default frequencies
key(S) ->
  key(S, #{ existing => ?DEFAULT_EXISTING_FREQUENCY, non_existing => ?DEFAULT_NON_EXISTING_FREQUENCY }).

%% Return either an existing or non-existing key, according to custom frequencies.
%% It falls back to non-existing in case the state is empty
key(S, Frequencies) ->
  NEFrequency = maps:get(non_existing, Frequencies, ?DEFAULT_NON_EXISTING_FREQUENCY),
  EFrequency  = maps:get(existing,     Frequencies, ?DEFAULT_EXISTING_FREQUENCY),
  case maps:get(keys, S) of
    [] -> non_existing_key(S);
    _  -> frequency([{EFrequency,  existing_key(S)}, {NEFrequency, non_existing_key(S)}])
  end.

This can then be used as in:

key(S)
key(S, #{existing => ?HIGH_FREQUENCY})
key(S, #{non_existing => ?HIGH_FREQUENCY})