From 68b60400d6cbdd463845dc19544c3cafe9a32292 Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Fri, 23 Sep 2016 15:19:19 -0500 Subject: [PATCH 1/3] Replace PropEr with EQC PropEr broke my support for R14. Turns out that EQC Mini is quite usable so I've just switched to that. If EQC Mini exists it will be used, if not the test is skipped gracefully. --- Makefile | 12 +- rebar.config.script | 39 ++--- test/jiffy_11_proper_tests.erl | 185 ---------------------- test/jiffy_11_property_tests.erl | 257 +++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 225 deletions(-) delete mode 100644 test/jiffy_11_proper_tests.erl create mode 100644 test/jiffy_11_property_tests.erl diff --git a/Makefile b/Makefile index 025486e..f781311 100644 --- a/Makefile +++ b/Makefile @@ -15,17 +15,7 @@ distclean: clean git clean -fxd -devmarker: - @touch .jiffy.dev - - -depends: devmarker - @if test ! -d ./deps/proper; then \ - $(REBAR) get-deps; \ - fi - - -build: depends +build: $(REBAR) compile diff --git a/rebar.config.script b/rebar.config.script index 8a0049d..42bc6ef 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -1,37 +1,18 @@ % This file is part of Jiffy released under the MIT license. % 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 -> - CONFIG + CONFIG ++ [{erl_opts, ErlOpts}] end. diff --git a/test/jiffy_11_proper_tests.erl b/test/jiffy_11_proper_tests.erl deleted file mode 100644 index 23aa38d..0000000 --- a/test/jiffy_11_proper_tests.erl +++ /dev/null @@ -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 = <>, - {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. diff --git a/test/jiffy_11_property_tests.erl b/test/jiffy_11_property_tests.erl new file mode 100644 index 0000000..70d7333 --- /dev/null +++ b/test/jiffy_11_property_tests.erl @@ -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 = <>, + {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. From 0789c08f3d1ea8d453da902578be54f875711d83 Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Fri, 23 Sep 2016 15:35:20 -0500 Subject: [PATCH 2/3] Update the list of Erlang VMs to use on Travis-CI --- .travis.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index fa26d15..4762c65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,17 +3,15 @@ notifications: email: paul.joseph.davis@gmail.com script: make check otp_release: + - 19.1 + - 19.0 + - 18.3 + - 18.2 - 17.5 - 17.4 - - 17.3 - - 17.1 - - 17.0 - R16B03-1 - R16B02 - - R16B01 - R15B03 - R15B02 - - R15B01 - R14B04 - R14B03 - - R14B02 From c7756dae9f98a86d0670d5be6539ac8202a1f86a Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Fri, 18 Mar 2016 15:48:20 -0500 Subject: [PATCH 3/3] Add support for rebar3 Allow Jiffy to be used easily in projects using either rebar 2 or 3. --- .gitignore | 5 +++++ enc | Bin 0 -> 23260 bytes rebar.config | 11 +++-------- test/jiffy_01_yajl_tests.erl | 3 ++- test/jiffy_10_short_double_tests.erl | 3 ++- test/jiffy_util.hrl | 13 +++++++++++++ 6 files changed, 25 insertions(+), 10 deletions(-) create mode 100755 enc diff --git a/.gitignore b/.gitignore index e3e5e72..c6154b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ .eunit +.rebar .jiffy.dev *.app *.beam +*.d *.o *.so +_build +compile_commands.json deps erln8.config hexer.config +rebar.lock TEST-*.xml diff --git a/enc b/enc new file mode 100755 index 0000000000000000000000000000000000000000..239a35147542533b3ea915122d63240e0a37ccfd GIT binary patch literal 23260 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 @@ -19,7 +20,7 @@ gen({Name, Json, Erl}) -> read_cases() -> - CasesPath = filename:join(["..", "test", "cases", "*.json"]), + CasesPath = cases_path("*.json"), FileNames = lists:sort(filelib:wildcard(CasesPath)), lists:map(fun(F) -> make_pair(F) end, FileNames). diff --git a/test/jiffy_10_short_double_tests.erl b/test/jiffy_10_short_double_tests.erl index d66e1ea..0b099c1 100644 --- a/test/jiffy_10_short_double_tests.erl +++ b/test/jiffy_10_short_double_tests.erl @@ -8,7 +8,8 @@ -include("jiffy_util.hrl"). -filename() -> "../test/cases/short-doubles.txt". +filename() -> + cases_path("short-doubles.txt"). short_double_test_() -> diff --git a/test/jiffy_util.hrl b/test/jiffy_util.hrl index 51bd86a..4b714d9 100644 --- a/test/jiffy_util.hrl +++ b/test/jiffy_util.hrl @@ -25,3 +25,16 @@ enc(V) -> enc(V, Opts) -> iolist_to_binary(jiffy:encode(V, Opts)). + + +%% rebar runs eunit with PWD as .eunit/ +%% rebar3 runs eunit with PWD as ./ +%% this adapts to the differences +cases_path(Suffix) -> + {ok, Cwd} = file:get_cwd(), + Prefix = case filename:basename(Cwd) of + ".eunit" -> ".."; + _ -> "." + end, + Path = "test/cases", + filename:join([Prefix, Path, Suffix]).