diff options
author | chriseth <chris@ethereum.org> | 2017-08-07 18:52:40 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2017-08-10 21:49:02 +0800 |
commit | 95acbc7a9f03eecf837d87eb72f115c1b1650487 (patch) | |
tree | e50b229fd7c182343b51a4f62700ed024ba4a209 | |
parent | 279e64ae75c5615ca3fc7570a3d533270e43caac (diff) | |
download | dexon-solidity-95acbc7a9f03eecf837d87eb72f115c1b1650487.tar.gz dexon-solidity-95acbc7a9f03eecf837d87eb72f115c1b1650487.tar.zst dexon-solidity-95acbc7a9f03eecf837d87eb72f115c1b1650487.zip |
Some more ABI tests.
-rw-r--r-- | test/boostTest.cpp | 1 | ||||
-rw-r--r-- | test/libsolidity/ABIEncoderTests.cpp | 259 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 94 |
3 files changed, 354 insertions, 0 deletions
diff --git a/test/boostTest.cpp b/test/boostTest.cpp index c2121940..d8c5b678 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -46,6 +46,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) if (dev::test::Options::get().disableIPC) { for (auto suite: { + "ABIEncoderTest", "SolidityAuctionRegistrar", "SolidityFixedFeeRegistrar", "SolidityWallet", diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp new file mode 100644 index 00000000..44c673c5 --- /dev/null +++ b/test/libsolidity/ABIEncoderTests.cpp @@ -0,0 +1,259 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * Unit tests for Solidity's ABI encoder. + */ + +#include <functional> +#include <string> +#include <tuple> +#include <boost/test/unit_test.hpp> +#include <libsolidity/interface/Exceptions.h> +#include <test/libsolidity/SolidityExecutionFramework.h> + +using namespace std; +using namespace std::placeholders; +using namespace dev::test; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +#define REQUIRE_LOG_DATA(DATA) do { \ + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); \ + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); \ + BOOST_CHECK_EQUAL(toHex(m_logs[0].data), toHex(DATA)); \ +} while (false) + +BOOST_FIXTURE_TEST_SUITE(ABIEncoderTest, SolidityExecutionFramework) + +BOOST_AUTO_TEST_CASE(value_types) +{ + char const* sourceCode = R"( + contract C { + event E(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool, C); + function f() { + bytes6 x = hex"1bababababa2"; + bool b; + assembly { b := 7 } + C c; + assembly { c := sub(0, 5) } + E(10, uint16(uint256(-2)), uint24(0x12121212), int24(int256(-1)), bytes3(x), b, c); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs( + 10, u256(65534), u256(0x121212), u256(-1), string("\x1b\xab\xab"), true, u160(u256(-5)) + )); +} + +BOOST_AUTO_TEST_CASE(string_literal) +{ + char const* sourceCode = R"( + contract C { + event E(string, bytes20, string); + function f() { + E("abcdef", "abcde", "abcdefabcdefgehabcabcasdfjklabcdefabcedefghabcabcasdfjklabcdefabcdefghabcabcasdfjklabcdeefabcdefghabcabcasdefjklabcdefabcdefghabcabcasdfjkl"); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs( + 0x60, string("abcde"), 0xa0, + 6, string("abcdef"), + 0x8b, string("abcdefabcdefgehabcabcasdfjklabcdefabcedefghabcabcasdfjklabcdefabcdefghabcabcasdfjklabcdeefabcdefghabcabcasdefjklabcdefabcdefghabcabcasdfjkl") + )); +} + + +BOOST_AUTO_TEST_CASE(enum_type_cleanup) +{ + char const* sourceCode = R"( + contract C { + enum E { A, B } + function f(uint x) returns (E en) { + assembly { en := x } + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f(uint256)", 0) == encodeArgs(0)); + BOOST_CHECK(callContractFunction("f(uint256)", 1) == encodeArgs(1)); + BOOST_CHECK(callContractFunction("f(uint256)", 2) == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(conversion) +{ + char const* sourceCode = R"( + contract C { + event E(bytes4, bytes4, uint16, uint8, int16, int8); + function f() { + bytes2 x; assembly { x := 0xf1f2f3f400000000000000000000000000000000000000000000000000000000 } + uint8 a; + uint16 b = 0x1ff; + int8 c; + int16 d; + assembly { a := sub(0, 1) c := 0x0101ff d := 0xff01 } + E(10, x, a, uint8(b), c, int8(d)); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs( + string(3, 0) + string("\x0a"), string("\xf1\xf2"), + 0xff, 0xff, u256(-1), u256(1) + )); +} + +BOOST_AUTO_TEST_CASE(storage_byte_array) +{ + char const* sourceCode = R"( + contract C { + bytes short; + bytes long; + event E(bytes s, bytes l); + function f() { + short = "123456789012345678901234567890a"; + long = "ffff123456789012345678901234567890afffffffff123456789012345678901234567890a"; + E(short, long); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs( + 0x40, 0x80, + 31, string("123456789012345678901234567890a"), + 75, string("ffff123456789012345678901234567890afffffffff123456789012345678901234567890a") + )); +} + +BOOST_AUTO_TEST_CASE(storage_array) +{ + char const* sourceCode = R"( + contract C { + address[3] addr; + event E(address[3] a); + function f() { + assembly { + sstore(0, sub(0, 1)) + sstore(1, sub(0, 2)) + sstore(2, sub(0, 3)) + } + E(addr); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs(u160(-1), u160(-2), u160(-3))); +} + +BOOST_AUTO_TEST_CASE(storage_array_dyn) +{ + char const* sourceCode = R"( + contract C { + address[] addr; + event E(address[] a); + function f() { + addr.push(1); + addr.push(2); + addr.push(3); + E(addr); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs(0x20, 3, u160(1), u160(2), u160(3))); +} + +BOOST_AUTO_TEST_CASE(storage_array_compact) +{ + char const* sourceCode = R"( + contract C { + int72[] x; + event E(int72[]); + function f() { + x.push(-1); + x.push(2); + x.push(-3); + x.push(4); + x.push(-5); + x.push(6); + x.push(-7); + x.push(8); + E(x); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + REQUIRE_LOG_DATA(encodeArgs( + 0x20, 8, u256(-1), 2, u256(-3), 4, u256(-5), 6, u256(-7), 8 + )); +} + +BOOST_AUTO_TEST_CASE(external_function) +{ + char const* sourceCode = R"( + contract C { + event E(function(uint) external returns (uint), function(uint) external returns (uint)); + function(uint) external returns (uint) g; + function f(uint) returns (uint) { + g = this.f; + E(this.f, g); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f(uint256)"); + string functionIdF = asString(m_contractAddress.ref()) + asString(FixedHash<4>(dev::keccak256("f(uint256)")).ref()); + REQUIRE_LOG_DATA(encodeArgs(functionIdF, functionIdF)); +} + +BOOST_AUTO_TEST_CASE(external_function_cleanup) +{ + char const* sourceCode = R"( + contract C { + event E(function(uint) external returns (uint), function(uint) external returns (uint)); + // This test relies on the fact that g is stored in slot zero. + function(uint) external returns (uint) g; + function f(uint) returns (uint) { + function(uint) external returns (uint)[1] memory h; + assembly { sstore(0, sub(0, 1)) mstore(h, sub(0, 1)) } + E(h[0], g); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f(uint256)"); + REQUIRE_LOG_DATA(encodeArgs(string(24, char(-1)), string(24, char(-1)))); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d0c5285c..166c4660 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3157,6 +3157,31 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); } +BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) +{ + char const* sourceCode = R"( + contract ClientReceipt { + bytes x; + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() { + x.length = 31; + x[0] = "A"; + x[1] = "B"; + x[2] = "C"; + x[30] = "Z"; + Deposit(10, x, 15); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z")); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); +} + BOOST_AUTO_TEST_CASE(event_indexed_string) { char const* sourceCode = R"( @@ -4402,6 +4427,75 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) BOOST_CHECK(storageEmpty(m_contractAddress)); } +BOOST_AUTO_TEST_CASE(array_copy_storage_abi) +{ + // NOTE: This does not really test copying from storage to ABI directly, + // because it will always copy to memory first. + char const* sourceCode = R"( + contract c { + uint8[] x; + uint16[] y; + uint24[] z; + function test1() returns (uint8[]) { + for (uint i = 0; i < 101; ++i) + x.push(uint8(i)); + return x; + } + function test2() returns (uint16[]) { + for (uint i = 0; i < 101; ++i) + y.push(uint16(i)); + return y; + } + function test3() returns (uint24[]) { + for (uint i = 0; i < 101; ++i) + z.push(uint24(i)); + return z; + } + } + )"; + compileAndRun(sourceCode); + bytes valueSequence; + for (size_t i = 0; i < 101; ++i) + valueSequence += toBigEndian(u256(i)); + BOOST_CHECK(callContractFunction("test1()") == encodeArgs(0x20, 101) + valueSequence); + BOOST_CHECK(callContractFunction("test2()") == encodeArgs(0x20, 101) + valueSequence); + BOOST_CHECK(callContractFunction("test3()") == encodeArgs(0x20, 101) + valueSequence); +} + +BOOST_AUTO_TEST_CASE(array_copy_storage_abi_signed) +{ + // NOTE: This does not really test copying from storage to ABI directly, + // because it will always copy to memory first. + char const* sourceCode = R"( + contract c { + int16[] x; + function test() returns (int16[]) { + x.push(int16(-1)); + x.push(int16(-1)); + x.push(int16(8)); + x.push(int16(-16)); + x.push(int16(-2)); + x.push(int16(6)); + x.push(int16(8)); + x.push(int16(-1)); + return x; + } + } + )"; + compileAndRun(sourceCode); + bytes valueSequence; + BOOST_CHECK(callContractFunction("test()") == encodeArgs(0x20, 8, + u256(-1), + u256(-1), + u256(8), + u256(-16), + u256(-2), + u256(6), + u256(8), + u256(-1) + )); +} + BOOST_AUTO_TEST_CASE(array_push) { char const* sourceCode = R"( |