Merge pull request #75 from aeternity/fix_aci

Restructure and improve ACI
This commit is contained in:
Hans Svensson
2019-05-31 11:33:07 +02:00
committed by GitHub
11 changed files with 455 additions and 431 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
-module(aeso_abi_tests).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
-compile([export_all, nowarn_export_all]).
-define(SANDBOX(Code), sandbox(fun() -> Code end)).
-define(DUMMY_HASH_WORD, 16#123).
+92 -46
View File
@@ -2,31 +2,30 @@
-include_lib("eunit/include/eunit.hrl").
do_test() ->
test_contract(1),
test_contract(2),
test_contract(3).
simple_aci_test_() ->
[{"Test contract " ++ integer_to_list(N),
fun() -> test_contract(N) end}
|| N <- [1, 2, 3]].
test_contract(N) ->
{Contract,MapACI,DecACI} = test_cases(N),
{ok,JSON} = aeso_aci:encode(Contract),
?assertEqual(MapACI, jsx:decode(JSON, [return_maps])),
?assertEqual(DecACI, aeso_aci:decode(JSON)).
{ok,JSON} = aeso_aci:contract_interface(json, Contract),
?assertEqual([MapACI], JSON),
?assertEqual({ok, DecACI}, aeso_aci:render_aci_json(JSON)).
test_cases(1) ->
Contract = <<"contract C =\n"
" function a(i : int) = i+1\n">>,
MapACI = #{<<"contract">> =>
#{<<"name">> => <<"C">>,
<<"type_defs">> => [],
<<"functions">> =>
[#{<<"name">> => <<"a">>,
<<"arguments">> =>
[#{<<"name">> => <<"i">>,
<<"type">> => [<<"int">>]}],
<<"returns">> => <<"int">>,
<<"stateful">> => false}]}},
MapACI = #{contract =>
#{name => <<"C">>,
type_defs => [],
functions =>
[#{name => <<"a">>,
arguments =>
[#{name => <<"i">>,
type => <<"int">>}],
returns => <<"int">>,
stateful => false}]}},
DecACI = <<"contract C =\n"
" function a : (int) => int\n">>,
{Contract,MapACI,DecACI};
@@ -35,42 +34,89 @@ test_cases(2) ->
Contract = <<"contract C =\n"
" type allan = int\n"
" function a(i : allan) = i+1\n">>,
MapACI = #{<<"contract">> =>
#{<<"name">> => <<"C">>,
<<"type_defs">> =>
[#{<<"name">> => <<"allan">>,
<<"typedef">> => <<"int">>,
<<"vars">> => []}],
<<"functions">> =>
[#{<<"arguments">> =>
[#{<<"name">> => <<"i">>,
<<"type">> => [<<"int">>]}],
<<"name">> => <<"a">>,
<<"returns">> => <<"int">>,
<<"stateful">> => false}]}},
MapACI = #{contract =>
#{name => <<"C">>,
type_defs =>
[#{name => <<"allan">>,
typedef => <<"int">>,
vars => []}],
functions =>
[#{arguments =>
[#{name => <<"i">>,
type => <<"C.allan">>}],
name => <<"a">>,
returns => <<"int">>,
stateful => false}]}},
DecACI = <<"contract C =\n"
" function a : (int) => int\n">>,
" type allan = int\n"
" function a : (C.allan) => int\n">>,
{Contract,MapACI,DecACI};
test_cases(3) ->
Contract = <<"contract C =\n"
" type state = ()\n"
" datatype event = SingleEventDefined\n"
" datatype bert('a) = Bin('a)\n"
" function a(i : bert(string)) = 1\n">>,
MapACI = #{<<"contract">> =>
#{<<"functions">> =>
[#{<<"arguments">> =>
[#{<<"name">> => <<"i">>,
<<"type">> =>
[#{<<"C.bert">> => [<<"string">>]}]}],
<<"name">> => <<"a">>,<<"returns">> => <<"int">>,
<<"stateful">> => false}],
<<"name">> => <<"C">>,
<<"type_defs">> =>
[#{<<"name">> => <<"bert">>,
<<"typedef">> =>
#{<<"variant">> =>
MapACI = #{contract =>
#{functions =>
[#{arguments =>
[#{name => <<"i">>,
type =>
#{<<"C.bert">> => [<<"string">>]}}],
name => <<"a">>,returns => <<"int">>,
stateful => false}],
name => <<"C">>,
event => #{variant => [#{<<"SingleEventDefined">> => []}]},
state => #{tuple => []},
type_defs =>
[#{name => <<"bert">>,
typedef =>
#{variant =>
[#{<<"Bin">> => [<<"'a">>]}]},
<<"vars">> => [#{<<"name">> => <<"'a">>}]}]}},
vars => [#{name => <<"'a">>}]}]}},
DecACI = <<"contract C =\n"
" type state = ()\n"
" datatype event = SingleEventDefined\n"
" datatype bert('a) = Bin('a)\n"
" function a : (C.bert(string)) => int\n">>,
{Contract,MapACI,DecACI}.
%% Rounttrip
aci_test_() ->
[{"Testing ACI generation for " ++ ContractName,
fun() -> aci_test_contract(ContractName) end}
|| ContractName <- all_contracts()].
all_contracts() -> aeso_compiler_tests:compilable_contracts().
aci_test_contract(Name) ->
String = aeso_test_utils:read_contract(Name),
Opts = [{include, {file_system, [aeso_test_utils:contract_path()]}}],
{ok, JSON} = aeso_aci:contract_interface(json, String, Opts),
io:format("JSON:\n~p\n", [JSON]),
{ok, ContractStub} = aeso_aci:render_aci_json(JSON),
io:format("STUB:\n~s\n", [ContractStub]),
check_stub(ContractStub, [{src_file, Name}]),
ok.
check_stub(Stub, Options) ->
case aeso_parser:string(binary_to_list(Stub), Options) of
{ok, Ast} ->
try
%% io:format("AST: ~120p\n", [Ast]),
aeso_ast_infer_types:infer(Ast, [])
catch _:{type_errors, TE} ->
io:format("Type error:\n~s\n", [TE]),
error(TE);
_:R ->
io:format("Error: ~p\n", [R]),
error(R)
end;
{error, E} ->
io:format("Error: ~p\n", [E]),
error({parse_error, E})
end.
+16 -21
View File
@@ -221,20 +221,15 @@ failing_contracts() ->
, {"missing_fields_in_record_expression",
[<<"The field x is missing when constructing an element of type r('a) (at line 7, column 40)">>,
<<"The field y is missing when constructing an element of type r(int) (at line 8, column 40)">>,
<<"The fields y, z are missing when constructing an element of type r('1) (at line 6, column 40)">>]}
<<"The fields y, z are missing when constructing an element of type r('a) (at line 6, column 40)">>]}
, {"namespace_clash",
[<<"The contract Call (at line 4, column 10) has the same name as a namespace at (builtin location)">>]}
, {"bad_events",
[<<"The payload type int (at line 10, column 30) should be string">>,
<<"The payload type alias_address (at line 12, column 30) equals address but it should be string">>,
<<"The indexed type string (at line 9, column 25) is not a word type">>,
<<"The indexed type alias_string (at line 11, column 25) equals string which is not a word type">>]}
[<<"The indexed type string (at line 9, column 25) is not a word type">>,
<<"The indexed type alias_string (at line 10, column 25) equals string which is not a word type">>]}
, {"bad_events2",
[<<"The event constructor BadEvent1 (at line 9, column 7) has too many non-indexed values (max 1)">>,
<<"The event constructor BadEvent2 (at line 10, column 7) has too many indexed values (max 3)">>,
<<"The event constructor BadEvent3 (at line 11, column 7) has too many non-indexed values (max 1)">>,
<<"The payload type address (at line 11, column 17) should be string">>,
<<"The payload type int (at line 11, column 26) should be string">>]}
<<"The event constructor BadEvent2 (at line 10, column 7) has too many indexed values (max 3)">>]}
, {"type_clash",
[<<"Cannot unify int\n"
" and string\n"
@@ -261,46 +256,46 @@ failing_contracts() ->
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
"has the type\n"
" address">>,
<<"Cannot unify oracle_query('1, '2)\n"
<<"Cannot unify oracle_query('a, 'b)\n"
" and Remote\n"
"when checking the type of the expression at line 25, column 5\n"
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
" oracle_query('1, '2)\n"
" oracle_query('a, 'b)\n"
"against the expected type\n"
" Remote">>,
<<"Cannot unify oracle_query('3, '4)\n"
<<"Cannot unify oracle_query('c, 'd)\n"
" and bytes(32)\n"
"when checking the type of the expression at line 23, column 5\n"
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
" oracle_query('3, '4)\n"
" oracle_query('c, 'd)\n"
"against the expected type\n"
" bytes(32)">>,
<<"Cannot unify oracle_query('5, '6)\n"
<<"Cannot unify oracle_query('e, 'f)\n"
" and oracle(int, bool)\n"
"when checking the type of the expression at line 21, column 5\n"
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
" oracle_query('5, '6)\n"
" oracle_query('e, 'f)\n"
"against the expected type\n"
" oracle(int, bool)">>,
<<"Cannot unify oracle('7, '8)\n"
<<"Cannot unify oracle('g, 'h)\n"
" and Remote\n"
"when checking the type of the expression at line 18, column 5\n"
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
" oracle('7, '8)\n"
" oracle('g, 'h)\n"
"against the expected type\n"
" Remote">>,
<<"Cannot unify oracle('9, '10)\n"
<<"Cannot unify oracle('i, 'j)\n"
" and bytes(32)\n"
"when checking the type of the expression at line 16, column 5\n"
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
" oracle('9, '10)\n"
" oracle('i, 'j)\n"
"against the expected type\n"
" bytes(32)">>,
<<"Cannot unify oracle('11, '12)\n"
<<"Cannot unify oracle('k, 'l)\n"
" and oracle_query(int, bool)\n"
"when checking the type of the expression at line 14, column 5\n"
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
" oracle('11, '12)\n"
" oracle('k, 'l)\n"
"against the expected type\n"
" oracle_query(int, bool)">>,
<<"Cannot unify address\n"
+2 -4
View File
@@ -6,10 +6,8 @@ contract Events =
datatype event =
Event1(indexed alias_int, indexed int, string)
| Event2(alias_string, indexed alias_address)
| BadEvent1(indexed string, string)
| BadEvent2(indexed int, int)
| BadEvent3(indexed alias_string, string)
| BadEvent4(indexed int, alias_address)
| BadEvent1(indexed string)
| BadEvent2(indexed alias_string)
function f1(x : int, y : string) =
Chain.event(Event1(x, x+1, y))
-1
View File
@@ -8,7 +8,6 @@ contract Events =
| Event2(alias_string, indexed alias_address)
| BadEvent1(string, string)
| BadEvent2(indexed int, indexed int, indexed int, indexed address)
| BadEvent3(address, int)
function f1(x : int, y : string) =
Chain.event(Event1(x, x+1, y))