% This file is part of Jiffy released under the MIT license.
|
|
% See the LICENSE file for more information.
|
|
|
|
-module(jiffy_11_proper_tests).
|
|
|
|
-ifdef(JIFFY_DEV).
|
|
|
|
-include_lib("proper/include/proper.hrl").
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-include("jiffy_util.hrl").
|
|
|
|
opts() ->
|
|
[
|
|
{max_size, 15},
|
|
{numtests, 1000}
|
|
].
|
|
|
|
run(Name) ->
|
|
{msg("~s", [Name]), [
|
|
{timeout, 300, ?_assert(proper:quickcheck(?MODULE:Name(), opts()))}
|
|
]}.
|
|
|
|
proper_encode_decode_test_() ->
|
|
[
|
|
run(prop_enc_dec),
|
|
run(prop_enc_dec_pretty),
|
|
run(prop_enc_no_crash),
|
|
run(prop_dec_no_crash_bin),
|
|
run(prop_dec_no_crash_any)
|
|
].
|
|
|
|
prop_enc_dec() ->
|
|
?FORALL(Data, json(),
|
|
begin
|
|
%io:format(standard_error, "Data: ~p~n", [Data]),
|
|
Data == jiffy:decode(jiffy:encode(Data))
|
|
end
|
|
).
|
|
|
|
-ifndef(JIFFY_NO_MAPS).
|
|
to_map_ejson({Props}) ->
|
|
NewProps = [{K, to_map_ejson(V)} || {K, V} <- Props],
|
|
maps:from_list(NewProps);
|
|
to_map_ejson(Vals) when is_list(Vals) ->
|
|
[to_map_ejson(V) || V <- Vals];
|
|
to_map_ejson(Val) ->
|
|
Val.
|
|
|
|
prop_map_enc_dec() ->
|
|
?FORALL(Data, json(),
|
|
begin
|
|
MapData = to_map_ejson(Data),
|
|
MapData == jiffy:decode(jiffy:encode(MapData), [return_maps])
|
|
end
|
|
).
|
|
-endif.
|
|
|
|
prop_enc_dec_pretty() ->
|
|
?FORALL(Data, json(),
|
|
begin
|
|
Data == jiffy:decode(jiffy:encode(Data, [pretty]))
|
|
end
|
|
).
|
|
|
|
prop_enc_no_crash() ->
|
|
?FORALL(Data, any(), begin catch jiffy:encode(Data), true end).
|
|
|
|
prop_dec_no_crash_bin() ->
|
|
?FORALL(Data, binary(), begin catch jiffy:decode(Data), true end).
|
|
|
|
prop_dec_no_crash_any() ->
|
|
?FORALL(Data, any(), begin catch jiffy:decode(Data), true end).
|
|
|
|
|
|
% JSON Generation
|
|
|
|
|
|
json_null() ->
|
|
null.
|
|
|
|
|
|
json_boolean() ->
|
|
oneof([true, false]).
|
|
|
|
|
|
json_number() ->
|
|
oneof([integer(), float()]).
|
|
|
|
|
|
json_string() ->
|
|
escaped_utf8_bin().
|
|
|
|
|
|
json_list(S) when S =< 0 ->
|
|
[];
|
|
json_list(S) ->
|
|
?LETSHRINK(
|
|
[ListSize],
|
|
[integer(0, S)],
|
|
vector(ListSize, json_text(S - ListSize))
|
|
).
|
|
|
|
|
|
json_object(S) when S =< 0 ->
|
|
{[]};
|
|
json_object(S) ->
|
|
?LETSHRINK(
|
|
[ObjectSize],
|
|
[integer(0, S)],
|
|
{vector(ObjectSize, {json_string(), json_text(S - ObjectSize)})}
|
|
).
|
|
|
|
|
|
json_value() ->
|
|
oneof([
|
|
json_null(),
|
|
json_boolean(),
|
|
json_string(),
|
|
json_number()
|
|
]).
|
|
|
|
|
|
json_text(S) when S > 0 ->
|
|
?LAZY(oneof([
|
|
json_list(S),
|
|
json_object(S)
|
|
]));
|
|
json_text(_) ->
|
|
json_value().
|
|
|
|
|
|
json() ->
|
|
?SIZED(S, json_text(S)).
|
|
|
|
|
|
%% XXX: Add generators
|
|
%
|
|
% We should add generators that generate JSON binaries directly
|
|
% so we can test things that aren't produced by the encoder.
|
|
%
|
|
% We should also have a version of the JSON generator that inserts
|
|
% errors into the JSON that we can test for.
|
|
|
|
|
|
escaped_utf8_bin() ->
|
|
?SUCHTHAT(Bin,
|
|
?LET(S, ?SUCHTHAT(L, list(escaped_char()), L /= []),
|
|
unicode:characters_to_binary(S, unicode, utf8)),
|
|
is_binary(Bin)
|
|
).
|
|
|
|
|
|
escaped_char() ->
|
|
?LET(C, char(),
|
|
case C of
|
|
$" -> "\\\"";
|
|
C when C == 65534 -> 65533;
|
|
C when C == 65535 -> 65533;
|
|
C when C > 1114111 -> 1114111;
|
|
C -> C
|
|
end
|
|
).
|
|
|
|
-endif.
|