Skip to content

Commit 0752cf5

Browse files
Extend PropEr with atomlimit-safe generator variants
The atom generator of PropEr generates atoms from random strings and its use, explicitly or implicitly, is prone to exhausting the atom limit. This commit adds a variant to the atom generator which picks from the existing atoms and does not generate any new ones. It also provides variants of the any, list, and tuple generators which implicitly use the atom generator. Co-authored-by: Jan Uhlig <[email protected]>
1 parent b233706 commit 0752cf5

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

lib/common_test/include/ct_property_test.hrl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
-ifdef(PROPER).
3030
-define(MOD_eqc, proper).
3131
-include_lib("proper/include/proper.hrl").
32+
-include_lib("common_test/include/ct_property_test_proper_ext.hrl").
3233
-else.
3334
-ifdef(TRIQ).
3435
-define(MOD_eqc, triq).
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
%%
2+
%% %CopyrightBegin%
3+
%%
4+
%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
5+
%%
6+
%% Licensed under the Apache License, Version 2.0 (the "License");
7+
%% you may not use this file except in compliance with the License.
8+
%% You may obtain a copy of the License at
9+
%%
10+
%% http://www.apache.org/licenses/LICENSE-2.0
11+
%%
12+
%% Unless required by applicable law or agreed to in writing, software
13+
%% distributed under the License is distributed on an "AS IS" BASIS,
14+
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
%% See the License for the specific language governing permissions and
16+
%% limitations under the License.
17+
%%
18+
%% %CopyrightEnd%
19+
%%
20+
%%
21+
22+
-import(ct_property_test_proper_ext, [existing_atom/0,
23+
safe_atom/0,
24+
safe_any/0,
25+
safe_list/0,
26+
safe_tuple/0]).

lib/common_test/src/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ MODULES= \
7979
cth_conn_log \
8080
ct_groups \
8181
ct_property_test \
82+
ct_property_test_proper_ext \
8283
ct_release_test \
8384
ct_default_gl \
8485
erl2html2 \
@@ -104,7 +105,8 @@ HRL_FILES = \
104105
EXTERNAL_HRL_FILES = \
105106
../include/ct.hrl \
106107
../include/ct_event.hrl \
107-
../include/ct_property_test.hrl
108+
../include/ct_property_test.hrl \
109+
../include/ct_property_test_proper_ext.hrl
108110

109111
EXTERNAL_INC_PATH = ../include
110112

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
%%
2+
%% %CopyrightBegin%
3+
%%
4+
%% Copyright Ericsson AB 2003-2023. All Rights Reserved.
5+
%%
6+
%% Licensed under the Apache License, Version 2.0 (the "License");
7+
%% you may not use this file except in compliance with the License.
8+
%% You may obtain a copy of the License at
9+
%%
10+
%% http://www.apache.org/licenses/LICENSE-2.0
11+
%%
12+
%% Unless required by applicable law or agreed to in writing, software
13+
%% distributed under the License is distributed on an "AS IS" BASIS,
14+
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
%% See the License for the specific language governing permissions and
16+
%% limitations under the License.
17+
%%
18+
%% %CopyrightEnd%
19+
%%
20+
21+
-module(ct_property_test_proper_ext).
22+
23+
-export([existing_atom/0]).
24+
-export([safe_any/0]).
25+
-export([safe_atom/0]).
26+
-export([safe_list/0]).
27+
-export([safe_tuple/0]).
28+
29+
-spec safe_atom() -> proper_types:type().
30+
safe_atom() ->
31+
proper_types:oneof([proper_types:oneof(['', true, false, ok,
32+
error, undefined,
33+
infinity, 'ätöm',
34+
'原子', '_', '"',
35+
'\'', '\\', '+', '-',
36+
'*', '/', '(', ')',
37+
'[', ']', '{', '}',
38+
'#' | erlang:nodes(known)]),
39+
proper_types:noshrink(existing_atom())]).
40+
41+
42+
-spec existing_atom() -> proper_types:type().
43+
existing_atom() ->
44+
proper_types:bind(proper_types:non_neg_integer(),
45+
fun(N) ->
46+
get_existing_atom(N)
47+
end,
48+
false).
49+
50+
-define(ATOM_TERM_BIN(Index), <<131, 75, Index:24>>).
51+
get_existing_atom(Index) ->
52+
get_existing_atom(Index, erlang:system_info(atom_count)).
53+
54+
get_existing_atom(Index, Max) ->
55+
Index1 = Index rem Max,
56+
case binary_to_term(?ATOM_TERM_BIN(Index1)) of
57+
'' ->
58+
'';
59+
Atom ->
60+
case hd(atom_to_list(Atom)) of
61+
$$ -> get_existing_atom(Index1 + 1, Max);
62+
_ -> Atom
63+
end
64+
end.
65+
66+
67+
-spec safe_any() -> proper_types:type().
68+
safe_any() ->
69+
proper_types:sized(fun(Size) -> safe_any(Size) end).
70+
71+
safe_any(0) ->
72+
proper_types:oneof([safe_atom(),
73+
proper_types:integer(),
74+
proper_types:float()]);
75+
safe_any(Size) ->
76+
{_, Choice} = proper_arith:freq_choose([{3, simple},
77+
{1, binary},
78+
{4, list},
79+
{4, tuple}]),
80+
NumElements = proper_arith:rand_int(0, Size),
81+
case {Choice, NumElements} of
82+
{simple, _NumEls} ->
83+
safe_any(0);
84+
{binary, _NumEls} ->
85+
proper_types:resize(Size, proper_types:bitstring());
86+
{list, 0} ->
87+
[];
88+
{list, 1} ->
89+
[proper_types:lazy(fun() -> safe_any(Size-1) end)];
90+
{list, NumEls} ->
91+
ElSizes = proper_arith:distribute(Size-1, NumEls),
92+
proper_types:fixed_list([proper_types:lazy(fun() ->
93+
safe_any(S)
94+
end)
95+
|| S <- ElSizes]);
96+
{tuple, 0} ->
97+
{};
98+
{tuple, 1} ->
99+
{proper_types:lazy(fun() -> safe_any(Size-1) end)};
100+
{tuple, NumEls} ->
101+
ElSizes = proper_arith:distribute(Size-1, NumEls),
102+
proper_types:tuple([proper_types:lazy(fun() ->
103+
safe_any(S) end)
104+
|| S <- ElSizes])
105+
end.
106+
107+
108+
-spec safe_list() -> proper_types:type().
109+
safe_list() ->
110+
proper_types:list(safe_any()).
111+
112+
113+
-spec safe_tuple() -> proper_types:type().
114+
safe_tuple() ->
115+
proper_types:tuple(safe_any()).
116+

0 commit comments

Comments
 (0)