diff options
-rw-r--r-- | SolidityABIJSON.cpp | 42 | ||||
-rw-r--r-- | SolidityInterface.cpp | 173 |
2 files changed, 186 insertions, 29 deletions
diff --git a/SolidityABIJSON.cpp b/SolidityABIJSON.cpp index 1f7d35ab..13e65761 100644 --- a/SolidityABIJSON.cpp +++ b/SolidityABIJSON.cpp @@ -32,12 +32,12 @@ namespace solidity namespace test { -class InterfaceChecker +class JSONInterfaceChecker { public: - InterfaceChecker(): m_compilerStack(false) {} + JSONInterfaceChecker(): m_compilerStack(false) {} - void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString, std::string const& expectedSolidityInterface) + void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) { try { @@ -49,7 +49,6 @@ public: BOOST_FAIL(msg); } std::string generatedInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABI_INTERFACE); - std::string generatedSolidityInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABI_SOLIDITY_INTERFACE); Json::Value generatedInterface; m_reader.parse(generatedInterfaceString, generatedInterface); Json::Value expectedInterface; @@ -57,9 +56,6 @@ public: BOOST_CHECK_MESSAGE(expectedInterface == generatedInterface, "Expected:\n" << expectedInterface.toStyledString() << "\n but got:\n" << generatedInterface.toStyledString()); - BOOST_CHECK_MESSAGE(expectedSolidityInterface == generatedSolidityInterfaceString, - "Expected:\n" << expectedSolidityInterface << - "\n but got:\n" << generatedSolidityInterfaceString); } private: @@ -67,7 +63,7 @@ private: Json::Reader m_reader; }; -BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, InterfaceChecker) +BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, JSONInterfaceChecker) BOOST_AUTO_TEST_CASE(basic_test) { @@ -75,8 +71,6 @@ BOOST_AUTO_TEST_CASE(basic_test) " function f(uint a) returns(uint d) { return a * 7; }\n" "}\n"; - char const* sourceInterface = "contract test{function f(uint256 a)returns(uint256 d){}}"; - char const* interface = R"([ { "name": "f", @@ -97,18 +91,16 @@ BOOST_AUTO_TEST_CASE(basic_test) } ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(empty_contract) { char const* sourceCode = "contract test {\n" "}\n"; - char const* sourceInterface = "contract test{}"; - char const* interface = "[]"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_methods) @@ -117,7 +109,6 @@ BOOST_AUTO_TEST_CASE(multiple_methods) " function f(uint a) returns(uint d) { return a * 7; }\n" " function g(uint b) returns(uint e) { return b * 8; }\n" "}\n"; - char const* sourceInterface = "contract test{function f(uint256 a)returns(uint256 d){}function g(uint256 b)returns(uint256 e){}}"; char const* interface = R"([ { @@ -156,7 +147,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) } ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_params) @@ -164,7 +155,6 @@ BOOST_AUTO_TEST_CASE(multiple_params) char const* sourceCode = "contract test {\n" " function f(uint a, uint b) returns(uint d) { return a + b; }\n" "}\n"; - char const* sourceInterface = "contract test{function f(uint256 a,uint256 b)returns(uint256 d){}}"; char const* interface = R"([ { @@ -190,7 +180,7 @@ BOOST_AUTO_TEST_CASE(multiple_params) } ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_methods_order) @@ -200,7 +190,6 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) " function f(uint a) returns(uint d) { return a * 7; }\n" " function c(uint b) returns(uint e) { return b * 8; }\n" "}\n"; - char const* sourceInterface = "contract test{function c(uint256 b)returns(uint256 e){}function f(uint256 a)returns(uint256 d){}}"; char const* interface = R"([ { @@ -239,7 +228,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) } ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(const_function) @@ -248,7 +237,6 @@ BOOST_AUTO_TEST_CASE(const_function) " function foo(uint a, uint b) returns(uint d) { return a + b; }\n" " function boo(uint32 a) constant returns(uint b) { return a * 4; }\n" "}\n"; - char const* sourceInterface = "contract test{function foo(uint256 a,uint256 b)returns(uint256 d){}function boo(uint32 a)constant returns(uint256 b){}}"; char const* interface = R"([ { @@ -289,17 +277,16 @@ BOOST_AUTO_TEST_CASE(const_function) } ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(exclude_fallback_function) { char const* sourceCode = "contract test { function() {} }"; - char const* sourceInterface = "contract test{}"; char const* interface = "[]"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(events) @@ -309,8 +296,6 @@ BOOST_AUTO_TEST_CASE(events) " event e1(uint b, address indexed c); \n" " event e2(); \n" "}\n"; - char const* sourceInterface = "contract test{function f(uint256 a)returns(uint256 d){}event e1(uint256 b,address indexed c);event e2;}"; - char const* interface = R"([ { "name": "f", @@ -353,7 +338,7 @@ BOOST_AUTO_TEST_CASE(events) ])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } @@ -368,7 +353,6 @@ BOOST_AUTO_TEST_CASE(inherited) " function derivedFunction(string32 p) returns (string32 i) { return p; } \n" " event derivedEvent(uint indexed evtArgDerived); \n" " }"; - char const* sourceInterface = "contract Derived{function baseFunction(uint256 p)returns(uint256 i){}function derivedFunction(string32 p)returns(string32 i){}event derivedEvent(uint256 indexed evtArgDerived);event baseEvent(string32 indexed evtArgBase);}"; char const* interface = R"([ { @@ -423,7 +407,7 @@ BOOST_AUTO_TEST_CASE(inherited) }])"; - checkInterface(sourceCode, interface, sourceInterface); + checkInterface(sourceCode, interface); } diff --git a/SolidityInterface.cpp b/SolidityInterface.cpp new file mode 100644 index 00000000..3b7d26ec --- /dev/null +++ b/SolidityInterface.cpp @@ -0,0 +1,173 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + */ +/** + * @author Christian <c@ethdev.com> + * @date 2015 + * Unit tests for generating source interfaces for Solidity contracts. + */ + +#include <boost/test/unit_test.hpp> +#include <libsolidity/CompilerStack.h> +#include <libsolidity/AST.h> + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +class SolidityInterfaceChecker +{ +public: + SolidityInterfaceChecker(): m_compilerStack(false) {} + + /// Compiles the given code, generates the interface and parses that again. + ContractDefinition const& checkInterface(string const& _code, string const& _contractName = "") + { + m_code = _code; + BOOST_REQUIRE_NO_THROW(m_compilerStack.parse(_code)); + m_interface = m_compilerStack.getMetadata("", DocumentationType::ABI_SOLIDITY_INTERFACE); + BOOST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface)); + return m_reCompiler.getContractDefinition(_contractName); + } + + string getSourcePart(ASTNode const& _node) const + { + Location location = _node.getLocation(); + BOOST_REQUIRE(!location.isEmpty()); + return m_interface.substr(location.start, location.end - location.start); + } + +protected: + string m_code; + string m_interface; + CompilerStack m_compilerStack; + CompilerStack m_reCompiler; +}; + +BOOST_FIXTURE_TEST_SUITE(SolidityInterface, SolidityInterfaceChecker) + +BOOST_AUTO_TEST_CASE(empty_contract) +{ + ContractDefinition const& contract = checkInterface("contract test {}"); + BOOST_CHECK_EQUAL(getSourcePart(contract), "contract test{}"); +} + +BOOST_AUTO_TEST_CASE(single_function) +{ + ContractDefinition const& contract = checkInterface( + "contract test {\n" + " function f(uint a) returns(uint d) { return a * 7; }\n" + "}\n"); + BOOST_REQUIRE_EQUAL(1, contract.getDefinedFunctions().size()); + BOOST_CHECK_EQUAL(getSourcePart(*contract.getDefinedFunctions().front()), + "function f(uint256 a)returns(uint256 d){}"); +} + +BOOST_AUTO_TEST_CASE(single_constant_function) +{ + ContractDefinition const& contract = checkInterface( + "contract test { function f(uint a) constant returns(hash8 x) { 1==2; } }"); + BOOST_REQUIRE_EQUAL(1, contract.getDefinedFunctions().size()); + BOOST_CHECK_EQUAL(getSourcePart(*contract.getDefinedFunctions().front()), + "function f(uint256 a)constant returns(hash8 x){}"); +} + +BOOST_AUTO_TEST_CASE(multiple_functions) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a) returns(uint d) { return a * 7; }\n" + " function g(uint b) returns(uint e) { return b * 8; }\n" + "}\n"; + ContractDefinition const& contract = checkInterface(sourceCode); + set<string> expectation({"function f(uint256 a)returns(uint256 d){}", + "function g(uint256 b)returns(uint256 e){}"}); + BOOST_REQUIRE_EQUAL(2, contract.getDefinedFunctions().size()); + BOOST_CHECK(expectation == set<string>({getSourcePart(*contract.getDefinedFunctions().at(0)), + getSourcePart(*contract.getDefinedFunctions().at(1))})); +} + +BOOST_AUTO_TEST_CASE(exclude_fallback_function) +{ + char const* sourceCode = "contract test { function() {} }"; + ContractDefinition const& contract = checkInterface(sourceCode); + BOOST_CHECK_EQUAL(getSourcePart(contract), "contract test{}"); +} + +BOOST_AUTO_TEST_CASE(event) +{ + ContractDefinition const& contract = checkInterface( + "contract test { event Event; }"); + BOOST_REQUIRE_EQUAL(1, contract.getEvents().size()); + BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()), + "event Event;"); +} + +BOOST_AUTO_TEST_CASE(event_arguments) +{ + ContractDefinition const& contract = checkInterface( + "contract test { event Event(uint a, uint indexed b); }"); + BOOST_REQUIRE_EQUAL(1, contract.getEvents().size()); + BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()), + "event Event(uint256 a,uint256 indexed b);"); +} + +BOOST_AUTO_TEST_CASE(events) +{ + char const* sourceCode = "contract test {\n" + " function f(uint a) returns(uint d) { return a * 7; }\n" + " event e1(uint b, address indexed c); \n" + " event e2(); \n" + "}\n"; + ContractDefinition const& contract = checkInterface(sourceCode); + set<string> expectation({"event e1(uint256 b,address indexed c);", "event e2;"}); + BOOST_REQUIRE_EQUAL(2, contract.getEvents().size()); + BOOST_CHECK(expectation == set<string>({getSourcePart(*contract.getEvents().at(0)), + getSourcePart(*contract.getEvents().at(1))})); +} + +BOOST_AUTO_TEST_CASE(inheritance) +{ + char const* sourceCode = + " contract Base { \n" + " function baseFunction(uint p) returns (uint i) { return p; } \n" + " event baseEvent(string32 indexed evtArgBase); \n" + " } \n" + " contract Derived is Base { \n" + " function derivedFunction(string32 p) returns (string32 i) { return p; } \n" + " event derivedEvent(uint indexed evtArgDerived); \n" + " }"; + ContractDefinition const& contract = checkInterface(sourceCode); + set<string> expectedEvents({"event derivedEvent(uint256 indexed evtArgDerived);", + "event baseEvent(string32 indexed evtArgBase);"}); + set<string> expectedFunctions({"function baseFunction(uint256 p)returns(uint256 i){}", + "function derivedFunction(string32 p)returns(string32 i){}"}); + BOOST_CHECK(expectedEvents == set<string>({getSourcePart(*contract.getEvents().at(0)), + getSourcePart(*contract.getEvents().at(1))})); + BOOST_REQUIRE_EQUAL(2, contract.getDefinedFunctions().size()); + BOOST_CHECK(expectedFunctions == set<string>({getSourcePart(*contract.getDefinedFunctions().at(0)), + getSourcePart(*contract.getDefinedFunctions().at(1))})); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} |