Packaging 3.2.1
This commit is contained in:
parent
02a6731f58
commit
3097e90156
@ -1,15 +0,0 @@
|
|||||||
{application,aebytecode,
|
|
||||||
[{description,"A library and stand alone assembler for aeternity bytecode. This version supports AEVM bytecode and FATE bytecode."},
|
|
||||||
{registered,[]},
|
|
||||||
{included_applications,[]},
|
|
||||||
{applications,[stdlib,kernel]},
|
|
||||||
{vsn,"3.2.0"},
|
|
||||||
{modules,[aeb_fate_code_tests,aeb_fate_data_tests,
|
|
||||||
aeb_fate_encoding_tests,aefate_code_eqc,aefate_eqc,
|
|
||||||
aefate_type_eqc,aeb_aevm_abi,aeb_aevm_data,aeb_asm,
|
|
||||||
aeb_disassemble,aeb_fate_abi,aeb_fate_asm,
|
|
||||||
aeb_fate_code,aeb_fate_data,aeb_fate_encoding,
|
|
||||||
aeb_fate_generate_docs,aeb_fate_generate_ops,
|
|
||||||
aeb_fate_maps,aeb_heap,aeb_memory,aeb_opcodes,
|
|
||||||
aeb_primops,aefateasm,aeb_data_test,aeb_fate_asm_test,
|
|
||||||
aeb_serialize_test,aebytecode_SUITE]}]}.
|
|
@ -1,27 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_code`
|
|
||||||
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
|
||||||
|
|
||||||
-module(aeb_fate_code_tests).
|
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
|
|
||||||
-define(EQC_EUNIT(Module, PropName, Ms),
|
|
||||||
{ atom_to_list(PropName),
|
|
||||||
{timeout, (Ms * 10) div 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
|
||||||
|
|
||||||
quickcheck_test_() ->
|
|
||||||
{setup, fun() -> eqc:start() end,
|
|
||||||
[ ?EQC_EUNIT(aefate_code_eqc, prop_opcodes, 200),
|
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_serializes, 3000),
|
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_fail_serializes, 3000),
|
|
||||||
?EQC_EUNIT(aefate_code_eqc, prop_fuzz, 3000)
|
|
||||||
]}.
|
|
@ -1,27 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_data`
|
|
||||||
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
|
||||||
|
|
||||||
-module(aeb_fate_data_tests).
|
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
|
|
||||||
-define(EQC_EUNIT(Module, PropName, Ms),
|
|
||||||
{ atom_to_list(PropName),
|
|
||||||
{timeout, (Ms * 3) / 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
|
||||||
|
|
||||||
quickcheck_test_() ->
|
|
||||||
{setup, fun() -> eqc:start() end,
|
|
||||||
[ ?EQC_EUNIT(aefate_eqc, prop_roundtrip, 500),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_format_scan, 2000),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_order, 2000),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_fuzz, 2000)
|
|
||||||
]}.
|
|
@ -1,27 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Allow to run QuickCheck tests as eunit tests
|
|
||||||
%%% `rebar3 as eqc eunit --cover`
|
|
||||||
%%% or `rebar3 as eqc eunit --module=aeb_fate_encoding`
|
|
||||||
%%% Note that for obtaining cover file, one needs `rebar3 as eqc cover
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts
|
|
||||||
|
|
||||||
-module(aeb_fate_encoding_tests).
|
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
|
|
||||||
-define(EQC_EUNIT(Module, PropName, Ms),
|
|
||||||
{ atom_to_list(PropName),
|
|
||||||
{timeout, (Ms * 3) / 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
|
||||||
|
|
||||||
quickcheck_test_() ->
|
|
||||||
{setup, fun() -> eqc:start() end,
|
|
||||||
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
|
|
||||||
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
|
||||||
]}.
|
|
@ -1,167 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
|
||||||
%%%
|
|
||||||
%%% We want to be sure that we can deserialize all FATE assembler that is accepted on chain.
|
|
||||||
%%%
|
|
||||||
%%% We test something slightly weaker here,
|
|
||||||
%%% viz. All FATE assembler we serialize, we can deserialize
|
|
||||||
%%%
|
|
||||||
%%% Negative testing modelled:
|
|
||||||
%%% Failure 1: function names differ from 4 bytes
|
|
||||||
%%% Failure 2: pointer to empty code block
|
|
||||||
%%% Failure 3: end_BB operation as not ending block or not at end of block
|
|
||||||
%%% - empty code blocks
|
|
||||||
%%% - blocks that are not of the form (not end_bb)* end_bb.
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
|
||||||
|
|
||||||
-module(aefate_code_eqc).
|
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
%%-define(Failure(Failures, Number), case lists:member(Number, Failures) of true -> 1; false -> 0 end)
|
|
||||||
|
|
||||||
|
|
||||||
prop_serializes() ->
|
|
||||||
in_parallel(
|
|
||||||
?FORALL(FateCode, fate_code(0),
|
|
||||||
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(Binary))))
|
|
||||||
=/= true} || Failure <- [1, 2, 3, 4, 5] ]).
|
|
||||||
|
|
||||||
prop_fuzz() ->
|
|
||||||
in_parallel(
|
|
||||||
?FORALL(Binary, ?LET(FateCode, fate_code(0), aeb_fate_code:serialize(FateCode)),
|
|
||||||
?FORALL(FuzzedBin, fuzz(Binary),
|
|
||||||
try aeb_fate_code:deserialize(FuzzedBin) of
|
|
||||||
Code ->
|
|
||||||
?WHENFAIL(eqc:format("Code:\n ~p\n", [Code]),
|
|
||||||
begin
|
|
||||||
Bin1 = aeb_fate_code:serialize(Code),
|
|
||||||
Code1 = aeb_fate_code:deserialize(Bin1),
|
|
||||||
?WHENFAIL(eqc:format("Reserialized\n ~120p\n", [Bin1]),
|
|
||||||
equals(Code, Code1))
|
|
||||||
end)
|
|
||||||
catch _:_ -> true
|
|
||||||
end))).
|
|
||||||
|
|
||||||
prop_opcodes() ->
|
|
||||||
?FORALL(Opcode, choose(0, 16#ff),
|
|
||||||
try M = aeb_fate_opcodes:mnemonic(Opcode),
|
|
||||||
?WHENFAIL(eqc:format("opcode ~p -> ~p", [Opcode, M]),
|
|
||||||
conjunction([{valid, lists:member(Opcode, valid_opcodes())},
|
|
||||||
{eq, equals(aeb_fate_opcodes:m_to_op(M), Opcode)}]))
|
|
||||||
catch
|
|
||||||
_:_ ->
|
|
||||||
not lists:member(Opcode, valid_opcodes())
|
|
||||||
end).
|
|
||||||
|
|
||||||
|
|
||||||
valid_opcodes() ->
|
|
||||||
[ Op || #{opcode := Op} <- aeb_fate_generate_ops:get_ops() ].
|
|
||||||
|
|
||||||
|
|
||||||
fate_code(Failure) ->
|
|
||||||
?SIZED(Size,
|
|
||||||
?LET({FMap, SMap, AMap},
|
|
||||||
{non_empty(map(if Failure == 1 -> binary(1);
|
|
||||||
true -> binary(4) end,
|
|
||||||
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
|
||||||
{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
|
||||||
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, short_list(6, bb_code(Failure)),
|
|
||||||
maps:from_list(
|
|
||||||
lists:zip(lists:seq(0, length(BBs)-1), BBs)))}]).
|
|
||||||
|
|
||||||
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(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) ->
|
|
||||||
[ begin
|
|
||||||
Mnemonic = aeb_fate_opcodes:mnemonic(Op),
|
|
||||||
Arity = aeb_fate_opcodes:args(Op),
|
|
||||||
case Arity of
|
|
||||||
0 -> Mnemonic;
|
|
||||||
_ -> list_to_tuple([Mnemonic |
|
|
||||||
[ frequency([{if Failure == 5 -> 5; true -> 0 end, {stack, nat()}},
|
|
||||||
{5, {stack, 0}},
|
|
||||||
{5, {arg, nat()}},
|
|
||||||
{5, {var, nat()}},
|
|
||||||
{5, {immediate, small_fate_data(4)}}]) ||
|
|
||||||
_ <- lists:seq(1, Arity) ]])
|
|
||||||
end
|
|
||||||
end || Op <- Ops ].
|
|
||||||
|
|
||||||
fuzz(Binary) ->
|
|
||||||
?LET({N, Inj}, {choose(0, byte_size(Binary) - 1), choose(0, 255)},
|
|
||||||
begin
|
|
||||||
M = N * 8,
|
|
||||||
<<X:M, _:8, Z/binary>> = 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())).
|
|
||||||
|
|
||||||
small_fate_data_key(N) ->
|
|
||||||
?SIZED(Size, ?LET(Data, aefate_eqc:fate_data(Size div N, []), eqc_symbolic:eval(Data))).
|
|
@ -1,211 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
|
||||||
%%%
|
|
||||||
%%% We need to be able to generate data that serializes with ?LONG_LIST, ?LONG_TUPLE etc.
|
|
||||||
%%% In other words make some rather broad terms as well as some deep terms
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
|
||||||
|
|
||||||
-module(aefate_eqc).
|
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
|
||||||
-include("../include/aeb_fate_data.hrl").
|
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
|
|
||||||
prop_roundtrip() ->
|
|
||||||
?FORALL(FateData, fate_data(),
|
|
||||||
measure(bytes, size(term_to_binary(FateData)),
|
|
||||||
begin
|
|
||||||
Serialized = aeb_fate_encoding:serialize(FateData),
|
|
||||||
?WHENFAIL(eqc:format("Serialized ~p to ~p~n", [FateData, Serialized]),
|
|
||||||
equals(aeb_fate_encoding:deserialize(Serialized), FateData))
|
|
||||||
end)).
|
|
||||||
|
|
||||||
prop_format_scan() ->
|
|
||||||
?FORALL(FateData, fate_data([variant, map]),
|
|
||||||
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
|
||||||
begin
|
|
||||||
String = aeb_fate_data:format(FateData),
|
|
||||||
{ok, _Scanned, _} = aeb_fate_asm_scan:scan(unicode:characters_to_list(String)),
|
|
||||||
true
|
|
||||||
end)).
|
|
||||||
|
|
||||||
prop_serializes() ->
|
|
||||||
?FORALL({Data, Garbage}, {fate_data(), binary()},
|
|
||||||
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
|
|
||||||
begin
|
|
||||||
Binary = <<(aeb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
|
|
||||||
{FateData, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
|
||||||
measure(binary_size, size(Binary),
|
|
||||||
conjunction([{equal, equals(Data, FateData)},
|
|
||||||
{rest, equals(Garbage, Rest)},
|
|
||||||
{size, size(Binary) < 500000}]))
|
|
||||||
end)).
|
|
||||||
|
|
||||||
prop_no_maps_in_keys() ->
|
|
||||||
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
|
||||||
begin
|
|
||||||
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
|
||||||
try aeb_fate_encoding:serialize(FateData),
|
|
||||||
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
|
||||||
not HasMapInKeys)
|
|
||||||
catch error:Reason ->
|
|
||||||
?WHENFAIL(eqc:format("(~p) Should serialize\n", [Reason]), HasMapInKeys)
|
|
||||||
end
|
|
||||||
end).
|
|
||||||
|
|
||||||
prop_fuzz() ->
|
|
||||||
in_parallel(
|
|
||||||
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
|
||||||
?FORALL(InjectedBin, injection(Binary),
|
|
||||||
try Org = aeb_fate_encoding:deserialize(InjectedBin),
|
|
||||||
NewBin = aeb_fate_encoding:serialize(Org),
|
|
||||||
NewOrg = aeb_fate_encoding:deserialize(NewBin),
|
|
||||||
measure(success, 1,
|
|
||||||
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
|
|
||||||
equals(NewBin, InjectedBin)))
|
|
||||||
catch _:_ ->
|
|
||||||
true
|
|
||||||
end))).
|
|
||||||
|
|
||||||
|
|
||||||
prop_order() ->
|
|
||||||
?FORALL(Items, vector(3, fate_data([variant, map])),
|
|
||||||
begin
|
|
||||||
%% Use lt to take minimum
|
|
||||||
Min = lt_min(Items),
|
|
||||||
Max = lt_max(Items),
|
|
||||||
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
|
||||||
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
|
|
||||||
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
|
|
||||||
end).
|
|
||||||
|
|
||||||
lt_min([X, Y | Rest]) ->
|
|
||||||
case aeb_fate_data:lt(X, Y) of
|
|
||||||
true -> lt_min([X | Rest]);
|
|
||||||
false -> lt_min([Y| Rest])
|
|
||||||
end;
|
|
||||||
lt_min([X]) -> X.
|
|
||||||
|
|
||||||
lt_max([X, Y | Rest]) ->
|
|
||||||
case aeb_fate_data:lt(X, Y) of
|
|
||||||
true -> lt_max([Y | Rest]);
|
|
||||||
false -> lt_max([X| Rest])
|
|
||||||
end;
|
|
||||||
lt_max([X]) -> X.
|
|
||||||
|
|
||||||
prop_idempotent() ->
|
|
||||||
?FORALL(Items, list({fate_data_key(), fate_data()}),
|
|
||||||
equals(aeb_fate_encoding:sort(Items),
|
|
||||||
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fate_data(Kind) ->
|
|
||||||
?SIZED(Size, ?LET(Data, fate_data(Size, Kind), eqc_symbolic:eval(Data))).
|
|
||||||
|
|
||||||
fate_data() ->
|
|
||||||
fate_data([map, variant, store_map]).
|
|
||||||
|
|
||||||
%% keys may contain variants but no maps
|
|
||||||
fate_data_key() ->
|
|
||||||
fate_data([variant]).
|
|
||||||
|
|
||||||
fate_data(0, Options) ->
|
|
||||||
?LAZY(
|
|
||||||
frequency(
|
|
||||||
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
|
||||||
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
|
||||||
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}] ++
|
|
||||||
[{1, fate_store_map()} || lists:member(store_map, Options)]));
|
|
||||||
fate_data(Size, 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() -> ?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_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(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(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(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(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, store_map])),
|
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
|
||||||
|
|
||||||
fate_store_map() ->
|
|
||||||
%% only #{} is allowed as cache in serialization
|
|
||||||
?LET(X, oneof([int(), largeint()]),
|
|
||||||
return(aeb_fate_data:make_store_map(abs(X)))).
|
|
||||||
|
|
||||||
fate_bad_map() ->
|
|
||||||
?LET(N, choose(0, 6),
|
|
||||||
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
|
||||||
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
|
||||||
|
|
||||||
non_quote_string() ->
|
|
||||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
|
||||||
|
|
||||||
char() ->
|
|
||||||
choose(1, 255).
|
|
||||||
|
|
||||||
injection(Binary) ->
|
|
||||||
?LET({N, Inj}, {choose(0, byte_size(Binary) - 1), choose(0,255)},
|
|
||||||
begin
|
|
||||||
M = N * 8,
|
|
||||||
<<X:M, _:8, Z/binary>> = Binary,
|
|
||||||
<<X:M, Inj:8, Z/binary>>
|
|
||||||
end).
|
|
||||||
|
|
||||||
is_empty(L) ->
|
|
||||||
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
|
||||||
|
|
||||||
has_map(L) when is_list(L) ->
|
|
||||||
lists:any(fun(V) -> has_map(V) end, L);
|
|
||||||
has_map(T) when is_tuple(T) ->
|
|
||||||
has_map(tuple_to_list(T));
|
|
||||||
has_map(M) when is_map(M) ->
|
|
||||||
true;
|
|
||||||
has_map(?FATE_STORE_MAP(_, _)) ->
|
|
||||||
true;
|
|
||||||
has_map(_) ->
|
|
||||||
false.
|
|
@ -1,56 +0,0 @@
|
|||||||
%%% @author Thomas Arts
|
|
||||||
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
|
||||||
%%% Properties for testing Fate type representations
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
|
||||||
|
|
||||||
-module(aefate_type_eqc).
|
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
|
||||||
|
|
||||||
-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(kind(FateType),
|
|
||||||
begin
|
|
||||||
Serialized = aeb_fate_encoding:serialize_type(FateType),
|
|
||||||
BinSerialized = list_to_binary(Serialized),
|
|
||||||
?WHENFAIL(eqc:format("Serialized ~p to ~p (~p)~n", [FateType, Serialized, BinSerialized]),
|
|
||||||
begin
|
|
||||||
{Type, <<>>} = aeb_fate_encoding:deserialize_type(BinSerialized),
|
|
||||||
equals(Type, FateType)
|
|
||||||
end)
|
|
||||||
end)).
|
|
||||||
|
|
||||||
|
|
||||||
fate_type() ->
|
|
||||||
?SIZED(Size, fate_type(Size)).
|
|
||||||
|
|
||||||
fate_type(0) ->
|
|
||||||
oneof([integer,
|
|
||||||
boolean,
|
|
||||||
address,
|
|
||||||
{bytes, nat()},
|
|
||||||
contract,
|
|
||||||
oracle,
|
|
||||||
channel,
|
|
||||||
bits,
|
|
||||||
string]);
|
|
||||||
fate_type(Size) ->
|
|
||||||
?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)))).
|
|
||||||
|
|
59
rebar.config
59
rebar.config
@ -1,59 +0,0 @@
|
|||||||
%% -*- mode: erlang; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
{minimum_otp_vsn, "20.1"}.
|
|
||||||
|
|
||||||
{erl_opts, [debug_info]}.
|
|
||||||
|
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
|
||||||
{ref, "eb68fe3"}}}
|
|
||||||
, {getopt, "1.0.1"}
|
|
||||||
]}.
|
|
||||||
|
|
||||||
{escript_incl_apps, [aebytecode, eblake2, aeserialization, getopt]}.
|
|
||||||
{escript_main_app, aebytecode}.
|
|
||||||
{escript_name, aefateasm}.
|
|
||||||
{escript_emu_args, "%%!"}.
|
|
||||||
|
|
||||||
{pre_hooks,
|
|
||||||
[{"(linux|darwin|solaris|win32)", compile, "make sources"},
|
|
||||||
{"(freebsd)", compile, "gmake sources"}]}.
|
|
||||||
|
|
||||||
{provider_hooks, [{post, [{compile, escriptize}]}]}.
|
|
||||||
|
|
||||||
|
|
||||||
{dialyzer, [
|
|
||||||
{warnings, [unknown]},
|
|
||||||
{plt_apps, all_deps},
|
|
||||||
{base_plt_apps, [erts, kernel, stdlib, crypto, getopt]}
|
|
||||||
]}.
|
|
||||||
|
|
||||||
|
|
||||||
{relx, [{release, {aebytecode, "3.2.0"},
|
|
||||||
[aebytecode, eblake2, getopt]},
|
|
||||||
|
|
||||||
{dev_mode, true},
|
|
||||||
{include_erts, false},
|
|
||||||
|
|
||||||
{extended_start_script, true}]}.
|
|
||||||
|
|
||||||
{profiles, [{binary, [
|
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
|
||||||
{ref, "47aaa8f"}}}
|
|
||||||
, {getopt, "1.0.1"}
|
|
||||||
]},
|
|
||||||
|
|
||||||
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
|
|
||||||
escriptize,
|
|
||||||
"cp \"$REBAR_BUILD_DIR/bin/aefateasm\" ./aefateasm"},
|
|
||||||
{"win32",
|
|
||||||
escriptize,
|
|
||||||
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ aefateasm* "
|
|
||||||
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
|
|
||||||
]}
|
|
||||||
]},
|
|
||||||
{eqc, [{erl_opts, [{parse_transform, eqc_cover}, {d, 'EQC'}]},
|
|
||||||
{extra_src_dirs, ["quickcheck"]} %% May not be called eqc!
|
|
||||||
]}
|
|
||||||
]}.
|
|
23
rebar.lock
23
rebar.lock
@ -1,23 +0,0 @@
|
|||||||
{"1.2.0",
|
|
||||||
[{<<"aeserialization">>,
|
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
|
||||||
{ref,"eb68fe331bd476910394966b7f5ede7a74d37e35"}},
|
|
||||||
0},
|
|
||||||
{<<"base58">>,
|
|
||||||
{git,"https://github.com/aeternity/erl-base58.git",
|
|
||||||
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
|
||||||
1},
|
|
||||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
|
||||||
{<<"enacl">>,
|
|
||||||
{git,"https://github.com/aeternity/enacl.git",
|
|
||||||
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
|
|
||||||
1},
|
|
||||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
|
||||||
[
|
|
||||||
{pkg_hash,[
|
|
||||||
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
|
||||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
|
|
||||||
{pkg_hash_ext,[
|
|
||||||
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
|
|
||||||
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
|
|
||||||
].
|
|
Loading…
x
Reference in New Issue
Block a user