Skip to content

Commit

Permalink
introduce seed user option
Browse files Browse the repository at this point in the history
  • Loading branch information
fenollp committed Apr 2, 2020
1 parent 0365dd2 commit d8c8f95
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/proper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@
%%% <dd>This is equivalent to the {@link numtests/1} property wrapper. Any
%%% {@link numtests/1} wrappers in the actual property will overwrite this
%%% setting.</dd>
%%% <dt>`{seed, {<Non_negative_integer>,<Non_negative_integer>,<Non_negative_integer>}}'</dt>
%%% <dd>Pass a seed to the RNG so that random results can be reproduced.</dd>
%%% <dt>`{start_size, <Size>}'</dt>
%%% <dd>Specifies the initial value of the `size' parameter (default is 1), see
%%% the documentation of the {@link proper_types} module for details.</dd>
Expand Down Expand Up @@ -489,6 +491,7 @@
| {'search_steps',pos_integer()}
| {'search_strategy',proper_target:strategy()}
| pos_integer()
| {'seed',proper_gen:seed()}
| {'start_size',proper_gen:size()}
| {'max_size',proper_gen:size()}
| {'max_shrinks',non_neg_integer()}
Expand Down Expand Up @@ -924,6 +927,7 @@ parse_opt(UserOpt, Opts) ->
{search_steps, N} -> Opts#opts{search_steps = N};
{search_strategy, S} -> Opts#opts{search_strategy = S};
N when is_integer(N) -> Opts#opts{numtests = N};
{seed,Seed} -> Opts#opts{seed = Seed};
{start_size,Size} -> Opts#opts{start_size = Size};
{max_size,Size} -> Opts#opts{max_size = Size};
{max_shrinks,N} -> Opts#opts{max_shrinks = N};
Expand Down
48 changes: 48 additions & 0 deletions test/proper_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,54 @@ options_test_() ->
?FORALL(_,?SIZED(Size,integer(Size,Size)),false),
[{start_size,12}])].

seeded_test_() ->
Seed = os:timestamp(),
BaseOpts = [noshrink, {start_size,65536}, quiet],
Seeded = fun (Prop) ->
R = proper:counterexample(Prop, [{seed,Seed}|BaseOpts]),
proper:clean_garbage(),
R
end,
NoSeed = fun (Prop) ->
R = proper:counterexample(Prop, BaseOpts),
proper:clean_garbage(),
R
end,
ReSeeded = fun (Prop) ->
OtherSeed = os:timestamp(),
R = proper:counterexample(Prop, [{seed,OtherSeed}|BaseOpts]),
proper:clean_garbage(),
R
end,
[[?_assert(state_is_clean()),
?_assertMatch({Name,{_,Equals}} when Equals > 6, {Name,equaltimes(Seeded,Prop,Check,10)}),
?_assert(state_is_clean()),
?_assertMatch({Name,{_,Equals}} when Equals < 4, {Name,equaltimes(NoSeed,Prop,Check,10)}),
?_assert(state_is_clean()),
?_assertMatch({Name,{_,Equals}} when Equals < 4, {Name,equaltimes(ReSeeded,Prop,Check,10)}),
?_assert(state_is_clean())]
%% For each of these properties...
|| {Name,Prop} <- [{forall,?FORALL(_, integer(), false)},
{trapexit,?FORALL(_, integer(), ?TRAPEXIT(false))},
{targeted,?FORALL_TARGETED(I, integer(), begin ?MAXIMIZE(I),false end)}],
%% Ensure that, using a large enough size and at least 60% of the time:
%% * provided a seed, another run gives the same counterexample;
%% * when not provided a seed: run gives out differing results to the seeded one;
%% * and similarly when given a different seed.
Check <- [Seeded(Prop)]].

equaltimes(Runner, Prop, Expected, Max) ->
equaltimes(Runner, Prop, Expected, Max, Max, []).
equaltimes(_, _, _, Max, 0, Unexpecteds) ->
{Unexpecteds, Max - length(Unexpecteds)};
equaltimes(Runner, Prop, Expected, Max, N, Acc) ->
case Runner(Prop) of
Expected ->
equaltimes(Runner, Prop, Expected, Max, N-1, Acc);
Got ->
equaltimes(Runner, Prop, Expected, Max, N-1, [Got|Acc])
end.

setup_prop() ->
?SETUP(fun () ->
put(setup_token, true),
Expand Down

0 comments on commit d8c8f95

Please sign in to comment.