This commit is contained in:
chriseth 2016-10-19 18:43:42 +02:00
parent ff3553a348
commit 87b148494b
3 changed files with 197 additions and 26 deletions

View File

@ -7669,6 +7669,42 @@ BOOST_AUTO_TEST_CASE(pass_function_types_externally)
BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8)));
}
BOOST_AUTO_TEST_CASE(receive_external_function_type)
{
char const* sourceCode = R"(
contract C {
function g() returns (uint) { return 7; }
function f(function() external returns (uint) g) returns (uint) {
return g();
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction(
"f(bytes24)",
FixedHash<4>(dev::keccak256("g()")).asBytes() + m_contractAddress.asBytes() + bytes(32 - 4 - 20, 0)
) == encodeArgs(u256(7)));
}
BOOST_AUTO_TEST_CASE(return_external_function_type)
{
char const* sourceCode = R"(
contract C {
function g() {}
function f() returns (function() external) {
return this.g;
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(
callContractFunction("f()") ==
FixedHash<4>(dev::keccak256("g()")).asBytes() + m_contractAddress.asBytes() + bytes(32 - 4 - 20, 0)
);
}
BOOST_AUTO_TEST_CASE(store_function)
{
char const* sourceCode = R"(
@ -7676,7 +7712,7 @@ BOOST_AUTO_TEST_CASE(store_function)
function addTwo(uint x) returns (uint) { return x + 2; }
}
contract C {
function (function (uint) external returns (uint)) returns (uint) ev = eval;
function (function (uint) external returns (uint)) returns (uint) ev;
function (uint) external returns (uint) x;
function store(function(uint) external returns (uint) y) {
x = y;
@ -7685,6 +7721,7 @@ BOOST_AUTO_TEST_CASE(store_function)
return y(7);
}
function t() returns (uint) {
ev = eval;
this.store((new Other()).addTwo);
return ev(x);
}
@ -7728,15 +7765,15 @@ BOOST_AUTO_TEST_CASE(call_function_returning_function)
function f0() returns (uint) {
return 2;
}
function f1() returns (function() returns (uint)) {
returns f0;
function f1() internal returns (function() returns (uint)) {
return f0;
}
function f2() returns (function() returns (function () returns (uint))) {
returns f1;
function f2() internal returns (function() returns (function () returns (uint))) {
return f1;
}
function f3() returns (function() returns (function () returns (function () returns (uint))))
function f3() internal returns (function() returns (function () returns (function () returns (uint))))
{
returns f2;
return f2;
}
function f() returns (uint) {
function() returns(function() returns(function() returns(function() returns(uint)))) x;
@ -7746,20 +7783,17 @@ BOOST_AUTO_TEST_CASE(call_function_returning_function)
}
)";
compileAndRun(sourceCode, 0, "C");
compileAndRun(sourceCode, 0, "test");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
}
BOOST_AUTO_TEST_CASE(array_of_functions)
BOOST_AUTO_TEST_CASE(mapping_of_functions)
{
char const* sourceCode = R"(
contract Flow {
bool success;
function checkSuccess() returns(bool) {
return success;
}
bool public success;
mapping (address => function () internal returns()) stages;
mapping (address => function () internal) stages;
function stage0() internal {
stages[msg.sender] = stage1;
@ -7773,24 +7807,140 @@ BOOST_AUTO_TEST_CASE(array_of_functions)
success = true;
}
function f () {
if (0 == steps[msg.sender])
function Flow() {
stages[msg.sender] = stage0;
}
function f() {
stages[msg.sender]();
}
}
)";
compileAndRun(sourceCode, 0, "C");
compileAndRun(sourceCode, 0, "Flow");
BOOST_CHECK(callContractFunction("checkSuccess()") == encodeArgs(false));
callContractFunction("f()");
callContractFunction("f()");
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
BOOST_CHECK(callContractFunction("checkSuccess()") == encodeArgs(false));
callContractFunction("f()");
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
BOOST_CHECK(callContractFunction("checkSuccess()") == encodeArgs(true));
}
// TODO: arrays, libraries with external functions
BOOST_AUTO_TEST_CASE(packed_functions)
{
char const* sourceCode = R"(
contract C {
// these should take the same slot
function() returns (uint) a;
function() external returns (uint) b;
uint8 public x;
function set() {
x = 2;
a = g;
b = h;
}
function t1() returns (uint) {
return a();
}
function t2() returns (uint) {
return b();
}
function g() returns (uint) {
return 7;
}
function h() returns (uint) {
return 8;
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("set()") == encodeArgs());
BOOST_CHECK(callContractFunction("t1()") == encodeArgs(u256(7)));
BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(8)));
BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(2)));
}
BOOST_AUTO_TEST_CASE(function_memory_array)
{
char const* sourceCode = R"(
contract C {
function a(uint x) returns (uint) { return x + 1; }
function b(uint x) returns (uint) { return x + 2; }
function c(uint x) returns (uint) { return x + 3; }
function d(uint x) returns (uint) { return x + 5; }
function e(uint x) returns (uint) { return x + 8; }
function test(uint x, uint i) returns (uint) {
function(uint) internal returns (uint)[] arr =
new function(uint) internal returns (uint)[](10);
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
arr[4] = e;
return arr[i](x);
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)) == encodeArgs(u256(11)));
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)) == encodeArgs(u256(12)));
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)) == encodeArgs(u256(13)));
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)) == encodeArgs(u256(15)));
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)) == encodeArgs(u256(18)));
BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)) == encodeArgs());
}
BOOST_AUTO_TEST_CASE(function_delete)
{
char const* sourceCode = R"(
contract C {
function a() returns (uint) { return 7; }
function() internal returns (uint) y;
function set() returns (uint) {
y = a;
return y();
}
funciton d() returns (uint) {
delete y;
return 1;
}
function ca() returns (uint) {
return y();
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("set()") == encodeArgs(u256(7)));
BOOST_CHECK(callContractFunction("ca()") == encodeArgs(u256(7)));
BOOST_CHECK(callContractFunction("d()") == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("ca()") == encodeArgs());
}
BOOST_AUTO_TEST_CASE(copy_function_storage_array)
{
char const* sourceCode = R"(
contract C {
function() internal returns (uint)[] x;
function() internal returns (uint)[] y;
function test() returns (uint) {
x.length = 10;
x[9] = a;
y = x;
return y[9]();
}
function a() returns (uint) {
return 7;
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(7)));
}
BOOST_AUTO_TEST_CASE(shift_constant_left)
{

View File

@ -4227,6 +4227,7 @@ BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_internal
)";
BOOST_CHECK(success(text));
}
BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_external)
{
char const* text = R"(
@ -4238,6 +4239,23 @@ BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_external
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(function_type_arrays)
{
char const* text = R"(
contract C {
function(uint) external returns (uint)[] public x;
function(uint) internal returns (uint)[10] y;
function f() {
function(uint) returns (uint)[10] memory a;
function(uint) returns (uint)[10] storage b = y;
function(uint) external returns (uint)[] memory c;
c = new function(uint) external returns (uint)[](200);
}
}
)";
BOOST_CHECK(success(text));
}
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
{
char const* text = R"(

View File

@ -1325,11 +1325,14 @@ BOOST_AUTO_TEST_CASE(calling_function)
BOOST_CHECK(successParse(text));
}
BOOST_AUTO_TEST_CASE(array_of_functions)
BOOST_AUTO_TEST_CASE(mapping_and_array_of_functions)
{
char const* text = R"(
contract test {
mapping (address => function() internal returns ()) stages;
mapping (address => function() internal returns (uint)) a;
mapping (address => function() external) b;
mapping (address => function() external[]) c;
function() external[] d;
}
)";
BOOST_CHECK(successParse(text));