Add support for rebar3preencode-sketch
@ -1,10 +1,15 @@ | |||||
.eunit | .eunit | ||||
.rebar | |||||
.jiffy.dev | .jiffy.dev | ||||
*.app | *.app | ||||
*.beam | *.beam | ||||
*.d | |||||
*.o | *.o | ||||
*.so | *.so | ||||
_build | |||||
compile_commands.json | |||||
deps | deps | ||||
erln8.config | erln8.config | ||||
hexer.config | hexer.config | ||||
rebar.lock | |||||
TEST-*.xml | TEST-*.xml |
@ -1,37 +1,18 @@ | |||||
% This file is part of Jiffy released under the MIT license. | % This file is part of Jiffy released under the MIT license. | ||||
% See the LICENSE file for more information. | % See the LICENSE file for more information. | ||||
% Only include PropEr as a dependency when the JIFFY_DEV | |||||
% environment variable is defined. This allows downstream | |||||
% applications to avoid requiring PropEr. | |||||
% | % | ||||
% This script is based on the example provided with Rebar. | |||||
ErlOpts = [{d, 'JIFFY_DEV'}], | |||||
% Only run the EQC checks when EQC is present. | |||||
Proper = [ | |||||
{proper, ".*", {git, "git://github.com/manopapad/proper.git", "master"}} | |||||
], | |||||
HaveEQC = code:which(eqc) =/= non_existing, | |||||
ConfigPath = filename:dirname(SCRIPT), | |||||
DevMarker = filename:join([ConfigPath, ".jiffy.dev"]), | |||||
ErlOpts = if not HaveEQC -> []; true -> | |||||
[{d, 'HAVE_EQC'}] | |||||
end, | |||||
case filelib:is_file(DevMarker) of | |||||
true -> | |||||
% Don't override existing dependencies | |||||
Config0 = case lists:keyfind(deps, 1, CONFIG) of | |||||
false -> | |||||
CONFIG ++ [{deps, Proper}]; | |||||
{deps, DepsList} -> | |||||
lists:keyreplace(deps, 1, CONFIG, {deps, DepsList ++ Proper}) | |||||
end, | |||||
Config1 = case lists:keyfind(erl_opts, 1, Config0) of | |||||
false -> | |||||
Config0 ++ [{erl_opts, ErlOpts}]; | |||||
{erl_opts, Opts} -> | |||||
NewOpts = {erl_opts, Opts ++ ErlOpts}, | |||||
lists:keyreplace(erl_opts, 1, Config0, NewOpts) | |||||
end; | |||||
case lists:keyfind(erl_opts, 1, CONFIG) of | |||||
{erl_opts, Opts} -> | |||||
NewOpts = {erl_opts, Opts ++ ErlOpts}, | |||||
lists:keyreplace(erl_opts, 1, CONFIG, NewOpts); | |||||
false -> | false -> | ||||
CONFIG | |||||
CONFIG ++ [{erl_opts, ErlOpts}] | |||||
end. | end. |
@ -1,185 +0,0 @@ | |||||
% 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_dec_trailer), | |||||
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 | |||||
). | |||||
prop_dec_trailer() -> | |||||
?FORALL({T1, T2}, {json(), json()}, | |||||
begin | |||||
B1 = jiffy:encode(T1), | |||||
B2 = jiffy:encode(T2), | |||||
Combiners = [ | |||||
<<" ">>, | |||||
<<"\r\t">>, | |||||
<<"\n \t">>, | |||||
<<" ">> | |||||
], | |||||
lists:foreach(fun(Comb) -> | |||||
Bin = <<B1/binary, Comb/binary, B2/binary>>, | |||||
{has_trailer, T1, Rest} = jiffy:decode(Bin, [return_trailer]), | |||||
T2 = jiffy:decode(Rest) | |||||
end, Combiners), | |||||
true | |||||
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. |
@ -0,0 +1,257 @@ | |||||
% This file is part of Jiffy released under the MIT license. | |||||
% See the LICENSE file for more information. | |||||
-module(jiffy_11_property_tests). | |||||
-ifdef(HAVE_EQC). | |||||
-include_lib("eqc/include/eqc.hrl"). | |||||
-include_lib("eunit/include/eunit.hrl"). | |||||
-include("jiffy_util.hrl"). | |||||
property_test_() -> | |||||
[ | |||||
run(prop_enc_dec), | |||||
run(prop_enc_dec_pretty), | |||||
run(prop_dec_trailer), | |||||
run(prop_enc_no_crash), | |||||
run(prop_dec_no_crash_bin), | |||||
run(prop_dec_no_crash_any) | |||||
] ++ map_props(). | |||||
-ifndef(JIFFY_NO_MAPS). | |||||
map_props() -> | |||||
[ | |||||
run(prop_map_enc_dec) | |||||
]. | |||||
-else. | |||||
map_props() -> | |||||
[]. | |||||
-endif. | |||||
prop_enc_dec() -> | |||||
?FORALL(Data, json(), begin | |||||
Data == jiffy:decode(jiffy:encode(Data)) | |||||
end). | |||||
prop_dec_trailer() -> | |||||
?FORALL({T1, Comb, T2}, {json(), combiner(), json()}, | |||||
begin | |||||
B1 = jiffy:encode(T1), | |||||
B2 = jiffy:encode(T2), | |||||
Bin = <<B1/binary, Comb/binary, B2/binary>>, | |||||
{has_trailer, T1, Rest} = jiffy:decode(Bin, [return_trailer]), | |||||
T2 = jiffy:decode(Rest), | |||||
true | |||||
end | |||||
). | |||||
prop_enc_dec_pretty() -> | |||||
?FORALL(Data, json(), | |||||
begin | |||||
Data == jiffy:decode(jiffy:encode(Data, [pretty])) | |||||
end | |||||
). | |||||
-ifndef(JIFFY_NO_MAPS). | |||||
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_no_crash() -> | |||||
?FORALL(Data, any(), begin catch jiffy:encode(Data), true end). | |||||
prop_dec_no_crash_any() -> | |||||
?FORALL(Data, any(), begin catch jiffy:decode(Data), true end). | |||||
prop_dec_no_crash_bin() -> | |||||
?FORALL(Data, binary(), begin catch jiffy:decode(Data), true end). | |||||
opts() -> | |||||
[ | |||||
{numtests, [1000]} | |||||
]. | |||||
apply_opts(Prop) -> | |||||
apply_opts(Prop, opts()). | |||||
apply_opts(Prop, []) -> | |||||
Prop; | |||||
apply_opts(Prop, [{Name, Args} | Rest]) -> | |||||
NewProp = erlang:apply(eqc, Name, Args ++ [Prop]), | |||||
apply_opts(NewProp, Rest). | |||||
log(F, A) -> | |||||
io:format(standard_error, F, A). | |||||
run(Name) -> | |||||
Prop = apply_opts(?MODULE:Name()), | |||||
{msg("~s", [Name]), [ | |||||
{timeout, 300, ?_assert(eqc:quickcheck(Prop))} | |||||
]}. | |||||
-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. | |||||
-endif. | |||||
% Random any term generation | |||||
any() -> | |||||
?SIZED(Size, any(Size)). | |||||
any(0) -> | |||||
any_value(); | |||||
any(S) -> | |||||
oneof(any_value_types() ++ [ | |||||
?LAZY(any_list(S)), | |||||
?LAZY(any_tuple(S)) | |||||
]). | |||||
any_value() -> | |||||
oneof(any_value_types()). | |||||
any_value_types() -> | |||||
[ | |||||
largeint(), | |||||
int(), | |||||
real(), | |||||
atom(), | |||||
binary() | |||||
]. | |||||
any_list(0) -> | |||||
[]; | |||||
any_list(Size) -> | |||||
ListSize = Size div 5, | |||||
vector(ListSize, any(Size div 2)). | |||||
any_tuple(0) -> | |||||
{}; | |||||
any_tuple(Size) -> | |||||
?LET(L, any_list(Size), list_to_tuple(L)). | |||||
% JSON Generation | |||||
json() -> | |||||
?SIZED(Size, json(Size)). | |||||
json(0) -> | |||||
oneof([ | |||||
json_null(), | |||||
json_true(), | |||||
json_false(), | |||||
json_number(), | |||||
json_string() | |||||
]); | |||||
json(Size) -> | |||||
frequency([ | |||||
{1, json_null()}, | |||||
{1, json_true()}, | |||||
{1, json_false()}, | |||||
{1, json_number()}, | |||||
{1, json_string()}, | |||||
{5, ?LAZY(json_array(Size))}, | |||||
{5, ?LAZY(json_object(Size))} | |||||
]). | |||||
json_null() -> | |||||
null. | |||||
json_true() -> | |||||
true. | |||||
json_false() -> | |||||
false. | |||||
json_number() -> | |||||
oneof([largeint(), int(), real()]). | |||||
json_string() -> | |||||
utf8(). | |||||
json_array(0) -> | |||||
[]; | |||||
json_array(Size) -> | |||||
ArrSize = Size div 5, | |||||
vector(ArrSize, json(Size div 2)). | |||||
json_object(0) -> | |||||
{[]}; | |||||
json_object(Size) -> | |||||
ObjSize = Size div 5, | |||||
{vector(ObjSize, {json_string(), json(Size div 2)})}. | |||||
combiner() -> | |||||
?SIZED( | |||||
Size, | |||||
?LET( | |||||
L, | |||||
vector((Size div 4) + 1, oneof([$\r, $\n, $\t, $\s])), | |||||
list_to_binary(L) | |||||
) | |||||
). | |||||
atom() -> | |||||
?LET(L, ?SIZED(Size, vector(Size rem 254, char())), list_to_atom(L)). | |||||
%% 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. | |||||
-endif. |