mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7696 from ethereum/semanticsTestsLibraryDeployment
Add support for external libraries to extracted semantics tests.
This commit is contained in:
commit
a7e133b95c
@ -78,15 +78,34 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
|
||||
for (auto& test: m_tests)
|
||||
test.reset();
|
||||
|
||||
map<string, dev::test::Address> libraries;
|
||||
|
||||
bool constructed = false;
|
||||
|
||||
for (auto& test: m_tests)
|
||||
{
|
||||
if (&test == &m_tests.front())
|
||||
if (test.call().isConstructor)
|
||||
deploy("", test.call().value, test.call().arguments.rawBytes());
|
||||
else
|
||||
soltestAssert(deploy("", 0, bytes()), "Failed to deploy contract.");
|
||||
if (constructed)
|
||||
{
|
||||
soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call.");
|
||||
soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments.");
|
||||
}
|
||||
else if (test.call().isLibrary)
|
||||
{
|
||||
soltestAssert(
|
||||
deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful,
|
||||
"Failed to deploy library " + test.call().signature
|
||||
);
|
||||
libraries[test.call().signature] = m_contractAddress;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call.");
|
||||
{
|
||||
if (test.call().isConstructor)
|
||||
deploy("", test.call().value, test.call().arguments.rawBytes(), libraries);
|
||||
else
|
||||
soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract.");
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
if (test.call().isConstructor)
|
||||
{
|
||||
@ -171,8 +190,8 @@ void SemanticTest::parseExpectations(istream& _stream)
|
||||
std::move(functionCalls.begin(), functionCalls.end(), back_inserter(m_tests));
|
||||
}
|
||||
|
||||
bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments)
|
||||
bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments, map<string, dev::test::Address> const& _libraries)
|
||||
{
|
||||
auto output = compileAndRunWithoutCheck(m_source, _value, _contractName, _arguments);
|
||||
auto output = compileAndRunWithoutCheck(m_source, _value, _contractName, _arguments, _libraries);
|
||||
return !output.empty() && m_transactionSuccessful;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
|
||||
/// Compiles and deploys currently held source.
|
||||
/// Returns true if deployment was successful, false otherwise.
|
||||
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments);
|
||||
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, dev::test::Address> const& _libraries = {});
|
||||
|
||||
private:
|
||||
std::string m_source;
|
||||
|
13
test/libsolidity/semanticTests/libraries/stub.sol
Normal file
13
test/libsolidity/semanticTests/libraries/stub.sol
Normal file
@ -0,0 +1,13 @@
|
||||
library L {
|
||||
function f(uint256 v) external returns (uint256) { return v*v; }
|
||||
}
|
||||
contract C {
|
||||
function g(uint256 v) external returns (uint256) {
|
||||
return L.f(v);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// library: L
|
||||
// g(uint256): 1 -> 1
|
||||
// g(uint256): 2 -> 4
|
||||
// g(uint256): 4 -> 16
|
12
test/libsolidity/semanticTests/libraries/stub_internal.sol
Normal file
12
test/libsolidity/semanticTests/libraries/stub_internal.sol
Normal file
@ -0,0 +1,12 @@
|
||||
library L {
|
||||
function f(uint256 v) internal returns (uint256) { return v*v; }
|
||||
}
|
||||
contract C {
|
||||
function g(uint256 v) external returns (uint256) {
|
||||
return L.f(v);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// g(uint256): 1 -> 1
|
||||
// g(uint256): 2 -> 4
|
||||
// g(uint256): 4 -> 16
|
@ -58,6 +58,7 @@ namespace test
|
||||
K(Boolean, "boolean", 0) \
|
||||
/* special keywords */ \
|
||||
K(Left, "left", 0) \
|
||||
K(Library, "library", 0) \
|
||||
K(Right, "right", 0) \
|
||||
K(Failure, "FAILURE", 0) \
|
||||
|
||||
@ -268,6 +269,8 @@ struct FunctionCall
|
||||
/// Marks this function call as "short-handed", meaning
|
||||
/// no `->` declared.
|
||||
bool omitsArrow = true;
|
||||
/// Marks a library deployment call.
|
||||
bool isLibrary = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -75,44 +75,56 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls(siz
|
||||
|
||||
try
|
||||
{
|
||||
tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature();
|
||||
if (accept(Token::Comma, true))
|
||||
call.value = parseFunctionCallValue();
|
||||
if (accept(Token::Colon, true))
|
||||
call.arguments = parseFunctionCallArguments();
|
||||
|
||||
if (accept(Token::Newline, true))
|
||||
if (accept(Token::Library, true))
|
||||
{
|
||||
call.displayMode = FunctionCall::DisplayMode::MultiLine;
|
||||
m_lineNumber++;
|
||||
}
|
||||
|
||||
call.arguments.comment = parseComment();
|
||||
|
||||
if (accept(Token::Newline, true))
|
||||
{
|
||||
call.displayMode = FunctionCall::DisplayMode::MultiLine;
|
||||
m_lineNumber++;
|
||||
}
|
||||
|
||||
if (accept(Token::Arrow, true))
|
||||
{
|
||||
call.omitsArrow = false;
|
||||
call.expectations = parseFunctionCallExpectations();
|
||||
if (accept(Token::Newline, true))
|
||||
m_lineNumber++;
|
||||
expect(Token::Colon);
|
||||
call.signature = m_scanner.currentLiteral();
|
||||
expect(Token::Identifier);
|
||||
call.isLibrary = true;
|
||||
call.expectations.failure = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
call.expectations.failure = false;
|
||||
call.displayMode = FunctionCall::DisplayMode::SingleLine;
|
||||
tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature();
|
||||
if (accept(Token::Comma, true))
|
||||
call.value = parseFunctionCallValue();
|
||||
if (accept(Token::Colon, true))
|
||||
call.arguments = parseFunctionCallArguments();
|
||||
|
||||
if (accept(Token::Newline, true))
|
||||
{
|
||||
call.displayMode = FunctionCall::DisplayMode::MultiLine;
|
||||
m_lineNumber++;
|
||||
}
|
||||
|
||||
call.arguments.comment = parseComment();
|
||||
|
||||
if (accept(Token::Newline, true))
|
||||
{
|
||||
call.displayMode = FunctionCall::DisplayMode::MultiLine;
|
||||
m_lineNumber++;
|
||||
}
|
||||
|
||||
if (accept(Token::Arrow, true))
|
||||
{
|
||||
call.omitsArrow = false;
|
||||
call.expectations = parseFunctionCallExpectations();
|
||||
if (accept(Token::Newline, true))
|
||||
m_lineNumber++;
|
||||
}
|
||||
else
|
||||
{
|
||||
call.expectations.failure = false;
|
||||
call.displayMode = FunctionCall::DisplayMode::SingleLine;
|
||||
}
|
||||
|
||||
call.expectations.comment = parseComment();
|
||||
|
||||
if (call.signature == "constructor()")
|
||||
call.isConstructor = true;
|
||||
|
||||
}
|
||||
|
||||
call.expectations.comment = parseComment();
|
||||
|
||||
if (call.signature == "constructor()")
|
||||
call.isConstructor = true;
|
||||
|
||||
calls.emplace_back(std::move(call));
|
||||
}
|
||||
catch (Error const& _e)
|
||||
@ -456,6 +468,7 @@ void TestFileParser::Scanner::scanNextToken()
|
||||
if (_literal == "false") return TokenDesc{Token::Boolean, _literal};
|
||||
if (_literal == "ether") return TokenDesc{Token::Ether, _literal};
|
||||
if (_literal == "left") return TokenDesc{Token::Left, _literal};
|
||||
if (_literal == "library") return TokenDesc{Token::Library, _literal};
|
||||
if (_literal == "right") return TokenDesc{Token::Right, _literal};
|
||||
if (_literal == "hex") return TokenDesc{Token::Hex, _literal};
|
||||
if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal};
|
||||
|
@ -57,7 +57,9 @@ void testFunctionCall(
|
||||
u256 _value = 0,
|
||||
string _argumentComment = "",
|
||||
string _expectationComment = "",
|
||||
vector<string> _rawArguments = vector<string>{}
|
||||
vector<string> _rawArguments = vector<string>{},
|
||||
bool _isConstructor = false,
|
||||
bool _isLibrary = false
|
||||
)
|
||||
{
|
||||
BOOST_REQUIRE_EQUAL(_call.expectations.failure, _failure);
|
||||
@ -79,6 +81,9 @@ void testFunctionCall(
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_REQUIRE_EQUAL(_call.isConstructor, _isConstructor);
|
||||
BOOST_REQUIRE_EQUAL(_call.isLibrary, _isLibrary);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(TestFileParserTest)
|
||||
@ -883,6 +888,51 @@ BOOST_AUTO_TEST_CASE(call_unexpected_character)
|
||||
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor)
|
||||
{
|
||||
char const* source = R"(
|
||||
// constructor()
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"constructor()",
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
{},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(library)
|
||||
{
|
||||
char const* source = R"(
|
||||
// library: L
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"L",
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
{},
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -55,6 +55,12 @@ string TestFunctionCall::format(
|
||||
string newline = formatToken(Token::Newline);
|
||||
string failure = formatToken(Token::Failure);
|
||||
|
||||
if (m_call.isLibrary)
|
||||
{
|
||||
stream << _linePrefix << newline << ws << "library:" << ws << m_call.signature;
|
||||
return;
|
||||
}
|
||||
|
||||
/// Formats the function signature. This is the same independent from the display-mode.
|
||||
stream << _linePrefix << newline << ws << m_call.signature;
|
||||
if (m_call.value > u256(0))
|
||||
|
Loading…
Reference in New Issue
Block a user