Update and clean up quickcheck tests
This commit is contained in:
parent
f421c1e361
commit
f13ba67a2c
@ -27,22 +27,25 @@
|
||||
prop_serializes() ->
|
||||
in_parallel(
|
||||
?FORALL(FateCode, fate_code(0),
|
||||
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [FateCode]),
|
||||
begin
|
||||
Binary = aeb_fate_code:serialize(FateCode),
|
||||
?WHENFAIL(eqc:format("serialized: ~p~n", [Binary]),
|
||||
begin
|
||||
Decoded = aeb_fate_code:deserialize(Binary),
|
||||
measure(binary_size, size(Binary),
|
||||
equals(Decoded, FateCode))
|
||||
end)
|
||||
end))).
|
||||
begin
|
||||
{T0, Binary} = timer:tc(fun() -> aeb_fate_code:serialize(FateCode) end),
|
||||
?WHENFAIL(eqc:format("serialized:\n ~120p~n", [Binary]),
|
||||
begin
|
||||
{T1, Decoded} = timer:tc(fun() -> aeb_fate_code:deserialize(Binary) end),
|
||||
measure(binary_size, size(Binary),
|
||||
measure(serialize, T0 / 1000,
|
||||
measure(deserialize, T1 / 1000,
|
||||
conjunction([{equal, equals(Decoded, FateCode)},
|
||||
{serialize_time, T0 / 1000 < 500},
|
||||
{deserialize_time, T1 / 1000 < 500}]))))
|
||||
end)
|
||||
end)).
|
||||
|
||||
prop_fail_serializes() ->
|
||||
conjunction([{Failure, eqc:counterexample(
|
||||
?FORALL(FateCode, fate_code(Failure),
|
||||
?FORALL(Binary, catch aeb_fate_code:serialize(FateCode),
|
||||
is_binary(aeb_fate_code:serialize(FateCode)))))
|
||||
is_binary(Binary))))
|
||||
=/= true} || Failure <- [1,2,3,4, 5] ]).
|
||||
|
||||
prop_fuzz() ->
|
||||
@ -51,7 +54,7 @@ prop_fuzz() ->
|
||||
?FORALL(InjectedBin, injection(Binary),
|
||||
try Org = aeb_fate_code:deserialize(InjectedBin),
|
||||
NewBin = aeb_fate_code:serialize(Org),
|
||||
NewOrg = aeb_fate_code:deserialize(NewBin),
|
||||
NewOrg = (catch aeb_fate_code:deserialize(NewBin)),
|
||||
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
|
||||
equals(NewBin, InjectedBin))
|
||||
catch _:_ ->
|
||||
@ -80,16 +83,23 @@ fate_code(Failure) ->
|
||||
{non_empty(map(if Failure == 1 -> binary(1);
|
||||
true -> binary(4) end,
|
||||
{{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
||||
map(small_fate_data_key(5), small_fate_data(4)),
|
||||
map(small_fate_data_key(5), small_fate_data(4))},
|
||||
small_map(small_fate_data_key(5), small_fate_data(4)),
|
||||
small_map(small_fate_data_key(5), small_fate_data(4))},
|
||||
aeb_fate_code:update_annotations(
|
||||
aeb_fate_code:update_symbols(
|
||||
aeb_fate_code:update_functions(
|
||||
aeb_fate_code:new(), FMap), SMap), AMap))).
|
||||
|
||||
short_list(Max, Gen) ->
|
||||
?LET(N, choose(0, Max), eqc_gen:list(N, Gen)).
|
||||
|
||||
small_map(KeyGen, ValGen) ->
|
||||
?LET(KeyVals, short_list(6, {KeyGen, ValGen}),
|
||||
return(maps:from_list(KeyVals))).
|
||||
|
||||
bbs_code(Failure) ->
|
||||
frequency([{if Failure == 2 -> 5; true -> 0 end, #{0 => []}},
|
||||
{10, ?LET(BBs, list(bb_code(Failure)),
|
||||
{10, ?LET(BBs, short_list(6, bb_code(Failure)),
|
||||
maps:from_list(
|
||||
lists:zip(lists:seq(0, length(BBs)-1), BBs)))}]).
|
||||
|
||||
@ -97,9 +107,9 @@ bb_code(Failure) ->
|
||||
EndBB = [ Op || Op <- valid_opcodes(), aeb_fate_opcodes:end_bb(Op) ],
|
||||
NonEndBB = valid_opcodes() -- EndBB,
|
||||
frequency(
|
||||
[{if Failure == 3 -> 5; true -> 0 end, ?LET(Ops, non_empty(list(elements(NonEndBB))), bblock(Failure, Ops))},
|
||||
{if Failure == 4 -> 5; true -> 0 end, ?LET({Ops, Op}, {list(elements(valid_opcodes())), elements(EndBB)}, bblock(Failure, Ops ++ [Op]))},
|
||||
{10, ?LET({Ops, Op}, {list(elements(NonEndBB)), elements(EndBB)},
|
||||
[{if Failure == 3 -> 5; true -> 0 end, ?LET(Ops, non_empty(short_list(6, elements(NonEndBB))), bblock(Failure, Ops))},
|
||||
{if Failure == 4 -> 5; true -> 0 end, ?LET({Ops, Op}, {short_list(6, elements(valid_opcodes())), elements(EndBB)}, bblock(Failure, Ops ++ [Op]))},
|
||||
{10, ?LET({Ops, Op}, {short_list(6, elements(NonEndBB)), elements(EndBB)},
|
||||
bblock(Failure, Ops ++ [Op]))}]).
|
||||
|
||||
bblock(Failure, Ops) ->
|
||||
@ -126,6 +136,26 @@ injection(Binary) ->
|
||||
<<X:M, Inj:8, Z/binary>>
|
||||
end).
|
||||
|
||||
prop_small() ->
|
||||
?FORALL(Value, small_fate_data(4),
|
||||
begin
|
||||
Bin = aeb_fate_encoding:serialize(Value),
|
||||
Size = byte_size(Bin),
|
||||
measure(size, Size,
|
||||
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||
Size < 1000))
|
||||
end).
|
||||
|
||||
prop_small_type() ->
|
||||
?FORALL(Type, ?SIZED(Size, aefate_type_eqc:fate_type(Size div 3)),
|
||||
begin
|
||||
Bin = iolist_to_binary(aeb_fate_encoding:serialize_type(Type)),
|
||||
Size = byte_size(Bin),
|
||||
measure(size, Size,
|
||||
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||
Size < 1000))
|
||||
end).
|
||||
|
||||
small_fate_data(N) ->
|
||||
?SIZED(Size, resize(Size div N, aefate_eqc:fate_data())).
|
||||
|
||||
|
@ -32,21 +32,15 @@ prop_format_scan() ->
|
||||
end)).
|
||||
|
||||
prop_serializes() ->
|
||||
?FORALL(FateDatas, non_empty(?SIZED(Size, resize(Size div 2, list(fate_data())))),
|
||||
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [FateDatas]),
|
||||
?FORALL({Data, Garbage}, {fate_data(), binary()},
|
||||
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
|
||||
begin
|
||||
{T1, Binary} =
|
||||
timer:tc( fun() ->
|
||||
<< begin B = aeb_fate_encoding:serialize(Data),
|
||||
<<B/binary>> end || Data <- FateDatas >>
|
||||
end),
|
||||
{T2, {FateData, _}} =
|
||||
timer:tc(fun() -> aeb_fate_encoding:deserialize_one(Binary) end),
|
||||
Binary = <<(aeb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
|
||||
{FateData, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
||||
measure(binary_size, size(Binary),
|
||||
measure(encode, T1,
|
||||
measure(decode, T2,
|
||||
conjunction([{equal, equals(hd(FateDatas), FateData)},
|
||||
{size, size(Binary) < 500000}]))))
|
||||
conjunction([{equal, equals(Data, FateData)},
|
||||
{rest, equals(Garbage, Rest)},
|
||||
{size, size(Binary) < 500000}]))
|
||||
end)).
|
||||
|
||||
prop_fuzz() ->
|
||||
@ -98,74 +92,65 @@ fate_data() ->
|
||||
?SIZED(Size, ?LET(Data, fate_data(Size, [map, variant]), eqc_symbolic:eval(Data))).
|
||||
|
||||
fate_data_key() ->
|
||||
?SIZED(Size, ?LET(Data, fate_data(Size div 4, []), eqc_symbolic:eval(Data))).
|
||||
?SIZED(Size, ?LET(Data, fate_data(Size div 4, [variant]), eqc_symbolic:eval(Data))).
|
||||
|
||||
fate_data(0, _Options) ->
|
||||
?LAZY(
|
||||
oneof([fate_integer(),
|
||||
fate_boolean(),
|
||||
fate_nil(),
|
||||
fate_unit(),
|
||||
fate_string(),
|
||||
fate_address(),
|
||||
fate_hash(),
|
||||
fate_signature(),
|
||||
fate_contract(),
|
||||
fate_oracle(),
|
||||
fate_oracle_q(),
|
||||
fate_name(),
|
||||
fate_bits(),
|
||||
fate_channel()]));
|
||||
frequency(
|
||||
[{5, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||
{1, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||
fate_oracle(), fate_oracle_q(), fate_name(), fate_bits(), fate_channel()])}]));
|
||||
fate_data(Size, Options) ->
|
||||
oneof([?LAZY(fate_data(Size - 1, Options)),
|
||||
?LAZY(fate_list( fate_data(Size div 5, Options) )),
|
||||
?LAZY(fate_tuple( list(fate_data(Size div 5, Options)) ))] ++
|
||||
[?LAZY(fate_variant( list(fate_data(Size div 5, Options))))
|
||||
|| lists:member(variant, Options)
|
||||
] ++
|
||||
[
|
||||
?LAZY(fate_map( fate_data(Size div 8, Options -- [map, variant]),
|
||||
fate_data(Size div 5, Options)))
|
||||
|| lists:member(map, Options)
|
||||
]).
|
||||
?LAZY(
|
||||
oneof([fate_data(0, Options),
|
||||
fate_list(Size, Options),
|
||||
fate_tuple(Size, Options)] ++
|
||||
[fate_variant(Size, Options)
|
||||
|| lists:member(variant, Options)] ++
|
||||
[fate_map(Size, Options)
|
||||
|| lists:member(map, Options)])).
|
||||
|
||||
|
||||
fate_integer() -> {call, aeb_fate_data, make_integer, [oneof([int(), largeint()])]}.
|
||||
fate_bits() -> {call, aeb_fate_data, make_bits, [oneof([int(), largeint()])]}.
|
||||
fate_boolean() -> {call, aeb_fate_data, make_boolean, [elements([true, false])]}.
|
||||
fate_nil() -> {call, aeb_fate_data, make_list, [[]]}.
|
||||
fate_unit() -> {call, aeb_fate_data, make_unit, []}.
|
||||
fate_string() -> {call, aeb_fate_data, make_string,
|
||||
[frequency([{10, non_quote_string()}, {2, list(non_quote_string())},
|
||||
{1, ?LET(N, choose(64-3, 64+3), vector(N, $a))}])]}.
|
||||
fate_address() -> {call, aeb_fate_data, make_address, [non_zero_binary(256 div 8)]}.
|
||||
fate_hash() -> {call, aeb_fate_data, make_hash, [non_zero_binary(32)]}.
|
||||
fate_signature() -> {call, aeb_fate_data, make_signature, [non_zero_binary(64)]}.
|
||||
fate_contract() -> {call, aeb_fate_data, make_contract, [non_zero_binary(256 div 8)]}.
|
||||
fate_oracle() -> {call, aeb_fate_data, make_oracle, [non_zero_binary(256 div 8)]}.
|
||||
fate_oracle_q() -> {call, aeb_fate_data, make_oracle_query, [non_zero_binary(256 div 8)]}.
|
||||
fate_name() -> {call, aeb_fate_data, make_name, [non_zero_binary(256 div 8)]}.
|
||||
fate_channel() -> {call, aeb_fate_data, make_channel, [non_zero_binary(256 div 8)]}.
|
||||
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_integer(X))).
|
||||
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_bits(X))).
|
||||
fate_boolean() -> ?LET(X, elements([true, false]), return(aeb_fate_data:make_boolean(X))).
|
||||
fate_nil() -> aeb_fate_data:make_list([]).
|
||||
fate_unit() -> aeb_fate_data:make_unit().
|
||||
fate_string() -> ?LET(X, frequency([{10, non_quote_string()}, {2, list(non_quote_string())},
|
||||
{1, ?LET(N, choose(64-3, 64+3), vector(N, $a))}]),
|
||||
return(aeb_fate_data:make_string(X))).
|
||||
fate_address() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_address(X))).
|
||||
fate_bytes() -> ?LET(X, non_empty(binary()), return(aeb_fate_data:make_bytes(X))).
|
||||
fate_contract() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_contract(X))).
|
||||
fate_oracle() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle(X))).
|
||||
fate_oracle_q() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle_query(X))).
|
||||
fate_name() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_name(X))).
|
||||
fate_channel() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_channel(X))).
|
||||
|
||||
fate_values(Size, N, Options) ->
|
||||
eqc_gen:list(N, fate_data(Size div max(1, N), Options)).
|
||||
|
||||
%% May shrink to fate_unit
|
||||
fate_tuple(ListGen) ->
|
||||
{call, aeb_fate_data, make_tuple, [?LET(Elements, ListGen, list_to_tuple(Elements))]}.
|
||||
fate_tuple(Size, Options) ->
|
||||
?LET(N, choose(0, 6),
|
||||
?LETSHRINK(Elements, fate_values(Size, N, Options),
|
||||
return(aeb_fate_data:make_tuple(list_to_tuple(Elements))))).
|
||||
|
||||
fate_variant(ListGen) ->
|
||||
?LET({L1, L2, TupleAsList}, {list(choose(0, 255)), list(choose(0,255)), ListGen},
|
||||
{call, aeb_fate_data, make_variant,
|
||||
[L1 ++ [length(TupleAsList)] ++ L2, length(L1), list_to_tuple(TupleAsList)]}).
|
||||
fate_variant(Size, Options) ->
|
||||
?LET({L1, L2, {tuple, Args}}, {list(choose(0, 255)), list(choose(0,255)), fate_tuple(Size, Options)},
|
||||
return(aeb_fate_data:make_variant(L1 ++ [tuple_size(Args)] ++ L2,
|
||||
length(L1), Args))).
|
||||
|
||||
fate_list(Gen) ->
|
||||
{call, aeb_fate_data, make_list, [frequency([{20, list(Gen)}, {1, ?LET(N, choose(64-3, 64+3), vector(N, Gen))}])]}.
|
||||
fate_list(Size, Options) ->
|
||||
?LET(N, frequency([{20, choose(0, 6)}, {1, choose(64 - 3, 64 + 3)}]),
|
||||
?LETSHRINK(Vs, fate_values(Size, N, Options),
|
||||
return(aeb_fate_data:make_list(Vs)))).
|
||||
|
||||
fate_map(KeyGen, ValGen) ->
|
||||
{call, aeb_fate_data, make_map, [map(KeyGen, ValGen)]}.
|
||||
|
||||
|
||||
non_zero_binary(N) ->
|
||||
Bits = N*8,
|
||||
?SUCHTHAT(Bin, binary(N), begin <<V:Bits>> = Bin, V =/= 0 end).
|
||||
fate_map(Size, Options) ->
|
||||
?LET(N, choose(0, 6),
|
||||
?LETSHRINK(Values, fate_values(Size, N, Options),
|
||||
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map])),
|
||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||
|
||||
non_quote_string() ->
|
||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
||||
|
@ -11,9 +11,12 @@
|
||||
|
||||
-compile([export_all, nowarn_export_all]).
|
||||
|
||||
kind(X) when is_atom(X) -> X;
|
||||
kind(T) when is_tuple(T) -> element(1, T).
|
||||
|
||||
prop_roundtrip() ->
|
||||
?FORALL(FateType, fate_type(),
|
||||
collect(FateType,
|
||||
collect(kind(FateType),
|
||||
begin
|
||||
Serialized = aeb_fate_encoding:serialize_type(FateType),
|
||||
BinSerialized = list_to_binary(Serialized),
|
||||
@ -32,8 +35,7 @@ fate_type(0) ->
|
||||
oneof([integer,
|
||||
boolean,
|
||||
address,
|
||||
hash,
|
||||
signature,
|
||||
{bytes, nat()},
|
||||
contract,
|
||||
oracle,
|
||||
name,
|
||||
@ -41,9 +43,15 @@ fate_type(0) ->
|
||||
bits,
|
||||
string]);
|
||||
fate_type(Size) ->
|
||||
oneof([?LAZY(fate_type(Size div 2)),
|
||||
{list, ?LAZY(fate_type(Size div 2))},
|
||||
{tuple, list(?LAZY(fate_type(Size div 2)))},
|
||||
{variant, list(?LAZY(fate_type(Size div 2)))},
|
||||
?LETSHRINK([T1, T2], [?LAZY(fate_type(Size div 2)), ?LAZY(fate_type(Size div 2))],
|
||||
{map, T1, T2})]).
|
||||
?LAZY(
|
||||
oneof([fate_type(0),
|
||||
{list, fate_type(Size div 2)},
|
||||
?LETSHRINK(Ts, fate_types(Size), {tuple, Ts}),
|
||||
?LETSHRINK(Ts, fate_types(Size), {variant, Ts}),
|
||||
?LETSHRINK([T1, T2], vector(2, fate_type(Size div 2)),
|
||||
{map, T1, T2})])).
|
||||
|
||||
fate_types(Size) ->
|
||||
?LET(N, choose(0, 6),
|
||||
eqc_gen:list(N, fate_type(Size div max(2, N)))).
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user