Apply predicate when shrinking ?SUCHTHAT
diff --git a/src/triq_dom.erl b/src/triq_dom.erl
index 4c74e25..109f215 100644
--- a/src/triq_dom.erl
+++ b/src/triq_dom.erl
@@ -33,7 +33,8 @@
-define(SIZED(Size,Gen),
sized(fun(Size) -> Gen end)).
-%% How many times we try pick a value in order to satisfy a ?SUCHTHAT property.
+%% How many times we try to pick or shrink a value in order to satisfy a
+%% ?SUCHTHAT property.
-define(SUCHTHAT_LOOPS,100).
%% how many times we try to shrink a value before we bail out
@@ -1026,18 +1027,35 @@
-spec suchthat(domain(T),fun((T) -> boolean())) -> domain(T).
suchthat(Dom,Predicate) ->
#?DOM{kind=#suchthat{dom=Dom,pred=Predicate},
- pick=fun(#?DOM{kind=#suchthat{dom=Dom1,pred=Fun1}},SampleSize) ->
- suchthat_loop(?SUCHTHAT_LOOPS,Dom1,Fun1,SampleSize)
- end
- }.
+ pick=fun suchthat_pick/2,
+ shrink=fun suchthat_shrink/2}.
-suchthat_loop(0,_,_,_) ->
+suchthat_pick(#?DOM{kind=#suchthat{dom=Dom,pred=Pred}},SampleSize) ->
+ suchthat_pick_loop(?SUCHTHAT_LOOPS,Dom,Pred,SampleSize).
+
+suchthat_shrink(#?DOM{kind=#suchthat{dom=Dom,pred=Pred}},Val) ->
+ suchthat_shrink_loop(?SUCHTHAT_LOOPS, Dom, Pred, Val).
+
+suchthat_pick_loop(0,_,_,_) ->
erlang:exit(suchthat_failed);
-suchthat_loop(N,Dom,Fun,SampleSize) ->
+suchthat_pick_loop(N,Dom,Pred,SampleSize) ->
{ValDom,Val} = pick(Dom,SampleSize),
- case Fun(Val) of
- true -> {ValDom,Val};
- _ -> suchthat_loop(N-1, Dom, Fun, SampleSize)
+ case Pred(Val) of
+ true -> {suchthat(ValDom, Pred), Val};
+ _ -> suchthat_pick_loop(N-1, Dom, Pred, SampleSize)
+ end.
+
+suchthat_shrink_loop(0, Dom, Pred, Val) ->
+ {suchthat(Dom, Pred), Val};
+suchthat_shrink_loop(N, Dom, Pred, Val) ->
+ case shrink(Dom, Val) of
+ {Dom, Val} ->
+ {suchthat(Dom, Pred), Val};
+ {ShrinkedDom, ShrinkedVal} ->
+ case Pred(ShrinkedVal) of
+ true -> {suchthat(ShrinkedDom, Pred), ShrinkedVal};
+ _ -> suchthat_shrink_loop(N - 1, Dom, Pred, Val)
+ end
end.
diff --git a/test/triq_tests.erl b/test/triq_tests.erl
index f63d41f..bad079e 100644
--- a/test/triq_tests.erl
+++ b/test/triq_tests.erl
@@ -171,8 +171,10 @@
is_integer(X) == is_integer(Y)
end
)),
+ %% One variable must be equal to 0 and absolute value of the other must not
+ %% be greater than 1.
%% Note: 0 == 0.0
- ?assert((X == 0) and (Y == 0)).
+ ?assert((X * Y == 0) and (X + Y /= 0) and (abs(X) + abs(Y) =< 1)).
%%
%% This test makes sure that X shrinks only to 3.
@@ -216,6 +218,18 @@
false)),
one = X.
+suchthat_shrinking_test() ->
+ ?assertEqual(
+ [2],
+ triq:counterexample(
+ ?FORALL(
+ _,
+ ?SUCHTHAT(
+ X,
+ non_neg_integer(),
+ X > 1),
+ false))).
+
%%
%% Test passing counterexamples to properties
%%