|
@ -1,6 +1,5 @@ |
|
|
-module(proper_tests). |
|
|
-module(proper_tests). |
|
|
-include_lib("proper/include/proper.hrl"). |
|
|
-include_lib("proper/include/proper.hrl"). |
|
|
%%-include_lib("proper_stdlib/include/proper_ct.hrl"). |
|
|
|
|
|
-include_lib("eunit/include/eunit.hrl"). |
|
|
-include_lib("eunit/include/eunit.hrl"). |
|
|
-export([proper_test_/0]). |
|
|
-export([proper_test_/0]). |
|
|
|
|
|
|
|
@ -9,25 +8,27 @@ all() -> proper_ct:testcases(?MODULE). |
|
|
init_per_testcase(tc_prop_foo, Config) -> |
|
|
init_per_testcase(tc_prop_foo, Config) -> |
|
|
[{proper, [{numtests, 1000}]} | Config]. |
|
|
[{proper, [{numtests, 1000}]} | Config]. |
|
|
|
|
|
|
|
|
-type json_any() :: json_list() |
|
|
|
|
|
| json_dict() |
|
|
|
|
|
| json_number() |
|
|
|
|
|
| json_string() |
|
|
|
|
|
| json_null(). |
|
|
|
|
|
-type json_list() :: list(json_any()). |
|
|
|
|
|
-type json_dict() :: {[{json_key(), json_any()}]}. |
|
|
|
|
|
-type json_key() :: binary(). |
|
|
|
|
|
-type json_number() :: integer() | float(). |
|
|
|
|
|
-type json_string() :: binary(). |
|
|
|
|
|
-type json_null() :: null. |
|
|
|
|
|
|
|
|
%% Helper funs |
|
|
|
|
|
|
|
|
|
|
|
escaped_char() -> |
|
|
|
|
|
?LET(C, char(), |
|
|
|
|
|
case C == $" of |
|
|
|
|
|
true -> "\\\""; |
|
|
|
|
|
false -> C |
|
|
|
|
|
end). |
|
|
|
|
|
|
|
|
|
|
|
escaped_utf8_bin() -> |
|
|
|
|
|
?SUCHTHAT(Bin, |
|
|
|
|
|
?LET(S, ?SUCHTHAT(L, list(escaped_char()), L /= []), |
|
|
|
|
|
unicode:characters_to_binary(S, unicode, utf8)), |
|
|
|
|
|
is_binary(Bin)). |
|
|
|
|
|
|
|
|
%% Atomic types |
|
|
%% Atomic types |
|
|
json_null() -> |
|
|
json_null() -> |
|
|
null. |
|
|
null. |
|
|
|
|
|
|
|
|
json_string() -> |
|
|
json_string() -> |
|
|
?LET(Str, proper_stdgen:utf8_bin(), |
|
|
|
|
|
binary:replace(Str, <<"\"">>, <<"\\\"">>, [global])). %good enough |
|
|
|
|
|
|
|
|
escaped_utf8_bin(). |
|
|
|
|
|
|
|
|
json_number() -> |
|
|
json_number() -> |
|
|
oneof([integer(), float()]). |
|
|
oneof([integer(), float()]). |
|
@ -44,46 +45,60 @@ json_atomic() -> |
|
|
%% Compound types |
|
|
%% Compound types |
|
|
json_object() -> |
|
|
json_object() -> |
|
|
?SIZED(S, json_object(S)). |
|
|
?SIZED(S, json_object(S)). |
|
|
json_object(0) -> |
|
|
|
|
|
|
|
|
json_object(S) when S =< 0 -> |
|
|
json_atomic(); |
|
|
json_atomic(); |
|
|
json_object(S) -> |
|
|
json_object(S) -> |
|
|
frequency([{1, json_object(0)}, |
|
|
frequency([{1, json_object(0)}, |
|
|
{3, json_list()}, |
|
|
|
|
|
{9, ?LAZY( |
|
|
|
|
|
|
|
|
{3, ?LAZY(json_list(S))}, |
|
|
|
|
|
{3, ?LAZY( |
|
|
?LETSHRINK( |
|
|
?LETSHRINK( |
|
|
[Node], |
|
|
|
|
|
[{list({json_string(), json_object(S - 1)})}], |
|
|
|
|
|
Node |
|
|
|
|
|
))}]). |
|
|
|
|
|
|
|
|
[ObjectSize], |
|
|
|
|
|
[integer(1, S)], |
|
|
|
|
|
?LETSHRINK( |
|
|
|
|
|
[Object], |
|
|
|
|
|
[{vector(ObjectSize, |
|
|
|
|
|
{json_string(), |
|
|
|
|
|
json_object(S - ObjectSize)})}], |
|
|
|
|
|
Object |
|
|
|
|
|
)))}]). |
|
|
|
|
|
|
|
|
|
|
|
json_list(S) -> |
|
|
|
|
|
?LETSHRINK([ListSize], |
|
|
|
|
|
[integer(1, S)], |
|
|
|
|
|
vector(ListSize, json_object(S - ListSize))). |
|
|
|
|
|
|
|
|
json_list() -> |
|
|
json_list() -> |
|
|
list(json_object()). |
|
|
list(json_object()). |
|
|
|
|
|
|
|
|
tree(G) -> |
|
|
|
|
|
?SIZED(S, tree(S, G)). |
|
|
|
|
|
tree(0, _) -> |
|
|
|
|
|
leaf; |
|
|
|
|
|
tree(S, G) -> |
|
|
|
|
|
frequency([ |
|
|
|
|
|
{1, tree(0, G)}, |
|
|
|
|
|
{9, ?LAZY( |
|
|
|
|
|
?LETSHRINK( |
|
|
|
|
|
[L, R], |
|
|
|
|
|
[tree(S div 2, G), tree(S div 2, G)], |
|
|
|
|
|
{node, G, L, R} |
|
|
|
|
|
))} |
|
|
|
|
|
]). |
|
|
|
|
|
|
|
|
|
|
|
prop_foo() -> |
|
|
|
|
|
%% ?FORALL(Data, json_any(), |
|
|
|
|
|
%% Data == jiffy:decode(jiffy:encode(Data))). |
|
|
|
|
|
|
|
|
prop_encode_decode() -> |
|
|
?FORALL(Data, json_object(), |
|
|
?FORALL(Data, json_object(), |
|
|
begin |
|
|
begin |
|
|
%io:format(user, "Data: ~p~n", [Data]), |
|
|
|
|
|
|
|
|
%% io:format(user, "Data: ~p~n", [Data]), |
|
|
Data == jiffy:decode(jiffy:encode(Data)) |
|
|
Data == jiffy:decode(jiffy:encode(Data)) |
|
|
end). |
|
|
end). |
|
|
|
|
|
|
|
|
|
|
|
prop_encode_not_crash() -> |
|
|
|
|
|
?FORALL(Data, any(), |
|
|
|
|
|
begin |
|
|
|
|
|
catch jiffy:encode(Data), |
|
|
|
|
|
true |
|
|
|
|
|
end). |
|
|
|
|
|
|
|
|
|
|
|
prop_decode_not_crash_bin() -> |
|
|
|
|
|
?FORALL(Data, binary(), |
|
|
|
|
|
begin |
|
|
|
|
|
catch jiffy:decode(Data), |
|
|
|
|
|
true |
|
|
|
|
|
end). |
|
|
|
|
|
|
|
|
|
|
|
prop_decode_not_crash_any() -> |
|
|
|
|
|
?FORALL(Data, any(), |
|
|
|
|
|
begin |
|
|
|
|
|
catch jiffy:decode(Data), |
|
|
|
|
|
true |
|
|
|
|
|
end). |
|
|
|
|
|
|
|
|
proper_test_() -> |
|
|
proper_test_() -> |
|
|
{timeout, 600, |
|
|
|
|
|
?_assertEqual([], proper:module(proper_tests, [{to_file, user}, |
|
|
|
|
|
{numtests, 10}]))}. |
|
|
|
|
|
|
|
|
{timeout, 3600, |
|
|
|
|
|
?_assertEqual([], proper:module(proper_tests, [{to_file, user}, {max_size, 60}, |
|
|
|
|
|
{numtests, 1000}]))}. |