mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6120 from ethereum/soltest-hex-strings
[soltest] Add support for hex string literals
This commit is contained in:
commit
2896d6176b
@ -70,6 +70,7 @@ Bugfixes:
|
||||
|
||||
Build System:
|
||||
* Soltest: Add support for left-aligned, padded hex literals.
|
||||
* Soltest: Add support for left-aligned, unpadded hex string literals.
|
||||
* Soltest: Add support for right-aligned, padded boolean literals.
|
||||
|
||||
### 0.5.4 (2019-02-12)
|
||||
|
@ -17,6 +17,9 @@ contract C {
|
||||
function k(bytes32 b) public returns (bytes32) {
|
||||
return b;
|
||||
}
|
||||
function s() public returns (uint256) {
|
||||
return msg.data.length;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> 2
|
||||
@ -25,3 +28,4 @@ contract C {
|
||||
// i() -> FAILURE
|
||||
// j(bool): true -> false
|
||||
// k(bytes32): 0x31 -> 0x31
|
||||
// s(): hex"4200ef" -> 7
|
||||
|
@ -284,6 +284,17 @@ tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
||||
rawString += parsed;
|
||||
result = applyAlign(alignment, abiType, convertHexNumber(parsed));
|
||||
}
|
||||
else if (accept(Token::Hex, true))
|
||||
{
|
||||
if (isSigned)
|
||||
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
|
||||
if (alignment != DeclaredAlignment::None)
|
||||
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
||||
string parsed = parseHexNumber();
|
||||
rawString += parsed;
|
||||
result = convertHexString(parsed);
|
||||
abiType = ABIType{ABIType::HexString, ABIType::AlignNone, result.size()};
|
||||
}
|
||||
else if (accept(Token::Number))
|
||||
{
|
||||
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
||||
@ -310,7 +321,7 @@ tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
throw Error(Error::Type::ParserError, "Number encoding invalid.");
|
||||
throw Error(Error::Type::ParserError, "Literal encoding invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,6 +436,21 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
|
||||
}
|
||||
}
|
||||
|
||||
bytes TestFileParser::convertHexString(string const& _literal)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_literal.size() % 2)
|
||||
throw Error(Error::Type::ParserError, "Hex string encoding invalid.");
|
||||
else
|
||||
return fromHex(_literal);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
throw Error(Error::Type::ParserError, "Hex string encoding invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
void TestFileParser::Scanner::readStream(istream& _stream)
|
||||
{
|
||||
std::string line;
|
||||
@ -435,6 +461,8 @@ void TestFileParser::Scanner::readStream(istream& _stream)
|
||||
|
||||
void TestFileParser::Scanner::scanNextToken()
|
||||
{
|
||||
using namespace langutil;
|
||||
|
||||
// Make code coverage happy.
|
||||
assert(formatToken(Token::NUM_TOKENS) == "");
|
||||
|
||||
@ -444,6 +472,7 @@ void TestFileParser::Scanner::scanNextToken()
|
||||
if (_literal == "ether") return TokenDesc{Token::Ether, _literal};
|
||||
if (_literal == "left") return TokenDesc{Token::Left, _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};
|
||||
return TokenDesc{Token::Identifier, _literal};
|
||||
};
|
||||
@ -495,13 +524,18 @@ void TestFileParser::Scanner::scanNextToken()
|
||||
case ']':
|
||||
token = selectToken(Token::RBrack);
|
||||
break;
|
||||
case '\"':
|
||||
advance();
|
||||
token = selectToken(Token::HexNumber, scanHexNumber());
|
||||
advance();
|
||||
break;
|
||||
default:
|
||||
if (langutil::isIdentifierStart(current()))
|
||||
if (isIdentifierStart(current()))
|
||||
{
|
||||
TokenDesc detectedToken = detectKeyword(scanIdentifierOrKeyword());
|
||||
token = selectToken(detectedToken.first, detectedToken.second);
|
||||
}
|
||||
else if (langutil::isDecimalDigit(current()))
|
||||
else if (isDecimalDigit(current()))
|
||||
{
|
||||
if (current() == '0' && peek() == 'x')
|
||||
{
|
||||
@ -512,7 +546,7 @@ void TestFileParser::Scanner::scanNextToken()
|
||||
else
|
||||
token = selectToken(Token::Number, scanDecimalNumber());
|
||||
}
|
||||
else if (langutil::isWhiteSpace(current()))
|
||||
else if (isWhiteSpace(current()))
|
||||
token = selectToken(Token::Whitespace);
|
||||
else if (isEndOfLine())
|
||||
token = selectToken(Token::EOS);
|
||||
|
@ -60,6 +60,7 @@ namespace test
|
||||
T(Identifier, "identifier", 0) \
|
||||
/* type keywords */ \
|
||||
K(Ether, "ether", 0) \
|
||||
K(Hex, "hex", 0) \
|
||||
K(Boolean, "boolean", 0) \
|
||||
/* special keywords */ \
|
||||
K(Left, "left", 0) \
|
||||
@ -108,6 +109,7 @@ struct ABIType
|
||||
SignedDec,
|
||||
Boolean,
|
||||
Hex,
|
||||
HexString,
|
||||
Failure,
|
||||
None
|
||||
};
|
||||
@ -385,6 +387,10 @@ private:
|
||||
/// representation of the hex literal. Throws if conversion fails.
|
||||
bytes convertHexNumber(std::string const& _literal);
|
||||
|
||||
/// Tries to convert \param _literal to left-aligned, unpadded `bytes`
|
||||
/// representation of the hex string literal. Throws if conversion fails.
|
||||
bytes convertHexString(std::string const& _literal);
|
||||
|
||||
/// A scanner instance
|
||||
Scanner m_scanner;
|
||||
};
|
||||
|
@ -310,6 +310,40 @@ BOOST_AUTO_TEST_CASE(call_arguments_bool)
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_hex_string)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f(bytes): hex"4200ef" -> hex"ab0023"
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"f(bytes)",
|
||||
false,
|
||||
fromHex("4200ef"),
|
||||
fromHex("ab0023")
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_hex_string_lowercase)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f(bytes): hex"4200ef" -> hex"23ef00"
|
||||
)";
|
||||
auto const calls = parse(source);
|
||||
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||
testFunctionCall(
|
||||
calls.at(0),
|
||||
Mode::SingleLine,
|
||||
"f(bytes)",
|
||||
false,
|
||||
fromHex("4200EF"),
|
||||
fromHex("23EF00")
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_tuple)
|
||||
{
|
||||
char const* source = R"(
|
||||
@ -564,6 +598,22 @@ BOOST_AUTO_TEST_CASE(call_builtin_right_decimal)
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_hex_string_left_align)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f(bytes): left(hex"4200ef") ->
|
||||
)";
|
||||
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_arguments_hex_string_right_align)
|
||||
{
|
||||
char const* source = R"(
|
||||
// f(bytes): right(hex"4200ef") ->
|
||||
)";
|
||||
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_newline_invalid)
|
||||
{
|
||||
char const* source = R"(
|
||||
|
@ -164,6 +164,9 @@ string TestFunctionCall::formatBytesParameters(bytes const& _bytes, dev::solidit
|
||||
case ABIType::Hex:
|
||||
resultStream << toHex(byteRange, HexPrefix::Add);
|
||||
break;
|
||||
case ABIType::HexString:
|
||||
resultStream << "hex\"" << toHex(byteRange) << "\"";
|
||||
break;
|
||||
case ABIType::Failure:
|
||||
break;
|
||||
case ABIType::None:
|
||||
|
@ -138,6 +138,19 @@ BOOST_AUTO_TEST_CASE(format_hex_singleline)
|
||||
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(bytes32): 0x31 -> 0x3200000000000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(format_hex_string_singleline)
|
||||
{
|
||||
bytes expectedBytes = fromHex("4200ef");
|
||||
ABIType abiType{ABIType::HexString, ABIType::AlignLeft, 3};
|
||||
Parameter param{expectedBytes, "hex\"4200ef\"", abiType, FormatInfo{}};
|
||||
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
||||
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
||||
FunctionCall call{"f(string)", 0, arguments, expectations};
|
||||
TestFunctionCall test{call};
|
||||
|
||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(string): hex\"4200ef\" -> hex\"4200ef\"");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(format_bool_true_singleline)
|
||||
{
|
||||
bytes expectedBytes = toBigEndian(u256{true});
|
||||
|
Loading…
Reference in New Issue
Block a user