diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 788c388e4..352ee2148 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -41,7 +42,7 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes const& compileAndRun(std::string const& _sourceCode) + bytes const& compileAndRun(string const& _sourceCode) { bytes code = dev::solidity::CompilerStack::compile(_sourceCode); sendMessage(code, true); @@ -49,28 +50,64 @@ public: return m_output; } - bytes const& callFunction(byte _index, bytes const& _data) + bytes const& callContractFunction(byte _index, bytes const& _data = bytes()) { sendMessage(bytes(1, _index) + _data, false); return m_output; } - bytes const& callFunction(byte _index, u256 const& _argument1) + template + bytes const& callContractFunction(byte _index, Args const&... _arguments) { - return callFunction(_index, toBigEndian(_argument1)); + return callContractFunction(_index, argsToBigEndian(_arguments...)); } - bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun, u256 const& _argument1) + template + void testSolidityAgainstCpp(byte _index, CppFunction const& _cppFunction, Args const&... _arguments) { - return toBigEndian(_cppfun(_argument1)) == callFunction(_index, toBigEndian(_argument1)); + bytes solidityResult = callContractFunction(_index, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." + "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); } - bool testSolidityAgainstCpp(byte _index, std::function const& _cppfun) + template + void testSolidityAgainstCppOnRange(byte _index, CppFunction const& _cppFunction, + u256 const& _rangeStart, u256 const& _rangeEnd) { - return toBigEndian(_cppfun()) == callFunction(_index, bytes()); + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_index, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." + "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) + + "\nArgument: " + toHex(toBigEndian(argument))); + } } private: + template + bytes argsToBigEndian(FirstArg const& _firstArg, Args const&... _followingArgs) const + { + return toBigEndian(_firstArg) + argsToBigEndian(_followingArgs...); + } + + bytes argsToBigEndian() const { return bytes(); } + + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename enable_if::value, bytes>::type + { + return toBigEndian(_cppFunction(_arguments...)); + } + void sendMessage(bytes const& _data, bool _isCreation) { eth::Executive executive(m_state); @@ -91,7 +128,10 @@ private: BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); } else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); + } BOOST_REQUIRE(executive.go()); executive.finalize(); m_output = executive.out().toVector(); @@ -112,8 +152,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) " function f(uint a) returns(uint d) { return a * 7; }\n" "}\n"; compileAndRun(sourceCode); - u256 a = 0x200030004; - BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7)); + testSolidityAgainstCppOnRange(0, [](u256 const& a) -> u256 { return a * 7; }, 0, 100); } BOOST_AUTO_TEST_CASE(empty_contract) @@ -121,7 +160,7 @@ BOOST_AUTO_TEST_CASE(empty_contract) char const* sourceCode = "contract test {\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes()).empty()); + BOOST_CHECK(callContractFunction(0, bytes()).empty()); } BOOST_AUTO_TEST_CASE(recursive_calls) @@ -133,7 +172,7 @@ BOOST_AUTO_TEST_CASE(recursive_calls) " }\n" "}\n"; compileAndRun(sourceCode); - std::function recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 + function recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 { if (n <= 1) return 1; @@ -141,11 +180,7 @@ BOOST_AUTO_TEST_CASE(recursive_calls) return n * recursive_calls_cpp(n - 1); }; - BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(0))); - BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(1))); - BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(2))); - BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(3))); - BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(4))); + testSolidityAgainstCppOnRange(0, recursive_calls_cpp, 0, 5); } BOOST_AUTO_TEST_CASE(multiple_functions) @@ -185,11 +220,7 @@ BOOST_AUTO_TEST_CASE(while_loop) return nfac; }; - BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(0))); - BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(1))); - BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(2))); - BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(3))); - BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(4))); + testSolidityAgainstCppOnRange(0, while_loop_cpp, 0, 5); } BOOST_AUTO_TEST_CASE(break_outside_loop) @@ -200,9 +231,8 @@ BOOST_AUTO_TEST_CASE(break_outside_loop) " break; continue; return 2;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(2))); + compileAndRun(sourceCode); + testSolidityAgainstCpp(0, [](u256 const& _a) -> u256 { return 2; }, u256(0)); } BOOST_AUTO_TEST_CASE(nested_loops) @@ -225,8 +255,7 @@ BOOST_AUTO_TEST_CASE(nested_loops) " return x;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); + compileAndRun(sourceCode); auto nested_loops_cpp = [](u256 n) -> u256 { @@ -252,18 +281,7 @@ BOOST_AUTO_TEST_CASE(nested_loops) return n; }; - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(0))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(1))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(2))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(3))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(4))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(5))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(6))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(7))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(8))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(9))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(10))); - BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(11))); + testSolidityAgainstCppOnRange(0, nested_loops_cpp, 0, 12); } BOOST_AUTO_TEST_CASE(calling_other_functions) @@ -295,7 +313,8 @@ BOOST_AUTO_TEST_CASE(calling_other_functions) return 3 * n + 1; }; - auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp] (u256 n) -> u256 { + auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp](u256 n) -> u256 + { u256 y; while ((y = n) > 1) { @@ -307,11 +326,11 @@ BOOST_AUTO_TEST_CASE(calling_other_functions) return y; }; - BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(0))); - BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(1))); - BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(2))); - BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(8))); - BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(127))); + testSolidityAgainstCpp(2, collatz_cpp, u256(0)); + testSolidityAgainstCpp(2, collatz_cpp, u256(1)); + testSolidityAgainstCpp(2, collatz_cpp, u256(2)); + testSolidityAgainstCpp(2, collatz_cpp, u256(8)); + testSolidityAgainstCpp(2, collatz_cpp, u256(127)); } BOOST_AUTO_TEST_CASE(many_local_variables) @@ -324,8 +343,15 @@ BOOST_AUTO_TEST_CASE(many_local_variables) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) - == toBigEndian(u256(0x121121))); + auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256 + { + u256 a = 0x1; + u256 b = 0x10; + u256 c = 0x100; + u256 y = a + b + c + x1 + x2 + x3; + return y + b + x2; + }; + testSolidityAgainstCpp(0, f, u256(0x1000), u256(0x10000), u256(0x100000)); } BOOST_AUTO_TEST_CASE(packing_unpacking_types) @@ -338,7 +364,7 @@ BOOST_AUTO_TEST_CASE(packing_unpacking_types) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + BOOST_CHECK(callContractFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); } @@ -350,7 +376,7 @@ BOOST_AUTO_TEST_CASE(multiple_return_values) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) + BOOST_CHECK(callContractFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); } @@ -370,8 +396,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting) return n; }; - BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(0))); - BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(1))); + testSolidityAgainstCppOnRange(0, short_circuiting_cpp, 0, 2); } BOOST_AUTO_TEST_CASE(high_bits_cleaning) @@ -391,7 +416,7 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning) return 0; return x; }; - BOOST_CHECK(testSolidityAgainstCpp(0, high_bits_cleaning_cpp)); + testSolidityAgainstCpp(0, high_bits_cleaning_cpp); } BOOST_AUTO_TEST_CASE(sign_extension) @@ -411,7 +436,7 @@ BOOST_AUTO_TEST_CASE(sign_extension) return 0; return u256(x) * -1; }; - BOOST_CHECK(testSolidityAgainstCpp(0, sign_extension_cpp)); + testSolidityAgainstCpp(0, sign_extension_cpp); } BOOST_AUTO_TEST_CASE(small_unsigned_types) @@ -428,7 +453,7 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types) uint32_t x = uint32_t(0xffffff) * 0xffffff; return x / 0x100; }; - BOOST_CHECK(testSolidityAgainstCpp(0, small_unsigned_types_cpp)); + testSolidityAgainstCpp(0, small_unsigned_types_cpp); } BOOST_AUTO_TEST_CASE(small_signed_types) @@ -443,7 +468,7 @@ BOOST_AUTO_TEST_CASE(small_signed_types) { return -int32_t(10) * -int64_t(20); }; - BOOST_CHECK(testSolidityAgainstCpp(0, small_signed_types_cpp)); + testSolidityAgainstCpp(0, small_signed_types_cpp); } BOOST_AUTO_TEST_CASE(state_smoke_test) @@ -461,14 +486,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); - BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); - BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); - BOOST_CHECK(callFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); - BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); - BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); - BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); - BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); + BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); + BOOST_CHECK(callContractFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); + BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); } BOOST_AUTO_TEST_SUITE_END()