Przeglądaj źródła

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.
pull/118/head
Paul J. Davis 8 lat temu
rodzic
commit
68b60400d6
4 zmienionych plików z 268 dodań i 225 usunięć
  1. +1
    -11
      Makefile
  2. +10
    -29
      rebar.config.script
  3. +0
    -185
      test/jiffy_11_proper_tests.erl
  4. +257
    -0
      test/jiffy_11_property_tests.erl

+ 1
- 11
Makefile Wyświetl plik

@ -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

+ 10
- 29
rebar.config.script Wyświetl plik

@ -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.

+ 0
- 185
test/jiffy_11_proper_tests.erl Wyświetl plik

@ -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.

+ 257
- 0
test/jiffy_11_property_tests.erl Wyświetl plik

@ -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.

Ładowanie…
Anuluj
Zapisz