diff options
Diffstat (limited to 'test/libsolidity')
-rw-r--r-- | test/libsolidity/ASTJSON.cpp | 45 | ||||
-rw-r--r-- | test/libsolidity/Assembly.cpp | 10 | ||||
-rw-r--r-- | test/libsolidity/InlineAssembly.cpp | 23 | ||||
-rw-r--r-- | test/libsolidity/SolidityABIJSON.cpp | 38 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 749 | ||||
-rw-r--r-- | test/libsolidity/SolidityExpressionCompiler.cpp | 37 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 246 | ||||
-rw-r--r-- | test/libsolidity/SolidityNatspecJSON.cpp | 12 | ||||
-rw-r--r-- | test/libsolidity/SolidityOptimizer.cpp | 28 | ||||
-rw-r--r-- | test/libsolidity/SolidityParser.cpp | 111 |
10 files changed, 1204 insertions, 95 deletions
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp index a0fc5dd7..b88218e7 100644 --- a/test/libsolidity/ASTJSON.cpp +++ b/test/libsolidity/ASTJSON.cpp @@ -94,20 +94,6 @@ BOOST_AUTO_TEST_CASE(using_for_directive) BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint"); } -BOOST_AUTO_TEST_CASE(enum_definition) -{ - CompilerStack c; - c.addSource("a", "contract C { enum E {} }"); - c.parse(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); - Json::Value enumDefinition = astJson["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(enumDefinition["name"], "EnumDefinition"); - BOOST_CHECK_EQUAL(enumDefinition["attributes"]["name"], "E"); - BOOST_CHECK_EQUAL(enumDefinition["src"], "13:9:1"); -} - BOOST_AUTO_TEST_CASE(enum_value) { CompilerStack c; @@ -211,6 +197,37 @@ BOOST_AUTO_TEST_CASE(non_utf8) BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos); } +BOOST_AUTO_TEST_CASE(function_type) +{ + CompilerStack c; + c.addSource("a", + "contract C { function f(function() external payable returns (uint) x) " + "returns (function() external constant returns (uint)) {} }" + ); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value fun = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition"); + Json::Value argument = fun["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(argument["name"], "VariableDeclaration"); + BOOST_CHECK_EQUAL(argument["attributes"]["name"], "x"); + BOOST_CHECK_EQUAL(argument["attributes"]["type"], "function () payable external returns (uint256)"); + Json::Value funType = argument["children"][0]; + BOOST_CHECK_EQUAL(funType["attributes"]["constant"], false); + BOOST_CHECK_EQUAL(funType["attributes"]["payable"], true); + BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); + Json::Value retval = fun["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(retval["name"], "VariableDeclaration"); + BOOST_CHECK_EQUAL(retval["attributes"]["name"], ""); + BOOST_CHECK_EQUAL(retval["attributes"]["type"], "function () constant external returns (uint256)"); + funType = retval["children"][0]; + BOOST_CHECK_EQUAL(funType["attributes"]["constant"], true); + BOOST_CHECK_EQUAL(funType["attributes"]["payable"], false); + BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 8d7a3540..e5ce691b 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -91,8 +91,10 @@ void checkAssemblyLocations(AssemblyItems const& _items, vector<SourceLocation> BOOST_CHECK_MESSAGE( _items[i].location() == _locations[i], "Location mismatch for assembly item " + to_string(i) + ". Found: " + + (_items[i].location().sourceName ? *_items[i].location().sourceName + ":" : "(null source name)") + to_string(_items[i].location().start) + "-" + to_string(_items[i].location().end) + ", expected: " + + (_locations[i].sourceName ? *_locations[i].sourceName + ":" : "(null source name)") + to_string(_locations[i].start) + "-" + to_string(_locations[i].end)); } @@ -111,13 +113,13 @@ BOOST_AUTO_TEST_CASE(location_test) } } )"; - shared_ptr<string const> n = make_shared<string>("source"); + shared_ptr<string const> n = make_shared<string>(""); AssemblyItems items = compileContract(sourceCode); vector<SourceLocation> locations = - vector<SourceLocation>(18, SourceLocation(2, 75, n)) + - vector<SourceLocation>(31, SourceLocation(20, 72, n)) + + vector<SourceLocation>(16, SourceLocation(2, 75, n)) + + vector<SourceLocation>(27, SourceLocation(20, 72, n)) + vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} + - vector<SourceLocation>(4, SourceLocation(58, 67, n)) + + vector<SourceLocation>(2, SourceLocation(58, 67, n)) + vector<SourceLocation>(3, SourceLocation(20, 72, n)); checkAssemblyLocations(items, locations); } diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 6c04367f..185a6215 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -41,7 +41,7 @@ namespace test namespace { -bool successParse(std::string const& _source, bool _assemble = false) +bool successParse(std::string const& _source, bool _assemble = false, bool _allowWarnings = true) { assembly::InlineAssemblyStack stack; try @@ -51,8 +51,9 @@ bool successParse(std::string const& _source, bool _assemble = false) if (_assemble) { stack.assemble(); - if (!stack.errors().empty() && !Error::containsOnlyWarnings(stack.errors())) - return false; + if (!stack.errors().empty()) + if (!_allowWarnings || !Error::containsOnlyWarnings(stack.errors())) + return false; } } catch (FatalError const&) @@ -67,9 +68,9 @@ bool successParse(std::string const& _source, bool _assemble = false) return true; } -bool successAssemble(string const& _source) +bool successAssemble(string const& _source, bool _allowWarnings = true) { - return successParse(_source, true); + return successParse(_source, true, _allowWarnings); } } @@ -169,6 +170,18 @@ BOOST_AUTO_TEST_CASE(magic_variables) BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover }")); } +BOOST_AUTO_TEST_CASE(imbalanced_stack) +{ + BOOST_CHECK(successAssemble("{ 1 2 mul pop }", false)); + BOOST_CHECK(!successAssemble("{ 1 }", false)); + BOOST_CHECK(successAssemble("{ let x := 4 7 add }", false)); +} + +BOOST_AUTO_TEST_CASE(error_tag) +{ + BOOST_CHECK(successAssemble("{ invalidJumpLabel }")); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index 073d7d97..a8a39b0b 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -40,14 +40,14 @@ public: void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) { ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing contract failed"); - std::string generatedInterfaceString = m_compilerStack.metadata("", DocumentationType::ABIInterface); - Json::Value generatedInterface; - m_reader.parse(generatedInterfaceString, generatedInterface); + + Json::Value generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface); Json::Value expectedInterface; m_reader.parse(_expectedInterfaceString, expectedInterface); BOOST_CHECK_MESSAGE( expectedInterface == generatedInterface, - "Expected:\n" << expectedInterface.toStyledString() << "\n but got:\n" << generatedInterface.toStyledString() + "Expected:\n" << expectedInterface.toStyledString() << + "\n but got:\n" << generatedInterface.toStyledString() ); } @@ -524,6 +524,7 @@ BOOST_AUTO_TEST_CASE(constructor_abi) "type": "bool" } ], + "payable": false, "type": "constructor" } ])"; @@ -567,6 +568,7 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi) "type": "uint8" } ], + "payable": false, "type": "constructor" } ] @@ -684,7 +686,7 @@ BOOST_AUTO_TEST_CASE(payable_function) checkInterface(sourceCode, interface); } -BOOST_AUTO_TEST_CASE(payable_fallback_unction) +BOOST_AUTO_TEST_CASE(payable_fallback_function) { char const* sourceCode = R"( contract test { @@ -703,6 +705,32 @@ BOOST_AUTO_TEST_CASE(payable_fallback_unction) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(function_type) +{ + char const* sourceCode = R"( + contract test { + function g(function(uint) external returns (uint) x) {} + } + )"; + + char const* interface = R"( + [ + { + "constant" : false, + "payable": false, + "inputs": [{ + "name": "x", + "type": "function" + }], + "name": "g", + "outputs": [], + "type" : "function" + } + ] + )"; + checkInterface(sourceCode, interface); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 8600443d..4abe0894 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -353,6 +353,34 @@ BOOST_AUTO_TEST_CASE(while_loop) testSolidityAgainstCppOnRange("f(uint256)", while_loop_cpp, 0, 5); } + +BOOST_AUTO_TEST_CASE(do_while_loop) +{ + char const* sourceCode = "contract test {\n" + " function f(uint n) returns(uint nfac) {\n" + " nfac = 1;\n" + " var i = 2;\n" + " do { nfac *= i++; } while (i <= n);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + + auto do_while_loop_cpp = [](u256 const& n) -> u256 + { + u256 nfac = 1; + u256 i = 2; + do + { + nfac *= i++; + } + while (i <= n); + + return nfac; + }; + + testSolidityAgainstCppOnRange("f(uint256)", do_while_loop_cpp, 0, 5); +} + BOOST_AUTO_TEST_CASE(nested_loops) { // tests that break and continue statements in nested loops jump to the correct place @@ -1309,6 +1337,7 @@ BOOST_AUTO_TEST_CASE(struct_accessor) BOOST_AUTO_TEST_CASE(balance) { char const* sourceCode = "contract test {\n" + " function test() payable {}\n" " function getBalance() returns (uint256 balance) {\n" " return address(this).balance;\n" " }\n" @@ -1320,6 +1349,7 @@ BOOST_AUTO_TEST_CASE(balance) BOOST_AUTO_TEST_CASE(blockchain) { char const* sourceCode = "contract test {\n" + " function test() payable {}\n" " function someInfo() payable returns (uint256 value, address coinbase, uint256 blockNumber) {\n" " value = msg.value;\n" " coinbase = block.coinbase;\n" @@ -1535,6 +1565,7 @@ BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_greater_size) BOOST_AUTO_TEST_CASE(send_ether) { char const* sourceCode = "contract test {\n" + " function test() payable {}\n" " function a(address addr, uint amount) returns (uint ret) {\n" " addr.send(amount);\n" " return address(this).balance;\n" @@ -1647,6 +1678,7 @@ BOOST_AUTO_TEST_CASE(log_in_constructor) BOOST_AUTO_TEST_CASE(suicide) { char const* sourceCode = "contract test {\n" + " function test() payable {}\n" " function a(address receiver) returns (uint ret) {\n" " suicide(receiver);\n" " return 10;\n" @@ -1663,6 +1695,7 @@ BOOST_AUTO_TEST_CASE(suicide) BOOST_AUTO_TEST_CASE(selfdestruct) { char const* sourceCode = "contract test {\n" + " function test() payable {}\n" " function a(address receiver) returns (uint ret) {\n" " selfdestruct(receiver);\n" " return 10;\n" @@ -2928,24 +2961,24 @@ BOOST_AUTO_TEST_CASE(generic_call) BOOST_AUTO_TEST_CASE(generic_callcode) { char const* sourceCode = R"**( - contract receiver { + contract Receiver { uint public received; function receive(uint256 x) payable { received = x; } } - contract sender { + contract Sender { uint public received; - function sender() payable { } + function Sender() payable { } function doSend(address rec) returns (uint d) { bytes4 signature = bytes4(bytes32(sha3("receive(uint256)"))); rec.callcode.value(2)(signature, 23); - return receiver(rec).received(); + return Receiver(rec).received(); } } )**"; - compileAndRun(sourceCode, 0, "receiver"); + compileAndRun(sourceCode, 0, "Receiver"); u160 const c_receiverAddress = m_contractAddress; - compileAndRun(sourceCode, 50, "sender"); + compileAndRun(sourceCode, 50, "Sender"); u160 const c_senderAddress = m_contractAddress; BOOST_CHECK(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(0)); BOOST_CHECK(callContractFunction("received()") == encodeArgs(23)); @@ -2960,16 +2993,18 @@ BOOST_AUTO_TEST_CASE(generic_callcode) BOOST_AUTO_TEST_CASE(generic_delegatecall) { char const* sourceCode = R"**( - contract receiver { + contract Receiver { uint public received; address public sender; uint public value; + function Receiver() payable {} function receive(uint256 x) payable { received = x; sender = msg.sender; value = msg.value; } } - contract sender { + contract Sender { uint public received; address public sender; uint public value; + function Sender() payable {} function doSend(address rec) payable { bytes4 signature = bytes4(bytes32(sha3("receive(uint256)"))); @@ -2977,9 +3012,9 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall) } } )**"; - compileAndRun(sourceCode, 0, "receiver"); + compileAndRun(sourceCode, 0, "Receiver"); u160 const c_receiverAddress = m_contractAddress; - compileAndRun(sourceCode, 50, "sender"); + compileAndRun(sourceCode, 50, "Sender"); u160 const c_senderAddress = m_contractAddress; BOOST_CHECK(m_sender != c_senderAddress); // just for sanity BOOST_CHECK(callContractFunctionWithValue("doSend(address)", 11, c_receiverAddress) == encodeArgs()); @@ -3314,6 +3349,42 @@ BOOST_AUTO_TEST_CASE(using_enums) BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2)); } +BOOST_AUTO_TEST_CASE(enum_explicit_overflow) +{ + char const* sourceCode = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight } + function test() + { + } + function getChoiceExp(uint x) returns (uint d) + { + choice = ActionChoices(x); + d = uint256(choice); + } + function getChoiceFromSigned(int x) returns (uint d) + { + choice = ActionChoices(x); + d = uint256(choice); + } + function getChoiceFromNegativeLiteral() returns (uint d) + { + choice = ActionChoices(-1); + d = uint256(choice); + } + ActionChoices choice; + } + )"; + compileAndRun(sourceCode); + // These should throw + BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 3) == encodeArgs()); + BOOST_CHECK(callContractFunction("getChoiceFromSigned(int256)", -1) == encodeArgs()); + BOOST_CHECK(callContractFunction("getChoiceFromNegativeLiteral()") == encodeArgs()); + // These should work + BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 2) == encodeArgs(2)); + BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 0) == encodeArgs(0)); +} + BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name) { char const* sourceCode = R"( @@ -4435,6 +4506,67 @@ BOOST_AUTO_TEST_CASE(external_types_in_calls) BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(9))); } +BOOST_AUTO_TEST_CASE(invalid_enum_as_external_ret) +{ + char const* sourceCode = R"( + contract C { + enum X { A, B } + + function test_return() returns (X) { + X garbled; + assembly { + garbled := 5 + } + return garbled; + } + function test_inline_assignment() returns (X _ret) { + assembly { + _ret := 5 + } + } + function test_assignment() returns (X _ret) { + X tmp; + assembly { + tmp := 5 + } + _ret = tmp; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + // both should throw + BOOST_CHECK(callContractFunction("test_return()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test_inline_assignment()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test_assignment()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg) +{ + char const* sourceCode = R"( + contract C { + enum X { A, B } + + function tested (X x) returns (uint) { + return 1; + } + + function test() returns (uint) { + X garbled; + + assembly { + garbled := 5 + } + + return this.tested(garbled); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + // should throw + BOOST_CHECK(callContractFunction("test()") == encodeArgs()); +} + + BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes) { // bug #1798 @@ -4693,6 +4825,7 @@ BOOST_AUTO_TEST_CASE(failing_send) } } contract Main { + function Main() payable {} function callHelper(address _a) returns (bool r, uint bal) { r = !_a.send(5); bal = this.balance; @@ -4715,6 +4848,7 @@ BOOST_AUTO_TEST_CASE(send_zero_ether) } } contract Main { + function Main() payable {} function s() returns (bool) { var r = new Receiver(); return r.send(0); @@ -6216,6 +6350,7 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) char const* sourceCode = R"( library lib {} contract c { + function c() payable {} function f(address x) returns (bool) { return x.send(1); } @@ -6325,6 +6460,20 @@ BOOST_AUTO_TEST_CASE(decayed_tuple) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2))); } +BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers) +{ + char const* sourceCode = R"( + contract c { + function f() returns (int8) { + int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; + return foo3[0]; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1))); +} + BOOST_AUTO_TEST_CASE(destructuring_assignment) { char const* sourceCode = R"( @@ -7140,6 +7289,7 @@ BOOST_AUTO_TEST_CASE(failed_create) contract D { function D() payable {} } contract C { uint public x; + function C() payable {} function f(uint amount) returns (address) { x++; return (new D).value(amount)(); @@ -7253,7 +7403,7 @@ BOOST_AUTO_TEST_CASE(mutex) } contract Fund is mutexed { uint shares; - function Fund() { shares = msg.value; } + function Fund() payable { shares = msg.value; } function withdraw(uint amount) protected returns (uint) { // NOTE: It is very bad practice to write this function this way. // Please refer to the documentation of how to do this properly. @@ -7467,6 +7617,568 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7))); } +BOOST_AUTO_TEST_CASE(calling_uninitialized_function) +{ + char const* sourceCode = R"( + contract C { + function intern() returns (uint) { + function (uint) internal returns (uint) x; + x(2); + return 7; + } + function extern() returns (uint) { + function (uint) external returns (uint) x; + x(2); + return 7; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + // This should throw exceptions + BOOST_CHECK(callContractFunction("intern()") == encodeArgs()); + BOOST_CHECK(callContractFunction("extern()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail) +{ + char const* sourceCode = R"( + contract C { + function() internal returns (uint) x; + int mutex; + function t() returns (uint) { + if (mutex > 0) + return 7; + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + x(); + return 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(pass_function_types_internally) +{ + char const* sourceCode = R"( + contract C { + function f(uint x) returns (uint) { + return eval(g, x); + } + function eval(function(uint) returns (uint) x, uint a) internal returns (uint) { + return x(a); + } + function g(uint x) returns (uint) { return x + 1; } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8))); +} + +BOOST_AUTO_TEST_CASE(pass_function_types_externally) +{ + char const* sourceCode = R"( + contract C { + function f(uint x) returns (uint) { + return this.eval(this.g, x); + } + function f2(uint x) returns (uint) { + return eval(this.g, x); + } + function eval(function(uint) external returns (uint) x, uint a) returns (uint) { + return x(a); + } + function g(uint x) returns (uint) { return x + 1; } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8))); + 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(function)", + m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).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()") == + m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) + ); +} + +BOOST_AUTO_TEST_CASE(store_function) +{ + char const* sourceCode = R"( + contract Other { + function addTwo(uint x) returns (uint) { return x + 2; } + } + contract C { + 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; + } + function eval(function(uint) external returns (uint) y) returns (uint) { + return y(7); + } + function t() returns (uint) { + ev = eval; + this.store((new Other()).addTwo); + return ev(x); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9))); +} + +BOOST_AUTO_TEST_CASE(store_function_in_constructor) +{ + char const* sourceCode = R"( + contract C { + uint public result_in_constructor; + function (uint) internal returns (uint) x; + function C () { + x = double; + result_in_constructor = use(2); + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + function use(uint _arg) returns (uint) { + return x(_arg); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6))); + BOOST_CHECK(callContractFunction("result_in_constructor()") == encodeArgs(u256(4))); +} + +// TODO: store bound internal library functions + +BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor) +{ + char const* sourceCode = R"( + contract C { + function () internal returns (uint) x; + function C () { + x = unused; + } + function unused() internal returns (uint) { + return 7; + } + function t() returns (uint) { + return x(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor) +{ + char const* sourceCode = R"( + library L { function x() internal returns (uint) { return 7; } } + contract C { + function () internal returns (uint) x; + function C () { + x = L.x; + } + function t() returns (uint) { + return x(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime) +{ + char const* sourceCode = R"( + contract C { + uint public initial; + function C() { + initial = double(2); + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + function runtime(uint _arg) returns (uint) { + return double(_arg); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6))); + BOOST_CHECK(callContractFunction("initial()") == encodeArgs(u256(4))); +} + +BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check) +{ + char const* sourceCode = R"( + contract C { + function (uint) internal returns (uint) x; + function C() { + x = double; + } + function test() returns (bool) { + return x == double; + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(function_type_library_internal) +{ + char const* sourceCode = R"( + library Utils { + function reduce(uint[] memory array, function(uint, uint) returns (uint) f, uint init) internal returns (uint) { + for (uint i = 0; i < array.length; i++) { + init = f(array[i], init); + } + return init; + } + function sum(uint a, uint b) internal returns (uint) { + return a + b; + } + } + contract C { + function f(uint[] x) returns (uint) { + return Utils.reduce(x, Utils.sum, 0); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)) == encodeArgs(u256(11))); +} + + +BOOST_AUTO_TEST_CASE(call_function_returning_function) +{ + char const* sourceCode = R"( + contract test { + function f0() returns (uint) { + return 2; + } + function f1() internal returns (function() returns (uint)) { + return f0; + } + function f2() internal returns (function() returns (function () returns (uint))) { + return f1; + } + function f3() internal returns (function() returns (function () returns (function () returns (uint)))) + { + return f2; + } + function f() returns (uint) { + function() returns(function() returns(function() returns(function() returns(uint)))) x; + x = f3; + return x()()()(); + } + } + )"; + + compileAndRun(sourceCode, 0, "test"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2))); +} + +BOOST_AUTO_TEST_CASE(mapping_of_functions) +{ + char const* sourceCode = R"( + contract Flow { + bool public success; + + mapping (address => function () internal) stages; + + function stage0() internal { + stages[msg.sender] = stage1; + } + + function stage1() internal { + stages[msg.sender] = stage2; + } + + function stage2() internal { + success = true; + } + + function Flow() { + stages[msg.sender] = stage0; + } + + function f() returns (uint) { + stages[msg.sender](); + return 7; + } + } + )"; + + compileAndRun(sourceCode, 0, "Flow"); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(true)); +} + +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; + function() external returns (uint) c; + function() returns (uint) d; + uint8 public x; + + function set() { + x = 2; + d = g; + c = this.h; + b = this.h; + a = g; + } + function t1() returns (uint) { + return a(); + } + function t2() returns (uint) { + return b(); + } + function t3() returns (uint) { + return a(); + } + function t4() 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("t3()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("t4()") == 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)[] memory 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_storage) +{ + 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(); + } + function 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(function_delete_stack) +{ + char const* sourceCode = R"( + contract C { + function a() returns (uint) { return 7; } + function test() returns (uint) { + var y = a; + delete y; + y(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == 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(function_array_cross_calls) +{ + char const* sourceCode = R"( + contract D { + function f(function() external returns (function() external returns (uint))[] x) + returns (function() external returns (uint)[3] r) + { + r[0] = x[0](); + r[1] = x[1](); + r[2] = x[2](); + } + } + contract C { + function test() returns (uint, uint, uint) { + function() external returns (function() external returns (uint))[] memory x = + new function() external returns (function() external returns (uint))[](10); + for (uint i = 0; i < x.length; i ++) + x[i] = this.h; + x[0] = this.htwo; + var y = (new D()).f(x); + return (y[0](), y[1](), y[2]()); + } + function e() returns (uint) { return 5; } + function f() returns (uint) { return 6; } + function g() returns (uint) { return 7; } + uint counter; + function h() returns (function() external returns (uint)) { + return counter++ == 0 ? this.f : this.g; + } + function htwo() returns (function() external returns (uint)) { + return this.e; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(5), u256(6), u256(7))); +} + +BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage) +{ + char const* sourceCode = R"( + contract C { + function() internal returns (uint)[20] x; + int mutex; + function one() returns (uint) { + function() internal returns (uint)[20] xmem; + x = xmem; + return 3; + } + function two() returns (uint) { + if (mutex > 0) + return 7; + mutex = 1; + // If this test fails, it might re-execute this function. + x[0](); + return 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("one()") == encodeArgs(u256(3))); + BOOST_CHECK(callContractFunction("two()") == encodeArgs()); +} + BOOST_AUTO_TEST_CASE(shift_constant_left) { char const* sourceCode = R"( @@ -7553,6 +8265,21 @@ BOOST_AUTO_TEST_CASE(packed_storage_overflow) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe))); } +BOOST_AUTO_TEST_CASE(inline_assembly_invalidjumplabel) +{ + char const* sourceCode = R"( + contract C { + function f() { + assembly { + jump(invalidJumpLabel) + } + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs()); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index e9a05745..91edfefd 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -325,12 +325,12 @@ BOOST_AUTO_TEST_CASE(arithmetics) byte(Instruction::ADD), byte(Instruction::DUP2), byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x0, byte(Instruction::JUMPI), byte(Instruction::MOD), byte(Instruction::DUP2), byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x2, + byte(Instruction::PUSH1), 0x0, byte(Instruction::JUMPI), byte(Instruction::DIV), byte(Instruction::MUL)}); @@ -425,39 +425,6 @@ BOOST_AUTO_TEST_CASE(assignment) BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } -BOOST_AUTO_TEST_CASE(function_call) -{ - char const* sourceCode = "contract test {\n" - " function f(uint a, uint b) { a += g(a + 1, b) * 2; }\n" - " function g(uint a, uint b) returns (uint c) {}\n" - "}\n"; - bytes code = compileFirstExpression(sourceCode, {{"test", "g"}}, - {{"test", "f", "a"}, {"test", "f", "b"}}); - - // Stack: a, b - bytes expectation({byte(Instruction::PUSH1), 0x02, - byte(Instruction::PUSH1), 0x0c, - byte(Instruction::PUSH1), 0x01, - byte(Instruction::DUP5), - byte(Instruction::ADD), - // Stack here: a b 2 <ret label> (a+1) - byte(Instruction::DUP4), - byte(Instruction::PUSH1), 0x13, - byte(Instruction::JUMP), - byte(Instruction::JUMPDEST), - // Stack here: a b 2 g(a+1, b) - byte(Instruction::MUL), - // Stack here: a b g(a+1, b)*2 - byte(Instruction::DUP3), - byte(Instruction::ADD), - // Stack here: a b a+g(a+1, b)*2 - byte(Instruction::SWAP2), - byte(Instruction::POP), - byte(Instruction::DUP2), - byte(Instruction::JUMPDEST)}); - BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); -} - BOOST_AUTO_TEST_CASE(negative_literals_8bits) { char const* sourceCode = "contract test {\n" diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 640cc108..865eb7ce 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -57,7 +57,7 @@ parseAnalyseAndReturnError(string const& _source, bool _reportWarnings = false, { sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(source))); if(!sourceUnit) - return make_pair(sourceUnit, nullptr); + BOOST_FAIL("Parsing failed in type checker test."); SyntaxChecker syntaxChecker(errors); if (!syntaxChecker.checkSyntax(*sourceUnit)) @@ -1535,6 +1535,21 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) BOOST_CHECK(expectError(text) == Error::Type::TypeError); } +BOOST_AUTO_TEST_CASE(enum_to_enum_conversion_is_not_okay) +{ + char const* text = R"( + contract test { + enum Paper { Up, Down, Left, Right } + enum Ground { North, South, West, East } + function test() + { + Ground(Paper.Up); + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + BOOST_AUTO_TEST_CASE(enum_duplicate_values) { char const* text = R"( @@ -4015,8 +4030,8 @@ BOOST_AUTO_TEST_CASE(calling_payable) char const* text = R"( contract receiver { function pay() payable {} } contract test { - funciton f() { (new receiver()).pay.value(10)(); } - recevier r = new receiver(); + function f() { (new receiver()).pay.value(10)(); } + receiver r = new receiver(); function g() { r.pay.value(10)(); } } )"; @@ -4117,6 +4132,231 @@ BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype) BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); } +BOOST_AUTO_TEST_CASE(function_type) +{ + char const* text = R"( + contract C { + function f() { + function(uint) returns (uint) x; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_parameter) +{ + char const* text = R"( + contract C { + function f(function(uint) external returns (uint) g) returns (function(uint) external returns (uint)) { + return g; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_returned) +{ + char const* text = R"( + contract C { + function f() returns (function(uint) external returns (uint) g) { + return g; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(private_function_type) +{ + char const* text = R"( + contract C { + function f() { + function(uint) private returns (uint) x; + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(public_function_type) +{ + char const* text = R"( + contract C { + function f() { + function(uint) public returns (uint) x; + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(payable_internal_function_type) +{ + char const* text = R"( + contract C { + function (uint) internal payable returns (uint) x; + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(call_value_on_non_payable_function_type) +{ + char const* text = R"( + contract C { + function (uint) external returns (uint) x; + function f() { + x.value(2)(); + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(external_function_type_returning_internal) +{ + char const* text = R"( + contract C { + function() external returns (function () internal) x; + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(external_function_type_taking_internal) +{ + char const* text = R"( + contract C { + function(function () internal) external x; + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(call_value_on_payable_function_type) +{ + char const* text = R"( + contract C { + function (uint) external payable returns (uint) x; + function f() { + x.value(2)(1); + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter) +{ + // It should not be possible to give internal functions + // as parameters to external functions. + char const* text = R"( + contract C { + function f(function(uint) internal returns (uint) x) { + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(internal_function_returned_from_public_function) +{ + // It should not be possible to return internal functions from external functions. + char const* text = R"( + contract C { + function f() returns (function(uint) internal returns (uint) x) { + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_internal) +{ + char const* text = R"( + library L { + function f(function(uint) internal returns (uint) x) internal { + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(internal_function_as_external_parameter_in_library_external) +{ + char const* text = R"( + library L { + function f(function(uint) internal returns (uint) x) { + } + } + )"; + 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(delete_function_type) +{ + char const* text = R"( + contract C { + function(uint) external returns (uint) x; + function(uint) internal returns (uint) y; + function f() { + delete x; + var a = y; + delete a; + delete y; + var c = f; + delete c; + function(uint) internal returns (uint) g; + delete g; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(delete_function_type_invalid) +{ + char const* text = R"( + contract C { + function f() { + delete f; + } + } + )"; + BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(delete_external_function_type_invalid) +{ + char const* text = R"( + contract C { + function f() { + delete this.f; + } + } + )"; + BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); +} + BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal) { char const* text = R"( diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 1f74e928..49844f15 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -45,21 +45,19 @@ public: bool _userDocumentation ) { - std::string generatedDocumentationString; ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing failed"); + Json::Value generatedDocumentation; if (_userDocumentation) - generatedDocumentationString = m_compilerStack.metadata("", DocumentationType::NatspecUser); + generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecUser); else - generatedDocumentationString = m_compilerStack.metadata("", DocumentationType::NatspecDev); - Json::Value generatedDocumentation; - m_reader.parse(generatedDocumentationString, generatedDocumentation); + generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecDev); Json::Value expectedDocumentation; m_reader.parse(_expectedDocumentationString, expectedDocumentation); BOOST_CHECK_MESSAGE( expectedDocumentation == generatedDocumentation, - "Expected " << _expectedDocumentationString << - "\n but got:\n" << generatedDocumentationString + "Expected " << expectedDocumentation.toStyledString() << + "\n but got:\n" << generatedDocumentation.toStyledString() ); } diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 562b7859..4991cf24 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -365,16 +365,6 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions) // BOOST_CHECK_EQUAL(2, numSHA3s); } -BOOST_AUTO_TEST_CASE(successor_not_found_bug) -{ - // This bug was caused because MSVC chose to use the u256->bool conversion - // instead of u256->unsigned - char const* sourceCode = R"( - contract greeter { function greeter() {} } - )"; - compileBothVersions(sourceCode); -} - BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug) { // This bug appeared because a sha3 operation with too low sequence number was used, @@ -1238,6 +1228,24 @@ BOOST_AUTO_TEST_CASE(inconsistency) compareVersions("trigger()"); } +BOOST_AUTO_TEST_CASE(dead_code_elimination_across_assemblies) +{ + // This tests that a runtime-function that is stored in storage in the constructor + // is not removed as part of dead code elimination. + char const* sourceCode = R"( + contract DCE { + function () internal returns (uint) stored; + function DCE() { + stored = f; + } + function f() internal returns (uint) { return 7; } + function test() returns (uint) { return stored(); } + } + )"; + compileBothVersions(sourceCode); + compareVersions("test()"); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index a81a9828..914dbc30 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -824,7 +824,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration) contract c { enum foo { } })"; - BOOST_CHECK(successParse(text)); + BOOST_CHECK(!successParse(text)); } BOOST_AUTO_TEST_CASE(malformed_enum_declaration) @@ -1241,6 +1241,115 @@ BOOST_AUTO_TEST_CASE(payable_accessor) BOOST_CHECK(!successParse(text)); } +BOOST_AUTO_TEST_CASE(function_type_in_expression) +{ + char const* text = R"( + contract test { + function f(uint x, uint y) returns (uint a) {} + function g() { + function (uint, uint) internal returns (uint) f1 = f; + } + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_as_storage_variable) +{ + char const* text = R"( + contract test { + function (uint, uint) internal returns (uint) f1; + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_modifiers) +{ + char const* text = R"( + contract test { + function (uint, uint) modifier1() returns (uint) f1; + } + )"; + BOOST_CHECK(!successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_assignment) +{ + char const* text = R"( + contract test { + function f(uint x, uint y) returns (uint a) {} + function (uint, uint) internal returns (uint) f1 = f; + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_in_struct) +{ + char const* text = R"( + contract test { + struct S { + function (uint x, uint y) internal returns (uint a) f; + function (uint, uint) external returns (uint) g; + uint d; + } + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_as_parameter) +{ + char const* text = R"( + contract test { + function f(function(uint) external returns (uint) g) internal returns (uint a) { + return g(1); + } + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(calling_function) +{ + char const* text = R"( + contract test { + function f() { + function() returns(function() returns(function() returns(function() returns(uint)))) x; + uint y; + y = x()()()(); + } + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(mapping_and_array_of_functions) +{ + char const* text = R"( + contract test { + mapping (address => function() internal returns (uint)) a; + mapping (address => function() external) b; + mapping (address => function() external[]) c; + function() external[] d; + } + )"; + BOOST_CHECK(successParse(text)); +} + +BOOST_AUTO_TEST_CASE(function_type_state_variable) +{ + char const* text = R"( + contract test { + function() x; + function() y = x; + } + )"; + BOOST_CHECK(successParse(text)); +} + + BOOST_AUTO_TEST_SUITE_END() } |