Merge remote-tracking branch 'canonical/next'
[sinan.git] / test / sint_config_proper.erl
blob5180e0e3046b33885ea17dba4e91c2c80d48b899
1 %%%-------------------------------------------------------------------
2 %%% @author Eric Merritt <ericbmerritt@gmail.com>
3 %%% @copyright (C) 2011, Eric Merritt
4 %%% @doc
5 %%%
6 %%% @end
7 %%%-------------------------------------------------------------------
8 -module(sint_config_proper).
10 -export([]).
12 -include_lib("proper/include/proper.hrl").
14 %%==============================================================================
15 %% Properties
16 %%==============================================================================
17 prop_size_increases_with_new_entry() ->
18 ?FORALL({Config, K, V}, {config(), full_key(), value()},
19 begin
20 Size = sin_config:size(Config),
21 case sin_config:has_key(K, Config) of
22 true ->
23 Size == sin_config:size(sin_config:'__add__'(K, V, Config));
24 false ->
25 (Size + 1) == sin_config:size(
26 sin_config:'__add__'(K, V, Config))
27 end
28 end).
30 prop_size_decrease_when_removing() ->
31 ?FORALL({Config, K}, {config(), full_key()},
32 begin
33 Size = sin_config:size(Config),
34 case sin_config:has_key(K, Config) of
35 false ->
36 Size == sin_config:size(sin_config:remove(K, Config));
37 true ->
38 (Size - 1) == sin_config:size(
39 sin_config:remove(K, Config))
40 end
41 end).
44 prop_get_after_add_returns_correct_value() ->
45 ?FORALL({Config, K, V}, {config(), full_key(), value()},
46 begin
47 try sin_config:get(K, sin_config:'__add__'(K, V, Config)) of
48 V ->
49 true;
50 _ ->
51 false
52 catch
53 _:_ ->
54 false
55 end
56 end).
58 prop_key_is_present_after_add() ->
59 ?FORALL({Config, K, V}, {config(), full_key(), value()},
60 begin
61 sin_config:has_key(K, sin_config:'__add__'(K, V, Config))
62 end).
64 prop_inexact_match_positive() ->
65 ?FORALL({Config, Key = {K, S1, S2, S3, S4, S5}, V},
66 {config(),
67 {key(), specifier(), specifier(),
68 specifier(), specifier(), specifier()},
69 value()},
70 begin
71 MatchKey = {K, resolve_s(S1),
72 resolve_s(S2), resolve_s(S3),
73 resolve_s(S4), resolve_s(S5)},
74 Config2 = sin_config:'__add__'(Key, V, Config),
75 V == sin_config:'__match__'(MatchKey, Config2)
76 end).
78 prop_inexact_match_negative() ->
79 ?FORALL({Config, Key = {K, _, _, _, _, _}, V},
80 {config(),
81 {key(), direct(), specifier(), specifier(),
82 specifier(), specifier()},
83 value()},
84 begin
85 MatchKey = {K, direct(),
86 direct(), direct(),
87 direct(), direct()},
88 Config2 = sin_config:'__add__'(Key, V, Config),
89 try
90 sin_config:'__match__'(MatchKey, Config2),
91 false
92 catch
93 throw:not_found ->
94 true
95 end
96 end).
98 prop_new_from_terms() ->
99 ?FORALL({Entries, InitialOpts,
100 Key = {K, S1, S2, S3, S4, S5}, Value},
101 {partial_entries(), spec_opts(), full_key(),
102 value()},
103 begin
104 Config = sin_config:new_from_terms(Entries, InitialOpts),
105 Config1 = sin_config:'__add__'(Key, Value, Config),
107 MatchKey = {K, resolve_s(S1),
108 resolve_s(S2), resolve_s(S3),
109 resolve_s(S4), resolve_s(S5)},
110 Value == sin_config:'__match__'(MatchKey, Config1)
111 end).
113 prop_test_sort() ->
114 ?FORALL({Key1 = {K, S1, S2, _S3, S4, S5}, Value1, Value2, Value3},
115 {{key(), direct(), direct(), wildcard(), direct(), wildcard()},
116 value(), value(), value()},
117 begin
118 Key2 = {K, S1, S2, direct(), S4, S5},
119 Key3 = {K, S1, S2, direct(), S4, direct()},
120 Config = sin_config:new(),
121 Config1 = sin_config:'__add__'(Key3, Value3, Config),
122 Config2 = sin_config:'__add__'(Key2, Value2, Config1),
123 Config3 = sin_config:'__add__'(Key1, Value1, Config2),
125 [{TKey3, _}, {TKey2, _}, {TKey1, _}] =
126 sin_config:to_list(Config3),
128 (TKey1 == Key1 andalso TKey2 == Key2
129 andalso TKey3 == Key3)
131 end).
133 %%==============================================================================
134 %% Support functions
135 %%=============================================================================
137 resolve_s('*') ->
138 direct();
139 resolve_s(V) ->
143 %%==============================================================================
144 %% Generators
145 %%=============================================================================
147 wildcard() ->
148 exactly('*').
150 direct() ->
151 atom().
153 specifier() ->
154 union([wildcard(), direct()]).
156 key() ->
157 union([atom(), binary(), string()]).
159 value() ->
160 term().
162 full_key() ->
163 tuple([key(), specifier(),
164 specifier(), specifier(),
165 specifier(), specifier()]).
167 spec_name() ->
168 union([task, release, app, dir, module]).
170 spec_opts() ->
171 ?SIZED(N, spec_opts(N)).
173 spec_opts(0) ->
174 [{spec_name(), atom()}];
175 spec_opts(N) ->
176 ?LET(SO, spec_opts(N - 1),
177 [{spec_name(), atom()} | SO]).
179 partial_entry() ->
180 union([{key(), value()},
181 {{key(), spec_opts()}, value()},
182 {{key(), specifier()}, value()},
183 {{key(), specifier(), specifier()}, value()},
184 {{key(), specifier(), specifier(), specifier()}, value()},
185 {{key(), specifier(), specifier(), specifier(),
186 specifier()}, value()},
187 {{key(), specifier(), specifier(), specifier(),
188 specifier(), specifier()}, value()}]).
191 partial_entries() ->
192 ?SIZED(N, partial_entries(N)).
194 partial_entries(0) ->
195 [partial_entry()];
196 partial_entries(N) ->
197 ?LET(PE, partial_entries(N - 1),
198 [partial_entry() | PE]).
200 config() ->
201 ?SIZED(N, config(N)).
203 config(0) ->
204 {'$call', sin_config, new, []};
205 config(N) ->
206 ?LAZY(frequency([
207 {1, config(0)},
208 {3, {'$call', sin_config, remove,
209 [full_key(), config(N - 1)]}},
210 {6, {'$call', sin_config, '__add__',
211 [full_key(), value(), config(N - 1)]}}
212 ])).