aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt4
-rw-r--r--test/ExecutionFramework.h16
-rw-r--r--test/boostTest.cpp1
-rwxr-xr-xtest/externalTests.sh47
-rw-r--r--test/fuzzer.cpp2
-rw-r--r--test/libjulia/Common.cpp87
-rw-r--r--test/libjulia/Common.h55
-rw-r--r--test/libjulia/Disambiguator.cpp105
-rw-r--r--test/libjulia/FunctionGrouper.cpp85
-rw-r--r--test/libjulia/FunctionHoister.cpp85
-rw-r--r--test/libjulia/Parser.cpp12
-rw-r--r--test/libsolidity/ABIDecoderTests.cpp794
-rw-r--r--test/libsolidity/ABIEncoderTests.cpp50
-rw-r--r--test/libsolidity/ABITestsCommon.h43
-rw-r--r--test/libsolidity/Assembly.cpp54
-rw-r--r--test/libsolidity/InlineAssembly.cpp91
-rw-r--r--test/libsolidity/JSONCompiler.cpp2
-rw-r--r--test/libsolidity/SMTChecker.cpp146
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp3
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp6
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp46
-rw-r--r--test/libsolidity/SolidityParser.cpp10
-rw-r--r--test/libsolidity/StandardCompiler.cpp113
23 files changed, 1719 insertions, 138 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6a8a4399..f36ad4c5 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -3,7 +3,7 @@ list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/fuzzer.cpp")
file(GLOB_RECURSE headers "*.h")
add_executable(soltest ${sources} ${headers})
-target_link_libraries(soltest PRIVATE soljson solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
+target_link_libraries(soltest PRIVATE libsolc solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
add_executable(solfuzzer fuzzer.cpp)
-target_link_libraries(solfuzzer soljson evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES})
+target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES})
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index 2c61c0a6..8aa99473 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -84,14 +84,24 @@ public:
return callFallbackWithValue(0);
}
- template <class... Args>
- bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments)
+ bytes const& callContractFunctionWithValueNoEncoding(std::string _sig, u256 const& _value, bytes const& _arguments)
{
FixedHash<4> hash(dev::keccak256(_sig));
- sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value);
+ sendMessage(hash.asBytes() + _arguments, false, _value);
return m_output;
}
+ bytes const& callContractFunctionNoEncoding(std::string _sig, bytes const& _arguments)
+ {
+ return callContractFunctionWithValueNoEncoding(_sig, 0, _arguments);
+ }
+
+ template <class... Args>
+ bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments)
+ {
+ return callContractFunctionWithValueNoEncoding(_sig, _value, encodeArgs(_arguments...));
+ }
+
template <class... Args>
bytes const& callContractFunction(std::string _sig, Args const&... _arguments)
{
diff --git a/test/boostTest.cpp b/test/boostTest.cpp
index 7b452e06..a3cc51c5 100644
--- a/test/boostTest.cpp
+++ b/test/boostTest.cpp
@@ -57,6 +57,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
if (dev::test::Options::get().disableIPC)
{
for (auto suite: {
+ "ABIDecoderTest",
"ABIEncoderTest",
"SolidityAuctionRegistrar",
"SolidityFixedFeeRegistrar",
diff --git a/test/externalTests.sh b/test/externalTests.sh
index 1cc0af19..11972eae 100755
--- a/test/externalTests.sh
+++ b/test/externalTests.sh
@@ -44,53 +44,6 @@ DIR=$(mktemp -d)
npm install
find . -name soljson.js -exec cp "$SOLJSON" {} \;
- # This is a patch that lets truffle ignore the pre-release compiler warning
- cat > truffle.patch <<EOF
---- node_modules/truffle/build/cli.bundled.js 2017-11-27 16:56:47.114830112 +0100
-+++ /tmp/patched 2017-11-27 16:52:31.887064115 +0100
-@@ -313846,9 +313846,12 @@
- });
-
- output = JSON.parse(output);
-+ var errors = output.errors.filter(function(solidity_error) {
-+ return solidity_error.formattedMessage.indexOf("pre-release compiler") < 0;
-+ });
-
-- if (output.errors) {
-- throw new CompileError(output.errors[0].formattedMessage);
-+ if (errors) {
-+ throw new CompileError(errors[0].formattedMessage);
- }
-
- return {
-@@ -313901,9 +313904,13 @@
- return {error: importErrorKey};
- });
-
-- output = JSON.parse(output);
-+ output = JSON.parse(output);
-+
-+ var errors = output.errors.filter(function(solidity_error) {
-+ return solidity_error.formattedMessage.indexOf("pre-release compiler") < 0;
-+ });
-
-- var nonImportErrors = output.errors.filter(function(solidity_error) {
-+ var nonImportErrors = errors.filter(function(solidity_error) {
- // If the import error key is not found, we must not have an import error.
- // This means we have a *different* parsing error which we should show to the user.
- // Note: solc can return multiple parsing errors at once.
-@@ -313917,7 +313924,7 @@
-
- // Now, all errors must be import errors.
- // Filter out our forced import, then get the import paths of the rest.
-- var imports = output.errors.filter(function(solidity_error) {
-+ var imports = errors.filter(function(solidity_error) {
- return solidity_error.message.indexOf(failingImportFileName) < 0;
- }).map(function(solidity_error) {
- var matches = solidity_error.formattedMessage.match(/import[^'"]+("|')([^'"]+)("|');/);
-EOF
-
- patch node_modules/truffle/build/cli.bundled.js ./truffle.patch
npm run test
)
rm -rf "$DIR"
diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp
index 53ba7201..578e63a4 100644
--- a/test/fuzzer.cpp
+++ b/test/fuzzer.cpp
@@ -20,7 +20,7 @@
#include <libevmasm/Assembly.h>
#include <libevmasm/ConstantOptimiser.h>
-#include <solc/jsonCompiler.h>
+#include <libsolc/libsolc.h>
#include <json/json.h>
diff --git a/test/libjulia/Common.cpp b/test/libjulia/Common.cpp
new file mode 100644
index 00000000..e1ab8215
--- /dev/null
+++ b/test/libjulia/Common.cpp
@@ -0,0 +1,87 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Common functions the iulia tests.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/Disambiguator.h>
+
+#include <libsolidity/parsing/Scanner.h>
+
+#include <libsolidity/inlineasm/AsmParser.h>
+#include <libsolidity/inlineasm/AsmAnalysis.h>
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <libsolidity/interface/SourceReferenceFormatter.h>
+#include <libsolidity/interface/ErrorReporter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::solidity;
+
+void dev::julia::test::printErrors(ErrorList const& _errors, Scanner const& _scanner)
+{
+ for (auto const& error: _errors)
+ SourceReferenceFormatter::printExceptionInformation(
+ cout,
+ *error,
+ (error->type() == Error::Type::Warning) ? "Warning" : "Error",
+ [&](std::string const&) -> Scanner const& { return _scanner; }
+ );
+}
+
+
+pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::julia::test::parse(string const& _source, bool _julia)
+{
+ auto flavour = _julia ? assembly::AsmFlavour::IULIA : assembly::AsmFlavour::Strict;
+ ErrorList errors;
+ ErrorReporter errorReporter(errors);
+ auto scanner = make_shared<Scanner>(CharStream(_source), "");
+ auto parserResult = assembly::Parser(errorReporter, flavour).parse(scanner);
+ if (parserResult)
+ {
+ BOOST_REQUIRE(errorReporter.errors().empty());
+ auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
+ assembly::AsmAnalyzer analyzer(*analysisInfo, errorReporter, flavour);
+ if (analyzer.analyze(*parserResult))
+ {
+ BOOST_REQUIRE(errorReporter.errors().empty());
+ return make_pair(parserResult, analysisInfo);
+ }
+ }
+ printErrors(errors, *scanner);
+ BOOST_FAIL("Invalid source.");
+
+ // Unreachable.
+ return {};
+}
+
+assembly::Block dev::julia::test::disambiguate(string const& _source, bool _julia)
+{
+ auto result = parse(_source, _julia);
+ return boost::get<Block>(Disambiguator(*result.second)(*result.first));
+}
+
+string dev::julia::test::format(string const& _source, bool _julia)
+{
+ return assembly::AsmPrinter(_julia)(*parse(_source, _julia).first);
+}
diff --git a/test/libjulia/Common.h b/test/libjulia/Common.h
new file mode 100644
index 00000000..1371101c
--- /dev/null
+++ b/test/libjulia/Common.h
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Common functions the iulia tests.
+ */
+
+#pragma once
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace dev
+{
+namespace solidity
+{
+class Scanner;
+class Error;
+using ErrorList = std::vector<std::shared_ptr<Error const>>;
+namespace assembly
+{
+struct AsmAnalysisInfo;
+}
+}
+namespace julia
+{
+namespace test
+{
+
+void printErrors(solidity::ErrorList const& _errors, solidity::Scanner const& _scanner);
+std::pair<std::shared_ptr<solidity::assembly::Block>, std::shared_ptr<solidity::assembly::AsmAnalysisInfo>>
+parse(std::string const& _source, bool _julia = true);
+solidity::assembly::Block disambiguate(std::string const& _source, bool _julia = true);
+std::string format(std::string const& _source, bool _julia = true);
+
+}
+}
+}
diff --git a/test/libjulia/Disambiguator.cpp b/test/libjulia/Disambiguator.cpp
new file mode 100644
index 00000000..a6338449
--- /dev/null
+++ b/test/libjulia/Disambiguator.cpp
@@ -0,0 +1,105 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia name disambiguator.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ string result = p(disambiguate(_original));\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+ BOOST_CHECK_EQUAL(result, p(disambiguate(result)));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaDisambiguator)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(variables)
+{
+ CHECK(
+ "{ { let a:u256 } { let a:u256 } }",
+ "{ { let a:u256 } { let a_1:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(variables_clash)
+{
+ CHECK(
+ "{ { let a:u256 let a_1:u256 } { let a:u256 } }",
+ "{ { let a:u256 let a_1:u256 } { let a_2:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(variables_inside_functions)
+{
+ CHECK(
+ "{ { let c:u256 let b:u256 } function f(a:u256, c:u256) -> b:u256 { let x:u256 } { let a:u256 let x:u256 } }",
+ "{ { let c:u256 let b:u256 } function f(a:u256, c_1:u256) -> b_1:u256 { let x:u256 } { let a_1:u256 let x_1:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(function_call)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256, d:u256, f:u256 } { function f(a:u256) -> c:u256, d:u256 { let b:u256, c_1:u256 := f(a) } } }",
+ "{ { let a:u256, b:u256, c:u256, d:u256, f:u256 } { function f_1(a_1:u256) -> c_1:u256, d_1:u256 { let b_1:u256, c_1_1:u256 := f_1(a_1) } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(for_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256 } { for { let a:u256 } a { a := a } { let b:u256 := a } } }",
+ "{ { let a:u256, b:u256 } { for { let a_1:u256 } a_1 { a_1 := a_1 } { let b_1:u256 := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(switch_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256 } { let a:u256 switch a case 0:u256 { let b:u256 := a } default { let c:u256 := a } } }",
+ "{ { let a:u256, b:u256, c:u256 } { let a_1:u256 switch a_1 case 0:u256 { let b_1:u256 := a_1 } default { let c_1:u256 := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(if_statement)
+{
+ CHECK(
+ "{ { let a:u256, b:u256, c:u256 } { let a:bool if a { let b:bool := a } } }",
+ "{ { let a:u256, b:u256, c:u256 } { let a_1:bool if a_1 { let b_1:bool := a_1 } } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/FunctionGrouper.cpp b/test/libjulia/FunctionGrouper.cpp
new file mode 100644
index 00000000..78f382cb
--- /dev/null
+++ b/test/libjulia/FunctionGrouper.cpp
@@ -0,0 +1,85 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia function grouper.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/FunctionGrouper.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ Block b = disambiguate(_original);\
+ (FunctionGrouper{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaFunctionGrouper)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ { } }");
+}
+
+BOOST_AUTO_TEST_CASE(single_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() {} }",
+ "{ { let a:u256 } function f() {} }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_fun_mixed)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 } let c:u256 function g() { let d:u256 } let e:u256 }",
+ "{ { let a:u256 let c:u256 let e:u256 } function f() { let b:u256 } function g() { let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(nested_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 function g() { let c:u256} let d:u256 } }",
+ "{ { let a:u256 } function f() { let b:u256 function g() { let c:u256} let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(empty_block)
+{
+ CHECK(
+ "{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }",
+ "{ { let a:u256 { } } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/FunctionHoister.cpp b/test/libjulia/FunctionHoister.cpp
new file mode 100644
index 00000000..3d6fff85
--- /dev/null
+++ b/test/libjulia/FunctionHoister.cpp
@@ -0,0 +1,85 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for the iulia function hoister.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/FunctionHoister.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p(true);\
+ Block b = disambiguate(_original);\
+ (FunctionHoister{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaFunctionHoister)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(single_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() {} }",
+ "{ let a:u256 function f() {} }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(multi_fun_mixed)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 } let c:u256 function g() { let d:u256 } let e:u256 }",
+ "{ let a:u256 let c:u256 let e:u256 function f() { let b:u256 } function g() { let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(nested_fun)
+{
+ CHECK(
+ "{ let a:u256 function f() { let b:u256 function g() { let c:u256} let d:u256 } }",
+ "{ let a:u256 function g() { let c:u256 } function f() { let b:u256 let d:u256 } }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(empty_block)
+{
+ CHECK(
+ "{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }",
+ "{ let a:u256 function f() -> x:bool { let b:u256 := 4:u256 for {} f() {} {} } }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp
index 9aa325a4..a8a41b3c 100644
--- a/test/libjulia/Parser.cpp
+++ b/test/libjulia/Parser.cpp
@@ -52,11 +52,11 @@ bool parse(string const& _source, ErrorReporter& errorReporter)
try
{
auto scanner = make_shared<Scanner>(CharStream(_source));
- auto parserResult = assembly::Parser(errorReporter, true).parse(scanner);
+ auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::IULIA).parse(scanner);
if (parserResult)
{
assembly::AsmAnalysisInfo analysisInfo;
- return (assembly::AsmAnalyzer(analysisInfo, errorReporter, true)).analyze(*parserResult);
+ return (assembly::AsmAnalyzer(analysisInfo, errorReporter, assembly::AsmFlavour::IULIA)).analyze(*parserResult);
}
}
catch (FatalError const&)
@@ -196,6 +196,14 @@ BOOST_AUTO_TEST_CASE(empty_call)
CHECK_ERROR("{ () }", ParserError, "Literal or identifier expected.");
}
+BOOST_AUTO_TEST_CASE(tokens_as_identifers)
+{
+ BOOST_CHECK(successParse("{ let return:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let byte:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let address:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let bool:u256 := 1:u256 }"));
+}
+
BOOST_AUTO_TEST_CASE(lacking_types)
{
CHECK_ERROR("{ let x := 1:u256 }", ParserError, "Expected token Identifier got 'Assign'");
diff --git a/test/libsolidity/ABIDecoderTests.cpp b/test/libsolidity/ABIDecoderTests.cpp
new file mode 100644
index 00000000..15c04b37
--- /dev/null
+++ b/test/libsolidity/ABIDecoderTests.cpp
@@ -0,0 +1,794 @@
+/*
+ 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 decoder.
+ */
+
+#include <functional>
+#include <string>
+#include <tuple>
+#include <boost/test/unit_test.hpp>
+#include <libsolidity/interface/Exceptions.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
+
+#include <test/libsolidity/ABITestsCommon.h>
+
+using namespace std;
+using namespace std::placeholders;
+using namespace dev::test;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+BOOST_FIXTURE_TEST_SUITE(ABIDecoderTest, SolidityExecutionFramework)
+
+BOOST_AUTO_TEST_CASE(both_encoders_macro)
+{
+ // This tests that the "both decoders macro" at least runs twice and
+ // modifies the source.
+ string sourceCode;
+ int runs = 0;
+ BOTH_ENCODERS(runs++;)
+ BOOST_CHECK(sourceCode == NewEncoderPragma);
+ BOOST_CHECK_EQUAL(runs, 2);
+}
+
+BOOST_AUTO_TEST_CASE(value_types)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool e, C g) public returns (uint) {
+ if (a != 1) return 1;
+ if (b != 2) return 2;
+ if (c != 3) return 3;
+ if (d != 4) return 4;
+ if (x != "abc") return 5;
+ if (e != true) return 6;
+ if (g != this) return 7;
+ return 20;
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction(
+ "f(uint256,uint16,uint24,int24,bytes3,bool,address)",
+ 1, 2, 3, 4, string("abc"), true, u160(m_contractAddress)
+ ), encodeArgs(u256(20)));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(enums)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E { A, B }
+ function f(E e) public pure returns (uint x) {
+ assembly { x := e }
+ }
+ }
+ )";
+ bool newDecoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint8)", 0), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("f(uint8)", 1), encodeArgs(u256(1)));
+ // The old decoder was not as strict about enums
+ ABI_CHECK(callContractFunction("f(uint8)", 2), (newDecoder ? encodeArgs() : encodeArgs(2)));
+ ABI_CHECK(callContractFunction("f(uint8)", u256(-1)), (newDecoder? encodeArgs() : encodeArgs(u256(0xff))));
+ newDecoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(cleanup)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint16 a, int16 b, address c, bytes3 d, bool e)
+ public pure returns (uint v, uint w, uint x, uint y, uint z) {
+ assembly { v := a w := b x := c y := d z := e}
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(
+ callContractFunction("f(uint16,int16,address,bytes3,bool)", 1, 2, 3, "a", true),
+ encodeArgs(u256(1), u256(2), u256(3), string("a"), true)
+ );
+ ABI_CHECK(
+ callContractFunction(
+ "f(uint16,int16,address,bytes3,bool)",
+ u256(0xffffff), u256(0x1ffff), u256(-1), string("abcd"), u256(4)
+ ),
+ encodeArgs(u256(0xffff), u256(-1), (u256(1) << 160) - 1, string("abc"), true)
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(fixed_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint16[3] a, uint16[2][3] b, uint i, uint j, uint k)
+ public pure returns (uint, uint) {
+ return (a[i], b[j][k]);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 1, 2, 3,
+ 11, 12,
+ 21, 22,
+ 31, 32,
+ 1, 2, 1
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint16[3],uint16[2][3],uint256,uint256,uint256)", args),
+ encodeArgs(u256(2), u256(32))
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(dynamic_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16[] b, uint c)
+ public pure returns (uint, uint, uint) {
+ return (b.length, b[a], c);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ 7,
+ 11, 12, 13, 14, 15, 16, 17
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,uint16[],uint256)", args),
+ encodeArgs(u256(7), u256(17), u256(9))
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(dynamic_nested_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16[][] b, uint[2][][3] c, uint d)
+ public pure returns (uint, uint, uint, uint, uint, uint, uint) {
+ return (a, b.length, b[1].length, b[1][1], c[1].length, c[1][1][1], d);
+ }
+ function test() view returns (uint, uint, uint, uint, uint, uint, uint) {
+ uint16[][] memory b = new uint16[][](3);
+ b[0] = new uint16[](2);
+ b[0][0] = 0x55;
+ b[0][1] = 0x56;
+ b[1] = new uint16[](4);
+ b[1][0] = 0x65;
+ b[1][1] = 0x66;
+ b[1][2] = 0x67;
+ b[1][3] = 0x68;
+
+ uint[2][][3] memory c;
+ c[0] = new uint[2][](1);
+ c[0][0][1] = 0x75;
+ c[1] = new uint[2][](5);
+ c[1][1][1] = 0x85;
+
+ return this.f(0x12, b, c, 0x13);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 0x12, 4 * 0x20, 17 * 0x20, 0x13,
+ // b
+ 3, 3 * 0x20, 6 * 0x20, 11 * 0x20,
+ 2, 85, 86,
+ 4, 101, 102, 103, 104,
+ 0,
+ // c
+ 3 * 0x20, 6 * 0x20, 17 * 0x20,
+ 1, 0, 117,
+ 5, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0,
+ 0
+ );
+
+ bytes expectation = encodeArgs(0x12, 3, 4, 0x66, 5, 0x85, 0x13);
+ ABI_CHECK(callContractFunction("test()"), expectation);
+ ABI_CHECK(callContractFunction("f(uint256,uint16[][],uint256[2][][3],uint256)", args), expectation);
+ )
+}
+
+BOOST_AUTO_TEST_CASE(byte_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, bytes b, uint c)
+ public pure returns (uint, uint, byte, uint) {
+ return (a, b.length, b[3], c);
+ }
+
+ function f_external(uint a, bytes b, uint c)
+ external pure returns (uint, uint, byte, uint) {
+ return (a, b.length, b[3], c);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ 7, "abcdefg"
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,bytes,uint256)", args),
+ encodeArgs(u256(6), u256(7), "d", 9)
+ );
+ ABI_CHECK(
+ callContractFunction("f_external(uint256,bytes,uint256)", args),
+ encodeArgs(u256(6), u256(7), "d", 9)
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(calldata_arrays_too_large)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint[] b, uint c) external pure returns (uint) {
+ return 7;
+ }
+ }
+ )";
+ bool newEncoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ (u256(1) << 255) + 2, 1, 2
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,uint256[],uint256)", args),
+ newEncoder ? encodeArgs() : encodeArgs(7)
+ );
+ newEncoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_from_memory_simple)
+{
+ string sourceCode = R"(
+ contract C {
+ uint public _a;
+ uint[] public _b;
+ function C(uint a, uint[] b) {
+ _a = a;
+ _b = b;
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C", encodeArgs(
+ 7, 0x40,
+ // b
+ 3, 0x21, 0x22, 0x23
+ ));
+ ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
+ ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
+ ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
+ ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
+ ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_function_type)
+{
+ string sourceCode = R"(
+ contract D {
+ function () external returns (uint) public _a;
+ function D(function () external returns (uint) a) {
+ _a = a;
+ }
+ }
+ contract C {
+ function f() returns (uint) {
+ return 3;
+ }
+ function g(function () external returns (uint) _f) returns (uint) {
+ return _f();
+ }
+ // uses "decode from memory"
+ function test1() returns (uint) {
+ D d = new D(this.f);
+ return d._a()();
+ }
+ // uses "decode from calldata"
+ function test2() returns (uint) {
+ return this.g(this.f);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test1()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test2()"), encodeArgs(3));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_function_type_array)
+{
+ string sourceCode = R"(
+ contract D {
+ function () external returns (uint)[] public _a;
+ function D(function () external returns (uint)[] a) {
+ _a = a;
+ }
+ }
+ contract E {
+ function () external returns (uint)[3] public _a;
+ function E(function () external returns (uint)[3] a) {
+ _a = a;
+ }
+ }
+ contract C {
+ function f1() public returns (uint) {
+ return 1;
+ }
+ function f2() public returns (uint) {
+ return 2;
+ }
+ function f3() public returns (uint) {
+ return 3;
+ }
+ function g(function () external returns (uint)[] _f, uint i) public returns (uint) {
+ return _f[i]();
+ }
+ function h(function () external returns (uint)[3] _f, uint i) public returns (uint) {
+ return _f[i]();
+ }
+ // uses "decode from memory"
+ function test1_dynamic() public returns (uint) {
+ var x = new function() external returns (uint)[](3);
+ x[0] = this.f1;
+ x[1] = this.f2;
+ x[2] = this.f3;
+ D d = new D(x);
+ return d._a(2)();
+ }
+ function test1_static() public returns (uint) {
+ E e = new E([this.f1, this.f2, this.f3]);
+ return e._a(2)();
+ }
+ // uses "decode from calldata"
+ function test2_dynamic() public returns (uint) {
+ var x = new function() external returns (uint)[](3);
+ x[0] = this.f1;
+ x[1] = this.f2;
+ x[2] = this.f3;
+ return this.g(x, 0);
+ }
+ function test2_static() public returns (uint) {
+ return this.h([this.f1, this.f2, this.f3], 0);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test1_static()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test1_dynamic()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test2_static()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("test2_dynamic()"), encodeArgs(1));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_from_memory_complex)
+{
+ string sourceCode = R"(
+ contract C {
+ uint public _a;
+ uint[] public _b;
+ bytes[2] public _c;
+ function C(uint a, uint[] b, bytes[2] c) {
+ _a = a;
+ _b = b;
+ _c = c;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C", encodeArgs(
+ 7, 0x60, 7 * 0x20,
+ // b
+ 3, 0x21, 0x22, 0x23,
+ // c
+ 0x40, 0x80,
+ 8, string("abcdefgh"),
+ 52, string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ ));
+ ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
+ ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
+ ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
+ ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
+ ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
+ ABI_CHECK(callContractFunction("_c(uint256)", 0), encodeArgs(0x20, 8, string("abcdefgh")));
+ ABI_CHECK(callContractFunction("_c(uint256)", 1), encodeArgs(0x20, 52, string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")));
+ ABI_CHECK(callContractFunction("_c(uint256)", 2), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_value_type)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint b) public pure returns (uint) { return a; }
+ }
+ )";
+ bool newDecoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint256,uint256)", 1, 2), encodeArgs(1));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(64, 0)), encodeArgs(0));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(63, 0)), newDecoder ? encodeArgs() : encodeArgs(0));
+ newDecoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_array)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint[] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ bool newDecoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1)), newDecoder ? encodeArgs() : encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(31, 0)), newDecoder ? encodeArgs() : encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(32, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 2, 5, 6)), encodeArgs(7));
+ newDecoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_dynamic_input_array)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(bytes[1] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[1])", encodeArgs(0x20)), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_bytes)
+{
+ string sourceCode = R"(
+ contract C {
+ function e(bytes a) public pure returns (uint) { return 7; }
+ function f(bytes[] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(5, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(6, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(7, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(8, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(5, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(6, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(7, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(8, 0)), encodeArgs(7));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(cleanup_int_inside_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E { A, B }
+ function f(uint16[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ function g(int16[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ function h(E[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, 7), encodeArgs(7));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, 7), encodeArgs(7));
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256("0xffff")));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256(-1)));
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0x1ffff")), encodeArgs(u256("0xffff")));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0x10fff")), encodeArgs(u256("0x0fff")));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 0), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 1), encodeArgs(u256(1)));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 2), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(storage_ptr)
+{
+ string sourceCode = R"(
+ library L {
+ struct S { uint x; uint y; }
+ function f(uint[] storage r, S storage s) public returns (uint, uint, uint, uint) {
+ r[2] = 8;
+ s.x = 7;
+ return (r[0], r[1], s.x, s.y);
+ }
+ }
+ contract C {
+ uint8 x = 3;
+ L.S s;
+ uint[] r;
+ function f() public returns (uint, uint, uint, uint, uint, uint) {
+ r.length = 6;
+ r[0] = 1;
+ r[1] = 2;
+ r[2] = 3;
+ s.x = 11;
+ s.y = 12;
+ var (a, b, c, d) = L.f(r, s);
+ return (r[2], s.x, a, b, c, d);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "L");
+ compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(8, 7, 1, 2, 7, 12));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_simple)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { uint a; uint8 b; uint8 c; bytes2 d; }
+ function f(S s) public pure returns (uint a, uint b, uint c, uint d) {
+ a = s.a;
+ b = s.b;
+ c = s.c;
+ d = uint(s.d);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f((uint256,uint8,uint8,bytes2))", 1, 2, 3, "ab"), encodeArgs(1, 2, 3, 'a' * 0x100 + 'b'));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_cleanup)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { int16 a; uint8 b; bytes2 c; }
+ function f(S s) public pure returns (uint a, uint b, uint c) {
+ assembly {
+ a := mload(s)
+ b := mload(add(s, 0x20))
+ c := mload(add(s, 0x40))
+ }
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(
+ callContractFunction("f((int16,uint8,bytes2))", 0xff010, 0xff0002, "abcd"),
+ encodeArgs(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010"), 2, "ab")
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_short)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { int a; uint b; bytes16 c; }
+ function f(S s) public pure returns (S q) {
+ q = s;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(
+ callContractFunction("f((int256,uint256,bytes16))", 0xff010, 0xff0002, "abcd"),
+ encodeArgs(0xff010, 0xff0002, "abcd")
+ );
+ ABI_CHECK(
+ callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(32, 0)),
+ encodeArgs(0xff010, 0xff0002, 0)
+ );
+ ABI_CHECK(
+ callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(31, 0)),
+ encodeArgs()
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_function)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { function () external returns (uint) f; uint b; }
+ function f(S s) public returns (uint, uint) {
+ return (s.f(), s.b);
+ }
+ function test() public returns (uint, uint) {
+ return this.f(S(this.g, 3));
+ }
+ function g() public returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(7, 3));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(empty_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { }
+ function f(uint a, S s, uint b) public pure returns (uint x, uint y) {
+ assembly { x := a y := b }
+ }
+ function g() public returns (uint, uint) {
+ return this.f(7, S(), 8);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f(uint256,(),uint256)", 7, 8), encodeArgs(7, 8));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(7, 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(mediocre_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { C c; }
+ function f(uint a, S[2] s1, uint b) public returns (uint r1, C r2, uint r3) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address)[2],uint256)";
+ ABI_CHECK(callContractFunction(sig,
+ 7, u256(u160(m_contractAddress)), 0, 8
+ ), encodeArgs(7, u256(u160(m_contractAddress)), 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(mediocre2_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { C c; uint[] x; }
+ function f(uint a, S[2] s1, uint b) public returns (uint r1, C r2, uint r3) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address,uint256[])[2],uint256)";
+ ABI_CHECK(callContractFunction(sig,
+ 7, 0x60, 8,
+ 0x40, 7 * 0x20,
+ u256(u160(m_contractAddress)), 0x40,
+ 2, 0x11, 0x12,
+ 0x99, 0x40,
+ 4, 0x31, 0x32, 0x34, 0x35
+ ), encodeArgs(7, u256(u160(m_contractAddress)), 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(complex_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E {A, B, C}
+ struct T { uint x; E e; uint8 y; }
+ struct S { C c; T[] t;}
+ function f(uint a, S[2] s1, S[] s2, uint b) public returns
+ (uint r1, C r2, uint r3, uint r4, C r5, uint r6, E r7, uint8 r8) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ r4 = s2.length;
+ r5 = s2[1].c;
+ r6 = s2[1].t.length;
+ r7 = s2[1].t[1].e;
+ r8 = s2[1].t[1].y;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address,(uint256,uint8,uint8)[])[2],(address,(uint256,uint8,uint8)[])[],uint256)";
+ bytes args = encodeArgs(
+ 7, 0x80, 0x1e0, 8,
+ // S[2] s1
+ 0x40,
+ 0x100,
+ // S s1[0]
+ u256(u160(m_contractAddress)),
+ 0x40,
+ // T s1[0].t
+ 1, // length
+ // s1[0].t[0]
+ 0x11, 1, 0x12,
+ // S s1[1]
+ 0, 0x40,
+ // T s1[1].t
+ 0,
+ // S[] s2 (0x1e0)
+ 2, // length
+ 0x40, 0xa0,
+ // S s2[0]
+ 0, 0x40, 0,
+ // S s2[1]
+ 0x1234, 0x40,
+ // s2[1].t
+ 3, // length
+ 0, 0, 0,
+ 0x21, 2, 0x22,
+ 0, 0, 0
+ );
+ ABI_CHECK(callContractFunction(sig, args), encodeArgs(7, u256(u160(m_contractAddress)), 8, 2, 0x1234, 3, 2, 0x22));
+ // invalid enum value
+ args.data()[0x20 * 28] = 3;
+ ABI_CHECK(callContractFunction(sig, args), encodeArgs());
+ )
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces
diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp
index af51edcc..49db9ce1 100644
--- a/test/libsolidity/ABIEncoderTests.cpp
+++ b/test/libsolidity/ABIEncoderTests.cpp
@@ -25,6 +25,8 @@
#include <libsolidity/interface/Exceptions.h>
#include <test/libsolidity/SolidityExecutionFramework.h>
+#include <test/libsolidity/ABITestsCommon.h>
+
using namespace std;
using namespace std::placeholders;
using namespace dev::test;
@@ -42,20 +44,6 @@ namespace test
BOOST_CHECK_EQUAL(toHex(m_logs[0].data), toHex(DATA)); \
} while (false)
-static string const NewEncoderPragma = "pragma experimental ABIEncoderV2;\n";
-
-#define NEW_ENCODER(CODE) \
-{ \
- sourceCode = NewEncoderPragma + sourceCode; \
- { CODE } \
-}
-
-#define BOTH_ENCODERS(CODE) \
-{ \
- { CODE } \
- NEW_ENCODER(CODE) \
-}
-
BOOST_FIXTURE_TEST_SUITE(ABIEncoderTest, SolidityExecutionFramework)
BOOST_AUTO_TEST_CASE(both_encoders_macro)
@@ -74,7 +62,7 @@ BOOST_AUTO_TEST_CASE(value_types)
string sourceCode = R"(
contract C {
event E(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool, C);
- function f() {
+ function f() public {
bytes6 x = hex"1bababababa2";
bool b;
assembly { b := 7 }
@@ -98,7 +86,7 @@ BOOST_AUTO_TEST_CASE(string_literal)
string sourceCode = R"(
contract C {
event E(string, bytes20, string);
- function f() {
+ function f() public {
E("abcdef", "abcde", "abcdefabcdefgehabcabcasdfjklabcdefabcedefghabcabcasdfjklabcdefabcdefghabcabcasdfjklabcdeefabcdefghabcabcasdefjklabcdefabcdefghabcabcasdfjkl");
}
}
@@ -120,7 +108,7 @@ BOOST_AUTO_TEST_CASE(enum_type_cleanup)
string sourceCode = R"(
contract C {
enum E { A, B }
- function f(uint x) returns (E en) {
+ function f(uint x) public returns (E en) {
assembly { en := x }
}
}
@@ -138,7 +126,7 @@ BOOST_AUTO_TEST_CASE(conversion)
string sourceCode = R"(
contract C {
event E(bytes4, bytes4, uint16, uint8, int16, int8);
- function f() {
+ function f() public {
bytes2 x; assembly { x := 0xf1f2f3f400000000000000000000000000000000000000000000000000000000 }
uint8 a;
uint16 b = 0x1ff;
@@ -164,7 +152,7 @@ BOOST_AUTO_TEST_CASE(memory_array_one_dim)
string sourceCode = R"(
contract C {
event E(uint a, int16[] b, uint c);
- function f() {
+ function f() public {
int16[] memory x = new int16[](3);
assembly {
for { let i := 0 } lt(i, 3) { i := add(i, 1) } {
@@ -191,7 +179,7 @@ BOOST_AUTO_TEST_CASE(memory_array_two_dim)
string sourceCode = R"(
contract C {
event E(uint a, int16[][2] b, uint c);
- function f() {
+ function f() public {
int16[][2] memory x;
x[0] = new int16[](3);
x[1] = new int16[](2);
@@ -216,7 +204,7 @@ BOOST_AUTO_TEST_CASE(memory_byte_array)
string sourceCode = R"(
contract C {
event E(uint a, bytes[] b, uint c);
- function f() {
+ function f() public {
bytes[] memory x = new bytes[](2);
x[0] = "abcabcdefghjklmnopqrsuvwabcdefgijklmnopqrstuwabcdefgijklmnoprstuvw";
x[1] = "abcdefghijklmnopqrtuvwabcfghijklmnopqstuvwabcdeghijklmopqrstuvw";
@@ -243,7 +231,7 @@ BOOST_AUTO_TEST_CASE(storage_byte_array)
bytes short;
bytes long;
event E(bytes s, bytes l);
- function f() {
+ function f() public {
short = "123456789012345678901234567890a";
long = "ffff123456789012345678901234567890afffffffff123456789012345678901234567890a";
E(short, long);
@@ -267,7 +255,7 @@ BOOST_AUTO_TEST_CASE(storage_array)
contract C {
address[3] addr;
event E(address[3] a);
- function f() {
+ function f() public {
assembly {
sstore(0, sub(0, 1))
sstore(1, sub(0, 2))
@@ -290,7 +278,7 @@ BOOST_AUTO_TEST_CASE(storage_array_dyn)
contract C {
address[] addr;
event E(address[] a);
- function f() {
+ function f() public {
addr.push(1);
addr.push(2);
addr.push(3);
@@ -311,7 +299,7 @@ BOOST_AUTO_TEST_CASE(storage_array_compact)
contract C {
int72[] x;
event E(int72[]);
- function f() {
+ function f() public {
x.push(-1);
x.push(2);
x.push(-3);
@@ -339,7 +327,7 @@ BOOST_AUTO_TEST_CASE(external_function)
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) {
+ function f(uint) public returns (uint) {
g = this.f;
E(this.f, g);
}
@@ -347,7 +335,7 @@ BOOST_AUTO_TEST_CASE(external_function)
)";
BOTH_ENCODERS(
compileAndRun(sourceCode);
- callContractFunction("f(uint256)");
+ callContractFunction("f(uint256)", u256(0));
string functionIdF = asString(m_contractAddress.ref()) + asString(FixedHash<4>(dev::keccak256("f(uint256)")).ref());
REQUIRE_LOG_DATA(encodeArgs(functionIdF, functionIdF));
)
@@ -360,7 +348,7 @@ BOOST_AUTO_TEST_CASE(external_function_cleanup)
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 f(uint) public 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);
@@ -369,7 +357,7 @@ BOOST_AUTO_TEST_CASE(external_function_cleanup)
)";
BOTH_ENCODERS(
compileAndRun(sourceCode);
- callContractFunction("f(uint256)");
+ callContractFunction("f(uint256)", u256(0));
REQUIRE_LOG_DATA(encodeArgs(string(24, char(-1)), string(24, char(-1))));
)
}
@@ -404,7 +392,7 @@ BOOST_AUTO_TEST_CASE(function_name_collision)
// and by the ABI encoder
string sourceCode = R"(
contract C {
- function f(uint x) returns (uint) {
+ function f(uint x) public returns (uint) {
assembly {
function abi_encode_t_uint256_to_t_uint256() {
mstore(0, 7)
@@ -432,7 +420,7 @@ BOOST_AUTO_TEST_CASE(structs)
struct T { uint64[2] x; }
S s;
event e(uint16, S);
- function f() returns (uint, S) {
+ function f() public returns (uint, S) {
uint16 x = 7;
s.a = 8;
s.b = 9;
diff --git a/test/libsolidity/ABITestsCommon.h b/test/libsolidity/ABITestsCommon.h
new file mode 100644
index 00000000..2ef555f3
--- /dev/null
+++ b/test/libsolidity/ABITestsCommon.h
@@ -0,0 +1,43 @@
+/*
+ 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/>.
+*/
+
+#include <string>
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+static std::string const NewEncoderPragma = "pragma experimental ABIEncoderV2;\n";
+
+#define NEW_ENCODER(CODE) \
+{ \
+ sourceCode = NewEncoderPragma + sourceCode; \
+ { CODE } \
+}
+
+#define BOTH_ENCODERS(CODE) \
+{ \
+ { CODE } \
+ NEW_ENCODER(CODE) \
+}
+
+}
+}
+} // end namespaces
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 358d3c72..59af6d41 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -86,23 +86,59 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
return AssemblyItems();
}
+void printAssemblyLocations(AssemblyItems const& _items)
+{
+ auto printRepeated = [](SourceLocation const& _loc, size_t _repetitions)
+ {
+ cout <<
+ "\t\tvector<SourceLocation>(" <<
+ _repetitions <<
+ ", SourceLocation(" <<
+ _loc.start <<
+ ", " <<
+ _loc.end <<
+ ", make_shared<string>(\"" <<
+ *_loc.sourceName <<
+ "\"))) +" << endl;
+ };
+
+ vector<SourceLocation> locations;
+ for (auto const& item: _items)
+ locations.push_back(item.location());
+ size_t repetitions = 0;
+ SourceLocation const* previousLoc = nullptr;
+ for (size_t i = 0; i < locations.size(); ++i)
+ {
+ SourceLocation& loc = locations[i];
+ if (previousLoc && *previousLoc == loc)
+ repetitions++;
+ else
+ {
+ if (previousLoc)
+ printRepeated(*previousLoc, repetitions);
+ previousLoc = &loc;
+ repetitions = 1;
+ }
+ }
+ if (previousLoc)
+ printRepeated(*previousLoc, repetitions);
+}
+
void checkAssemblyLocations(AssemblyItems const& _items, vector<SourceLocation> const& _locations)
{
BOOST_CHECK_EQUAL(_items.size(), _locations.size());
for (size_t i = 0; i < min(_items.size(), _locations.size()); ++i)
{
- 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));
+ if (_items[i].location() != _locations[i])
+ {
+ BOOST_CHECK_MESSAGE(false, "Location mismatch for item " + to_string(i) + ". Found the following locations:");
+ printAssemblyLocations(_items);
+ return;
+ }
}
}
+
} // end anonymous namespace
BOOST_AUTO_TEST_SUITE(Assembly)
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index e9fb8431..b09eb261 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -51,10 +51,11 @@ boost::optional<Error> parseAndReturnFirstError(
string const& _source,
bool _assemble = false,
bool _allowWarnings = true,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly,
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
)
{
- AssemblyStack stack;
+ AssemblyStack stack(_language);
bool success = false;
try
{
@@ -87,22 +88,29 @@ bool successParse(
string const& _source,
bool _assemble = false,
bool _allowWarnings = true,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly,
AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
)
{
- return !parseAndReturnFirstError(_source, _assemble, _allowWarnings, _machine);
+ return !parseAndReturnFirstError(_source, _assemble, _allowWarnings, _language, _machine);
}
-bool successAssemble(string const& _source, bool _allowWarnings = true)
+bool successAssemble(string const& _source, bool _allowWarnings = true, AssemblyStack::Language _language = AssemblyStack::Language::Assembly)
{
- return successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM) &&
- successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM15);
+ return
+ successParse(_source, true, _allowWarnings, _language, AssemblyStack::Machine::EVM) &&
+ successParse(_source, true, _allowWarnings, _language, AssemblyStack::Machine::EVM15);
}
-Error expectError(std::string const& _source, bool _assemble, bool _allowWarnings = false)
+Error expectError(
+ std::string const& _source,
+ bool _assemble,
+ bool _allowWarnings = false,
+ AssemblyStack::Language _language = AssemblyStack::Language::Assembly
+)
{
- auto error = parseAndReturnFirstError(_source, _assemble, _allowWarnings);
+ auto error = parseAndReturnFirstError(_source, _assemble, _allowWarnings, _language);
BOOST_REQUIRE(error);
return *error;
}
@@ -120,14 +128,17 @@ void parsePrintCompare(string const& _source, bool _canWarn = false)
}
-#define CHECK_ERROR(text, assemble, typ, substring, warnings) \
+#define CHECK_ERROR_LANG(text, assemble, typ, substring, warnings, language) \
do \
{ \
- Error err = expectError((text), (assemble), warnings); \
+ Error err = expectError((text), (assemble), warnings, (language)); \
BOOST_CHECK(err.type() == (Error::Type::typ)); \
BOOST_CHECK(searchErrorMessage(err, (substring))); \
} while(0)
+#define CHECK_ERROR(text, assemble, typ, substring, warnings) \
+CHECK_ERROR_LANG(text, assemble, typ, substring, warnings, AssemblyStack::Language::Assembly)
+
#define CHECK_PARSE_ERROR(text, type, substring) \
CHECK_ERROR(text, false, type, substring, false)
@@ -137,6 +148,14 @@ CHECK_ERROR(text, false, type, substring, false)
#define CHECK_ASSEMBLE_ERROR(text, type, substring) \
CHECK_ERROR(text, true, type, substring, false)
+#define CHECK_STRICT_ERROR(text, type, substring) \
+CHECK_ERROR_LANG(text, false, type, substring, false, AssemblyStack::Language::StrictAssembly)
+
+#define CHECK_STRICT_WARNING(text, type, substring) \
+CHECK_ERROR(text, false, type, substring, false, AssemblyStack::Language::StrictAssembly)
+
+#define SUCCESS_STRICT(text) \
+do { successParse((text), false, false, AssemblyStack::Language::StrictAssembly); } while (false)
BOOST_AUTO_TEST_SUITE(SolidityInlineAssembly)
@@ -266,7 +285,7 @@ BOOST_AUTO_TEST_CASE(if_statement_scope)
BOOST_AUTO_TEST_CASE(if_statement_invalid)
{
- CHECK_PARSE_ERROR("{ if calldatasize {}", ParserError, "Instructions are not supported as conditions for if");
+ CHECK_PARSE_ERROR("{ if mload {} }", ParserError, "Expected token \"(\"");
BOOST_CHECK("{ if calldatasize() {}");
CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected token LBrace");
@@ -296,7 +315,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
{
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
- CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch");
+ CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected token \"(\"");
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
}
@@ -332,7 +351,7 @@ BOOST_AUTO_TEST_CASE(for_invalid_expression)
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'");
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'");
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'");
- CHECK_PARSE_ERROR("{ for {} calldatasize {} {} }", ParserError, "Instructions are not supported as conditions for the for statement.");
+ CHECK_PARSE_ERROR("{ for {} mload {} {} }", ParserError, "Expected token \"(\"");
CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
}
@@ -455,6 +474,47 @@ BOOST_AUTO_TEST_CASE(multiple_assignment)
BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE(LooseStrictMode)
+
+BOOST_AUTO_TEST_CASE(no_opcodes_in_strict)
+{
+ BOOST_CHECK(successParse("{ pop(callvalue) }"));
+ BOOST_CHECK(successParse("{ callvalue pop }"));
+ CHECK_STRICT_ERROR("{ pop(callvalue) }", ParserError, "Non-functional instructions are not allowed in this context.");
+ CHECK_STRICT_ERROR("{ callvalue pop }", ParserError, "Call or assignment expected");
+ SUCCESS_STRICT("{ pop(callvalue()) }");
+ BOOST_CHECK(successParse("{ switch callvalue case 0 {} }"));
+ CHECK_STRICT_ERROR("{ switch callvalue case 0 {} }", ParserError, "Non-functional instructions are not allowed in this context.");
+}
+
+BOOST_AUTO_TEST_CASE(no_labels_in_strict)
+{
+ BOOST_CHECK(successParse("{ a: }"));
+ CHECK_STRICT_ERROR("{ a: }", ParserError, "Labels are not supported");
+}
+
+BOOST_AUTO_TEST_CASE(no_stack_assign_in_strict)
+{
+ BOOST_CHECK(successParse("{ let x 4 =: x }"));
+ CHECK_STRICT_ERROR("{ let x 4 =: x }", ParserError, "Call or assignment expected.");
+}
+
+BOOST_AUTO_TEST_CASE(no_dup_swap_in_strict)
+{
+ BOOST_CHECK(successParse("{ swap1 }"));
+ CHECK_STRICT_ERROR("{ swap1 }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ dup1 pop }"));
+ CHECK_STRICT_ERROR("{ dup1 pop }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ swap2 }"));
+ CHECK_STRICT_ERROR("{ swap2 }", ParserError, "Call or assignment expected.");
+ BOOST_CHECK(successParse("{ dup2 pop }"));
+ CHECK_STRICT_ERROR("{ dup2 pop }", ParserError, "Call or assignment expected.");
+ CHECK_PARSE_ERROR("{ switch dup1 case 0 {} }", ParserError, "Instruction \"dup1\" not allowed in this context");
+ CHECK_STRICT_ERROR("{ switch dup1 case 0 {} }", ParserError, "Instruction \"dup1\" not allowed in this context");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
BOOST_AUTO_TEST_SUITE(Printing)
BOOST_AUTO_TEST_CASE(print_smoke)
@@ -540,7 +600,7 @@ BOOST_AUTO_TEST_CASE(function_calls)
function g(a, b, c)
{
}
- g(1, mul(2, address), f(mul(2, caller)))
+ g(1, mul(2, address()), f(mul(2, caller())))
y()
})";
boost::replace_all(source, "\t", " ");
@@ -712,8 +772,9 @@ BOOST_AUTO_TEST_CASE(jump_warning)
{
CHECK_PARSE_WARNING("{ 1 jump }", Warning, "Jump instructions");
CHECK_PARSE_WARNING("{ 1 2 jumpi }", Warning, "Jump instructions");
- CHECK_PARSE_WARNING("{ a: jump(a) }", Warning, "Jump instructions");
- CHECK_PARSE_WARNING("{ a: jumpi(a, 2) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ jump(44) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ jumpi(44, 2) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ a: }", Warning, "Jump instructions");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp
index 7dc4808b..0c904c77 100644
--- a/test/libsolidity/JSONCompiler.cpp
+++ b/test/libsolidity/JSONCompiler.cpp
@@ -23,7 +23,7 @@
#include <boost/test/unit_test.hpp>
#include <libdevcore/JSON.h>
#include <libsolidity/interface/Version.h>
-#include <solc/jsonCompiler.h>
+#include <libsolc/libsolc.h>
#include "../Metadata.h"
#include "../TestHelper.h"
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index 667d666b..2a1609cc 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -94,6 +94,7 @@ BOOST_AUTO_TEST_CASE(warn_on_typecast)
BOOST_AUTO_TEST_CASE(warn_on_struct)
{
string text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct A { uint a; uint b; }
function f() public pure returns (A) {
@@ -167,9 +168,9 @@ BOOST_AUTO_TEST_CASE(function_call_does_not_clear_local_vars)
CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(branches_clear_variables)
+BOOST_AUTO_TEST_CASE(branches_merge_variables)
{
- // Only clears accessed variables
+ // Branch does not touch variable a
string text = R"(
contract C {
function f(uint x) public pure {
@@ -181,7 +182,7 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
- // It is just a plain clear and will not combine branches.
+ // Positive branch touches variable a, but assertion should still hold.
text = R"(
contract C {
function f(uint x) public pure {
@@ -193,8 +194,8 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
}
)";
- CHECK_WARNING(text, "Assertion violation happens here");
- // Clear also works on the else branch
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Negative branch touches variable a, but assertion should still hold.
text = R"(
contract C {
function f(uint x) public pure {
@@ -207,8 +208,8 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
}
)";
- CHECK_WARNING(text, "Assertion violation happens here");
- // Variable is not cleared, if it is only read.
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is not merged, if it is only read.
text = R"(
contract C {
function f(uint x) public pure {
@@ -223,6 +224,36 @@ BOOST_AUTO_TEST_CASE(branches_clear_variables)
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is reset in both branches
+ text = R"(
+ contract C {
+ function f(uint x) public pure {
+ uint a = 2;
+ if (x > 10) {
+ a = 3;
+ } else {
+ a = 3;
+ }
+ assert(a == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ // Variable is reset in both branches
+ text = R"(
+ contract C {
+ function f(uint x) public pure {
+ uint a = 2;
+ if (x > 10) {
+ a = 3;
+ } else {
+ a = 4;
+ }
+ assert(a >= 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
}
BOOST_AUTO_TEST_CASE(branches_assert_condition)
@@ -261,7 +292,7 @@ BOOST_AUTO_TEST_CASE(branches_assert_condition)
CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(ways_to_clear_variables)
+BOOST_AUTO_TEST_CASE(ways_to_merge_variables)
{
string text = R"(
contract C {
@@ -274,6 +305,7 @@ BOOST_AUTO_TEST_CASE(ways_to_clear_variables)
}
}
)";
+ CHECK_WARNING(text, "Assertion violation happens here");
text = R"(
contract C {
function f(uint x) public pure {
@@ -351,9 +383,9 @@ BOOST_AUTO_TEST_CASE(while_loop_simple)
// Check that side-effects of condition are taken into account
text = R"(
contract C {
- function f(uint x) public pure {
+ function f(uint x, uint y) public pure {
x = 7;
- while ((x = 5) > 0) {
+ while ((x = y) > 0) {
}
assert(x == 7);
}
@@ -458,6 +490,100 @@ BOOST_AUTO_TEST_CASE(for_loop)
CHECK_WARNING(text, "Assertion violation");
}
+BOOST_AUTO_TEST_CASE(division)
+{
+ string text = R"(
+ contract C {
+ function f(uint x, uint y) public pure returns (uint) {
+ return x / y;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Division by zero");
+ text = R"(
+ contract C {
+ function f(uint x, uint y) public pure returns (uint) {
+ require(y != 0);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure returns (int) {
+ require(y != 0);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Overflow");
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure returns (int) {
+ require(y != 0);
+ require(y != -1);
+ return x / y;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(division_truncates_correctly)
+{
+ string text = R"(
+ contract C {
+ function f(uint x, uint y) public pure {
+ x = 7;
+ y = 2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = 7;
+ y = 2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = -7;
+ y = 2;
+ assert(x / y == -3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = 7;
+ y = -2;
+ assert(x / y == -3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f(int x, int y) public pure {
+ x = -7;
+ y = -2;
+ assert(x / y == 3);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 33962730..26bfb6d0 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -942,6 +942,7 @@ BOOST_AUTO_TEST_CASE(function_type)
BOOST_AUTO_TEST_CASE(return_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; T[] sub; }
struct T { uint[2] x; }
@@ -991,6 +992,7 @@ BOOST_AUTO_TEST_CASE(return_structs)
BOOST_AUTO_TEST_CASE(return_structs_with_contracts)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { C[] x; C y; }
function f() returns (S s, C c) {
@@ -1090,6 +1092,7 @@ BOOST_AUTO_TEST_CASE(event_structs)
BOOST_AUTO_TEST_CASE(structs_in_libraries)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library L {
struct S { uint a; T[] sub; bytes b; }
struct T { uint[2] x; }
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 05dc9ba3..f5f7e64a 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2971,7 +2971,7 @@ BOOST_AUTO_TEST_CASE(event_no_arguments)
{
char const* sourceCode = R"(
contract ClientReceipt {
- event Deposit;
+ event Deposit();
function deposit() {
Deposit();
}
@@ -3013,7 +3013,7 @@ BOOST_AUTO_TEST_CASE(events_with_same_name)
{
char const* sourceCode = R"(
contract ClientReceipt {
- event Deposit;
+ event Deposit();
event Deposit(address _addr);
event Deposit(address _addr, uint _amount);
function deposit() returns (uint) {
@@ -3059,7 +3059,7 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited)
{
char const* sourceCode = R"(
contract A {
- event Deposit;
+ event Deposit();
}
contract B {
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 97d359e8..eb6a440e 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -602,6 +602,7 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
BOOST_AUTO_TEST_CASE(external_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract Test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
struct Empty {}
@@ -629,6 +630,7 @@ BOOST_AUTO_TEST_CASE(external_structs)
BOOST_AUTO_TEST_CASE(external_structs_in_libraries)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library Test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
struct Empty {}
@@ -2107,7 +2109,7 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
function f(uint a) public { uint8[a] x; }
}
)";
- CHECK_ERROR(text, TypeError, "Identifier must be declared constant.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_with_negative_length)
@@ -3511,6 +3513,7 @@ BOOST_AUTO_TEST_CASE(using_for_not_used)
BOOST_AUTO_TEST_CASE(library_memory_struct)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
library c {
struct S { uint x; }
function f() public returns (S ) {}
@@ -3605,6 +3608,20 @@ BOOST_AUTO_TEST_CASE(invalid_args_creating_memory_array)
CHECK_ERROR(text, TypeError, "Wrong argument count for function call: 0 arguments given but expected 1.");
}
+BOOST_AUTO_TEST_CASE(invalid_args_creating_struct)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+
+ function f() public {
+ var s = S({a: 1});
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Wrong argument count for struct constructor: 1 arguments given but expected 2.");
+}
+
BOOST_AUTO_TEST_CASE(function_overload_array_type)
{
char const* text = R"(
@@ -4395,7 +4412,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
@@ -4407,7 +4424,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion)
@@ -5696,6 +5713,7 @@ BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
BOOST_AUTO_TEST_CASE(return_structs)
{
char const* text = R"(
+ pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; T[] sub; }
struct T { uint[] x; }
@@ -7250,7 +7268,7 @@ BOOST_AUTO_TEST_CASE(array_length_too_large)
uint[8**90] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
@@ -7260,7 +7278,7 @@ BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
uint[true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_constant_var)
@@ -7282,7 +7300,7 @@ BOOST_AUTO_TEST_CASE(array_length_non_integer_constant_var)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
@@ -7293,7 +7311,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function)
uint[f] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_can_be_recursive_constant)
@@ -7317,7 +7335,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_function_call)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_const_cannot_be_fractional)
@@ -7366,7 +7384,7 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_constant_function_parameter)
}
}
)";
- CHECK_ERROR(text, TypeError, "Constant identifier declaration must have a constant value.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_with_cyclic_constant)
@@ -7405,7 +7423,7 @@ BOOST_AUTO_TEST_CASE(array_length_with_pure_functions)
uint[LEN] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
}
BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
@@ -7415,25 +7433,25 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
uint[-true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[true/1] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[1/true] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[1.111111E1111111111111] ids;
}
)";
- CHECK_ERROR(text, TypeError, "Invalid literal value.");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal or constant expression.");
text = R"(
contract C {
uint[3/0] ids;
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 72473c3e..861e6408 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -960,6 +960,16 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
BOOST_CHECK(successParse(text));
}
+BOOST_AUTO_TEST_CASE(event_with_no_argument_list_fails)
+{
+ char const* text = R"(
+ contract c {
+ event e;
+ }
+ )";
+ CHECK_PARSE_ERROR(text, "Expected token LParen got 'Semicolon'");
+}
+
BOOST_AUTO_TEST_CASE(visibility_specifiers)
{
char const* text = R"(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 4504946b..e48624e5 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -179,6 +179,14 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
"fileA": {
"content": "contract A { }"
}
+ },
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "metadata" ],
+ "": [ "legacyAST" ]
+ }
+ }
}
}
)";
@@ -226,6 +234,46 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
);
}
+BOOST_AUTO_TEST_CASE(compilation_error)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { function }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(result.isMember("errors"));
+ BOOST_CHECK(result["errors"].size() >= 1);
+ for (auto const& error: result["errors"])
+ {
+ BOOST_REQUIRE(error.isObject());
+ BOOST_REQUIRE(error["message"].isString());
+ if (error["message"].asString().find("pre-release compiler") == string::npos)
+ {
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(error),
+ "{\"component\":\"general\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier, got 'RBrace'\\n"
+ "contract A { function }\\n ^\\n\",\"message\":\"Expected identifier, got 'RBrace'\","
+ "\"severity\":\"error\",\"sourceLocation\":{\"end\":22,\"file\":\"fileA\",\"start\":22},\"type\":\"ParserError\"}"
+ );
+ }
+ }
+}
+
BOOST_AUTO_TEST_CASE(output_selection_explicit)
{
char const* input = R"(
@@ -403,6 +451,71 @@ BOOST_AUTO_TEST_CASE(output_selection_dependent_contract_with_import)
BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
}
+BOOST_AUTO_TEST_CASE(filename_with_colon)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "http://github.com/ethereum/solidity/std/StandardToken.sol": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "http://github.com/ethereum/solidity/std/StandardToken.sol": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "http://github.com/ethereum/solidity/std/StandardToken.sol", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(library_filename_with_colon)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "evm.bytecode"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "import \"git:library.sol\"; contract A { function f() returns (uint) { return L.g(); } }"
+ },
+ "git:library.sol": {
+ "content": "library L { function g() returns (uint) { return 1; } }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"].isObject());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"].isArray());
+ BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"][0].isObject());
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}