1%%% -*- coding: utf-8 -*-
2%%% -*- erlang-indent-level: 2 -*-
3%%% -------------------------------------------------------------------
4%%% Copyright 2020-     Manolis Papadakis <manopapad@gmail.com>,
5%%%                     Eirini Arvaniti <eirinibob@gmail.com>
6%%%                 and Kostis Sagonas <kostis@cs.ntua.gr>
7%%%
8%%% This file is part of PropEr.
9%%%
10%%% PropEr is free software: you can redistribute it and/or modify
11%%% it under the terms of the GNU General Public License as published by
12%%% the Free Software Foundation, either version 3 of the License, or
13%%% (at your option) any later version.
14%%%
15%%% PropEr is distributed in the hope that it will be useful,
16%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18%%% GNU General Public License for more details.
19%%%
20%%% You should have received a copy of the GNU General Public License
21%%% along with PropEr.  If not, see <http://www.gnu.org/licenses/>.
22
23%%% @copyright 2020 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas
24%%% @version {@version}
25%%% @author Spiros Dontas
26
27%% -----------------------------------------------------------------------------
28%% Tests inspired by https://github.com/proper-testing/proper/issues/221
29%% -----------------------------------------------------------------------------
30
31-module(targeted_shrinking_test).
32-include_lib("proper/include/proper.hrl").
33-include_lib("eunit/include/eunit.hrl").
34
35%% -----------------------------------------------------------------------------
36%% Generators
37%% -----------------------------------------------------------------------------
38
39let_int() ->
40  ?LET(I, integer(), I).
41
42nf_let_int() ->
43  fun (Prev, _T) ->
44      ?LET(I, integer(Prev, inf), I)
45  end.
46
47nf_int_shrink() ->
48  fun (Prev, _T) ->
49      ?SHRINK(integer(Prev, inf), [integer()])
50  end.
51
52int_user_nf() ->
53  ?USERNF(integer(), nf_let_int()).
54
55let_int_user_nf() ->
56  ?USERNF(let_int(), nf_let_int()).
57
58int_user_nf_shrink_inner() ->
59  ?USERNF(let_int(), nf_int_shrink()).
60
61int_user_nf_shrink_outer() ->
62  ?USERNF(?SHRINK(let_int(), [integer()]),
63          fun(Prev, _T) -> integer(Prev, inf) end).
64
65normal_list() ->
66  list(integer()).
67
68let_list() ->
69  ?LET(L, list(integer()), L).
70
71nf_list() ->
72  fun (Prev, _T) ->
73      {Max, NewLen} = case Prev of
74                        [] -> {0, 1};
75                        _ -> {max(0, lists:max(Prev)), length(Prev)}
76                      end,
77      ?SHRINK(vector(NewLen * 2, integer(Max, inf)),
78              [list(integer())])
79  end.
80
81normal_list_user_nf() ->
82  ?USERNF(normal_list(), nf_list()).
83
84let_list_user_nf() ->
85  ?USERNF(let_list(), nf_list()).
86
87%% -----------------------------------------------------------------------------
88%% Properties
89%% -----------------------------------------------------------------------------
90
91property_int(I) ->
92  ?MAXIMIZE(I),
93  I < 500.
94
95prop_int() ->
96  ?FORALL_TARGETED(I, int_user_nf(), property_int(I)).
97
98prop_let_int() ->
99  ?FORALL_TARGETED(I, let_int_user_nf(), property_int(I)).
100
101prop_int_shrink_outer() ->
102  ?FORALL_TARGETED(I, int_user_nf_shrink_outer(), property_int(I)).
103
104prop_int_shrink_inner() ->
105  ?FORALL_TARGETED(I, int_user_nf_shrink_inner(), property_int(I)).
106
107property_list(L) ->
108  ?MAXIMIZE(lists:sum(L)),
109  lists:sum(L) < 1000.
110
111prop_normal_list() ->
112  ?FORALL_TARGETED(L, normal_list_user_nf(), property_list(L)).
113
114prop_let_list() ->
115  ?FORALL_TARGETED(L, let_list_user_nf(), property_list(L)).
116
117%% -----------------------------------------------------------------------------
118%% Tests
119%% -----------------------------------------------------------------------------
120
121normal_list_test() ->
122  false = proper:quickcheck(prop_normal_list()),
123  [L] = proper:counterexample(),
124  ?_assert(lists:sum(L) =:= 1000).
125
126let_list_test() ->
127  false = proper:quickcheck(prop_let_list()),
128  [L] = proper:counterexample(),
129  ?_assert(lists:sum(L) =:= 1000).
130