mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[isoltest] Adds support for fallback and ether functions.
This commit is contained in:
parent
02af613fa5
commit
e92b921123
@ -92,6 +92,12 @@ public:
|
|||||||
return callFallbackWithValue(0);
|
return callFallbackWithValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes const& callLowLevel(bytes const& _data, u256 const& _value)
|
||||||
|
{
|
||||||
|
sendMessage(_data, false, _value);
|
||||||
|
return m_output;
|
||||||
|
}
|
||||||
|
|
||||||
bytes const& callContractFunctionWithValueNoEncoding(std::string _sig, u256 const& _value, bytes const& _arguments)
|
bytes const& callContractFunctionWithValueNoEncoding(std::string _sig, u256 const& _value, bytes const& _arguments)
|
||||||
{
|
{
|
||||||
FixedHash<4> hash(dev::keccak256(_sig));
|
FixedHash<4> hash(dev::keccak256(_sig));
|
||||||
|
@ -98,11 +98,13 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bytes output = callContractFunctionWithValueNoEncoding(
|
bytes output = test.call().useCallWithoutSignature ?
|
||||||
test.call().signature,
|
callLowLevel(test.call().arguments.rawBytes(), test.call().value) :
|
||||||
test.call().value,
|
callContractFunctionWithValueNoEncoding(
|
||||||
test.call().arguments.rawBytes()
|
test.call().signature,
|
||||||
);
|
test.call().value,
|
||||||
|
test.call().arguments.rawBytes()
|
||||||
|
);
|
||||||
|
|
||||||
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
|
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -2514,23 +2514,6 @@ BOOST_AUTO_TEST_CASE(super_alone)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(fallback_function)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract A {
|
|
||||||
uint data;
|
|
||||||
function() external { data = 1; }
|
|
||||||
function getData() public returns (uint r) { return data; }
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
ALSO_VIA_YUL(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("getData()"), encodeArgs(0));
|
|
||||||
ABI_CHECK(callContractFunction(""), encodeArgs());
|
|
||||||
ABI_CHECK(callContractFunction("getData()"), encodeArgs(1));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(inherited_fallback_function)
|
BOOST_AUTO_TEST_CASE(inherited_fallback_function)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
23
test/libsolidity/semanticTests/smoke/fallback.sol
Normal file
23
test/libsolidity/semanticTests/smoke/fallback.sol
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
contract A {
|
||||||
|
uint public data;
|
||||||
|
uint public balance;
|
||||||
|
bytes public externalData;
|
||||||
|
function() external payable {
|
||||||
|
data += 1;
|
||||||
|
balance = msg.value;
|
||||||
|
externalData = msg.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// data() -> 0
|
||||||
|
// ()
|
||||||
|
// data() -> 1
|
||||||
|
// (): hex"42ef"
|
||||||
|
// data() -> 2
|
||||||
|
// externalData() -> 0x20, 2, left(0x42ef)
|
||||||
|
// balance() -> 0
|
||||||
|
// (), 1 ether
|
||||||
|
// balance() -> 1
|
||||||
|
// (), 2 ether: hex"fefe"
|
||||||
|
// balance() -> 2
|
||||||
|
// externalData() -> 0x20, 2, left(0xfefe)
|
@ -262,6 +262,9 @@ struct FunctionCall
|
|||||||
DisplayMode displayMode = DisplayMode::SingleLine;
|
DisplayMode displayMode = DisplayMode::SingleLine;
|
||||||
/// Marks this function call as the constructor.
|
/// Marks this function call as the constructor.
|
||||||
bool isConstructor = false;
|
bool isConstructor = false;
|
||||||
|
/// If this function call's signature has no name and no arguments,
|
||||||
|
/// a low-level call with unstructured calldata will be issued.
|
||||||
|
bool useCallWithoutSignature = false;
|
||||||
/// Marks this function call as "short-handed", meaning
|
/// Marks this function call as "short-handed", meaning
|
||||||
/// no `->` declared.
|
/// no `->` declared.
|
||||||
bool omitsArrow = true;
|
bool omitsArrow = true;
|
||||||
|
@ -75,7 +75,7 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls(siz
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
call.signature = parseFunctionSignature();
|
tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature();
|
||||||
if (accept(Token::Comma, true))
|
if (accept(Token::Comma, true))
|
||||||
call.value = parseFunctionCallValue();
|
call.value = parseFunctionCallValue();
|
||||||
if (accept(Token::Colon, true))
|
if (accept(Token::Colon, true))
|
||||||
@ -148,10 +148,17 @@ bool TestFileParser::expect(soltest::Token _token, bool const _advance)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string TestFileParser::parseFunctionSignature()
|
pair<string, bool> TestFileParser::parseFunctionSignature()
|
||||||
{
|
{
|
||||||
string signature = m_scanner.currentLiteral();
|
string signature;
|
||||||
expect(Token::Identifier);
|
bool hasName = false;
|
||||||
|
|
||||||
|
if (accept(Token::Identifier, false))
|
||||||
|
{
|
||||||
|
hasName = true;
|
||||||
|
signature = m_scanner.currentLiteral();
|
||||||
|
expect(Token::Identifier);
|
||||||
|
}
|
||||||
|
|
||||||
signature += formatToken(Token::LParen);
|
signature += formatToken(Token::LParen);
|
||||||
expect(Token::LParen);
|
expect(Token::LParen);
|
||||||
@ -169,11 +176,15 @@ string TestFileParser::parseFunctionSignature()
|
|||||||
if (accept(Token::Arrow, true))
|
if (accept(Token::Arrow, true))
|
||||||
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature);
|
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature);
|
||||||
|
|
||||||
signature += parameters;
|
if (!hasName && !parameters.empty())
|
||||||
|
throw Error(Error::Type::ParserError, "Signatures without a name cannot have parameters: " + signature);
|
||||||
|
else
|
||||||
|
signature += parameters;
|
||||||
|
|
||||||
expect(Token::RParen);
|
expect(Token::RParen);
|
||||||
signature += formatToken(Token::RParen);
|
signature += formatToken(Token::RParen);
|
||||||
return signature;
|
|
||||||
|
return {signature, !hasName};
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 TestFileParser::parseFunctionCallValue()
|
u256 TestFileParser::parseFunctionCallValue()
|
||||||
|
@ -46,6 +46,8 @@ namespace test
|
|||||||
* // -> 2, 3
|
* // -> 2, 3
|
||||||
* // h(uint256), 1 ether: 42
|
* // h(uint256), 1 ether: 42
|
||||||
* // -> FAILURE # If REVERT or other EVM failure was detected #
|
* // -> FAILURE # If REVERT or other EVM failure was detected #
|
||||||
|
* // () # Call fallback function #
|
||||||
|
* // (), 1 ether # Call ether function #
|
||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
class TestFileParser
|
class TestFileParser
|
||||||
@ -128,8 +130,10 @@ private:
|
|||||||
bool accept(soltest::Token _token, bool const _expect = false);
|
bool accept(soltest::Token _token, bool const _expect = false);
|
||||||
bool expect(soltest::Token _token, bool const _advance = true);
|
bool expect(soltest::Token _token, bool const _advance = true);
|
||||||
|
|
||||||
/// Parses a function call signature in the form of f(uint256, ...).
|
/// Parses a function call signature in the form of `f(uint256, ...)` and
|
||||||
std::string parseFunctionSignature();
|
/// returns the signature and a flag that indicates if the function name was
|
||||||
|
/// empty. If so, the signature is not allowed to define any parameters.
|
||||||
|
std::pair<std::string, bool> parseFunctionSignature();
|
||||||
|
|
||||||
/// Parses the optional ether value that can be passed alongside the
|
/// Parses the optional ether value that can be passed alongside the
|
||||||
/// function call arguments. Throws an InvalidEtherValueEncoding exception
|
/// function call arguments. Throws an InvalidEtherValueEncoding exception
|
||||||
|
Loading…
Reference in New Issue
Block a user