mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Right-aligns hex numbers and introduces alignment built-ins.
This commit is contained in:
parent
eb5bde95b3
commit
a40fbf0fc4
@ -75,12 +75,12 @@ bool SemanticTest::run(ostream& _stream, string const& _linePrefix, bool const _
|
|||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
|
||||||
for (auto const& test: m_tests)
|
for (auto const& test: m_tests)
|
||||||
_stream << test.format(_linePrefix, false, _formatted) << endl;
|
_stream << test.format(_linePrefix, false, _formatted) << endl;
|
||||||
|
_stream << endl;
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
|
||||||
for (auto const& test: m_tests)
|
for (auto const& test: m_tests)
|
||||||
_stream << test.format(_linePrefix, true, _formatted) << endl;
|
_stream << test.format(_linePrefix, true, _formatted) << endl;
|
||||||
|
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix
|
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix
|
||||||
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
|
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public returns (uint) {
|
function f() public returns (uint) {
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
function g(uint x, uint y) public returns (uint) {
|
function g(uint x, uint y) public returns (uint) {
|
||||||
return x - y;
|
return x - y;
|
||||||
@ -8,18 +8,20 @@ contract C {
|
|||||||
function h() public payable returns (uint) {
|
function h() public payable returns (uint) {
|
||||||
return f();
|
return f();
|
||||||
}
|
}
|
||||||
function x(bytes32 b) public returns (bytes32) {
|
function i(bytes32 b) public returns (bytes32) {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
function t(bool b) public returns (bool) {
|
function j(bool b) public returns (bool) {
|
||||||
return !b;
|
return !b;
|
||||||
}
|
}
|
||||||
|
function k(bytes32 b) public returns (bytes32) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// f() -> 1
|
// f() -> 2
|
||||||
// g(uint256,uint256): 1, -2 -> 3
|
// g(uint256,uint256): 1, -2 -> 3
|
||||||
// h(), 1 ether -> 1
|
// h(), 1 ether -> 2
|
||||||
// j() -> FAILURE
|
// i() -> FAILURE
|
||||||
// i() # Does not exist. # -> FAILURE # Reverts. #
|
// j(bool): true -> false
|
||||||
// x(bytes32): 0x31 -> 0x31
|
// k(bytes32): 0x31 -> 0x31
|
||||||
// t(bool): true -> false
|
|
||||||
|
28
test/libsolidity/semanticTests/smoke_test_alignment.sol
Normal file
28
test/libsolidity/semanticTests/smoke_test_alignment.sol
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
contract C {
|
||||||
|
uint256 public stateDecimal = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
contract D {
|
||||||
|
bool public stateBool = true;
|
||||||
|
uint256 public stateDecimal = 42;
|
||||||
|
bytes32 public stateBytes = "\x42\x00\xef";
|
||||||
|
|
||||||
|
function internalStateDecimal() public returns (uint256) {
|
||||||
|
return (new C()).stateDecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(bool _bool, uint256 _decimal, bytes32 _bytes) public returns (bool, uint256, bytes32) {
|
||||||
|
stateBool = _bool;
|
||||||
|
stateDecimal = _decimal;
|
||||||
|
stateBytes = _bytes;
|
||||||
|
return (stateBool, stateDecimal, stateBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// stateBool() -> true
|
||||||
|
// stateBool() -> right(true)
|
||||||
|
// stateDecimal() -> 42
|
||||||
|
// stateDecimal() -> right(42)
|
||||||
|
// stateBytes() -> left(0x4200ef)
|
||||||
|
// internalStateDecimal() -> 0x20
|
||||||
|
// update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef)
|
@ -33,6 +33,45 @@ using namespace dev::solidity::test;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace soltest;
|
using namespace soltest;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum class DeclaredAlignment
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
None,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bytes alignLeft(bytes _bytes)
|
||||||
|
{
|
||||||
|
return std::move(_bytes) + bytes(32 - _bytes.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bytes alignRight(bytes _bytes)
|
||||||
|
{
|
||||||
|
return bytes(32 - _bytes.size(), 0) + std::move(_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bytes applyAlign(DeclaredAlignment _alignment, ABIType& _abiType, bytes _converted)
|
||||||
|
{
|
||||||
|
if (_alignment != DeclaredAlignment::None)
|
||||||
|
_abiType.alignDeclared = true;
|
||||||
|
|
||||||
|
switch (_alignment)
|
||||||
|
{
|
||||||
|
case DeclaredAlignment::Left:
|
||||||
|
_abiType.align = ABIType::AlignLeft;
|
||||||
|
return alignLeft(std::move(_converted));
|
||||||
|
case DeclaredAlignment::Right:
|
||||||
|
_abiType.align = ABIType::AlignRight;
|
||||||
|
return alignRight(std::move(_converted));
|
||||||
|
default:
|
||||||
|
_abiType.align = ABIType::AlignRight;
|
||||||
|
return alignRight(std::move(_converted));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls()
|
vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls()
|
||||||
{
|
{
|
||||||
vector<FunctionCall> calls;
|
vector<FunctionCall> calls;
|
||||||
@ -137,9 +176,16 @@ string TestFileParser::parseFunctionSignature()
|
|||||||
|
|
||||||
u256 TestFileParser::parseFunctionCallValue()
|
u256 TestFileParser::parseFunctionCallValue()
|
||||||
{
|
{
|
||||||
u256 value = convertNumber(parseDecimalNumber());
|
try
|
||||||
expect(Token::Ether);
|
{
|
||||||
return value;
|
u256 value{parseDecimalNumber()};
|
||||||
|
expect(Token::Ether);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
throw Error(Error::Type::ParserError, "Ether value encoding invalid.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionCallArgs TestFileParser::parseFunctionCallArguments()
|
FunctionCallArgs TestFileParser::parseFunctionCallArguments()
|
||||||
@ -192,51 +238,75 @@ Parameter TestFileParser::parseParameter()
|
|||||||
|
|
||||||
tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
||||||
{
|
{
|
||||||
|
ABIType abiType{ABIType::None, ABIType::AlignNone, 0};
|
||||||
|
DeclaredAlignment alignment{DeclaredAlignment::None};
|
||||||
|
bytes result{toBigEndian(u256{0})};
|
||||||
|
string rawString;
|
||||||
|
bool isSigned = false;
|
||||||
|
|
||||||
|
if (accept(Token::Left, true))
|
||||||
|
{
|
||||||
|
rawString += formatToken(Token::Left);
|
||||||
|
expect(Token::LParen);
|
||||||
|
rawString += formatToken(Token::LParen);
|
||||||
|
alignment = DeclaredAlignment::Left;
|
||||||
|
}
|
||||||
|
if (accept(Token::Right, true))
|
||||||
|
{
|
||||||
|
rawString += formatToken(Token::Right);
|
||||||
|
expect(Token::LParen);
|
||||||
|
rawString += formatToken(Token::LParen);
|
||||||
|
alignment = DeclaredAlignment::Right;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
u256 number{0};
|
if (accept(Token::Sub, true))
|
||||||
ABIType abiType{ABIType::None, ABIType::AlignRight, 0};
|
|
||||||
string rawString;
|
|
||||||
|
|
||||||
if (accept(Token::Sub))
|
|
||||||
{
|
{
|
||||||
abiType = ABIType{ABIType::SignedDec, ABIType::AlignRight, 32};
|
|
||||||
expect(Token::Sub);
|
|
||||||
rawString += formatToken(Token::Sub);
|
rawString += formatToken(Token::Sub);
|
||||||
|
isSigned = true;
|
||||||
|
}
|
||||||
|
if (accept(Token::Boolean))
|
||||||
|
{
|
||||||
|
if (isSigned)
|
||||||
|
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
|
||||||
|
abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
|
||||||
|
string parsed = parseBoolean();
|
||||||
|
rawString += parsed;
|
||||||
|
result = applyAlign(alignment, abiType, convertBoolean(parsed));
|
||||||
|
}
|
||||||
|
else if (accept(Token::HexNumber))
|
||||||
|
{
|
||||||
|
if (isSigned)
|
||||||
|
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
|
||||||
|
abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
|
||||||
|
string parsed = parseHexNumber();
|
||||||
|
rawString += parsed;
|
||||||
|
result = applyAlign(alignment, abiType, convertHexNumber(parsed));
|
||||||
|
}
|
||||||
|
else if (accept(Token::Number))
|
||||||
|
{
|
||||||
|
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
||||||
|
abiType = ABIType{type, ABIType::AlignRight, 32};
|
||||||
string parsed = parseDecimalNumber();
|
string parsed = parseDecimalNumber();
|
||||||
rawString += parsed;
|
rawString += parsed;
|
||||||
number = convertNumber(parsed) * -1;
|
if (isSigned)
|
||||||
|
parsed = "-" + parsed;
|
||||||
|
result = applyAlign(alignment, abiType, convertNumber(parsed));
|
||||||
}
|
}
|
||||||
else
|
else if (accept(Token::Failure, true))
|
||||||
{
|
{
|
||||||
if (accept(Token::Boolean))
|
if (isSigned)
|
||||||
{
|
throw Error(Error::Type::ParserError, "Invalid failure literal.");
|
||||||
abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
|
abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
|
||||||
string parsed = parseBoolean();
|
result = bytes{};
|
||||||
rawString += parsed;
|
|
||||||
return make_tuple(toBigEndian(u256{convertBoolean(parsed)}), abiType, rawString);
|
|
||||||
}
|
|
||||||
else if (accept(Token::HexNumber))
|
|
||||||
{
|
|
||||||
abiType = ABIType{ABIType::Hex, ABIType::AlignLeft, 32};
|
|
||||||
string parsed = parseHexNumber();
|
|
||||||
rawString += parsed;
|
|
||||||
return make_tuple(convertHexNumber(parsed), abiType, rawString);
|
|
||||||
}
|
|
||||||
else if (accept(Token::Number))
|
|
||||||
{
|
|
||||||
abiType = ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
|
||||||
string parsed = parseDecimalNumber();
|
|
||||||
rawString += parsed;
|
|
||||||
number = convertNumber(parsed);
|
|
||||||
}
|
|
||||||
else if (accept(Token::Failure, true))
|
|
||||||
{
|
|
||||||
abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
|
|
||||||
return make_tuple(bytes{}, abiType, rawString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return make_tuple(toBigEndian(number), abiType, rawString);
|
if (alignment != DeclaredAlignment::None)
|
||||||
|
{
|
||||||
|
expect(Token::RParen);
|
||||||
|
rawString += formatToken(Token::RParen);
|
||||||
|
}
|
||||||
|
return make_tuple(result, abiType, rawString);
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
@ -298,21 +368,21 @@ string TestFileParser::parseHexNumber()
|
|||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestFileParser::convertBoolean(string const& _literal)
|
bytes TestFileParser::convertBoolean(string const& _literal)
|
||||||
{
|
{
|
||||||
if (_literal == "true")
|
if (_literal == "true")
|
||||||
return true;
|
return bytes{true};
|
||||||
else if (_literal == "false")
|
else if (_literal == "false")
|
||||||
return false;
|
return bytes{false};
|
||||||
else
|
else
|
||||||
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
|
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 TestFileParser::convertNumber(string const& _literal)
|
bytes TestFileParser::convertNumber(string const& _literal)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return u256{_literal};
|
return toCompactBigEndian(u256{_literal});
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
@ -330,8 +400,7 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bytes result = fromHex(_literal);
|
return fromHex(_literal);
|
||||||
return result + bytes(32 - result.size(), 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
@ -357,6 +426,8 @@ void TestFileParser::Scanner::scanNextToken()
|
|||||||
if (_literal == "true") return TokenDesc{Token::Boolean, _literal};
|
if (_literal == "true") return TokenDesc{Token::Boolean, _literal};
|
||||||
if (_literal == "false") return TokenDesc{Token::Boolean, _literal};
|
if (_literal == "false") return TokenDesc{Token::Boolean, _literal};
|
||||||
if (_literal == "ether") return TokenDesc{Token::Ether, _literal};
|
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 == "FAILURE") return TokenDesc{Token::Failure, _literal};
|
if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal};
|
||||||
return TokenDesc{Token::Identifier, _literal};
|
return TokenDesc{Token::Identifier, _literal};
|
||||||
};
|
};
|
||||||
|
@ -62,6 +62,8 @@ namespace test
|
|||||||
K(Ether, "ether", 0) \
|
K(Ether, "ether", 0) \
|
||||||
K(Boolean, "boolean", 0) \
|
K(Boolean, "boolean", 0) \
|
||||||
/* special keywords */ \
|
/* special keywords */ \
|
||||||
|
K(Left, "left", 0) \
|
||||||
|
K(Right, "right", 0) \
|
||||||
K(Failure, "FAILURE", 0) \
|
K(Failure, "FAILURE", 0) \
|
||||||
|
|
||||||
namespace soltest
|
namespace soltest
|
||||||
@ -112,12 +114,13 @@ struct ABIType
|
|||||||
enum Align
|
enum Align
|
||||||
{
|
{
|
||||||
AlignLeft,
|
AlignLeft,
|
||||||
AlignRight
|
AlignRight,
|
||||||
|
AlignNone,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type = ABIType::None;
|
Type type = ABIType::None;
|
||||||
Align align = ABIType::AlignRight;
|
Align align = ABIType::AlignRight;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
bool alignDeclared = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -370,16 +373,15 @@ private:
|
|||||||
/// Parses the current hex number literal.
|
/// Parses the current hex number literal.
|
||||||
std::string parseHexNumber();
|
std::string parseHexNumber();
|
||||||
|
|
||||||
/// Coverts "true" to `true`, "false" to `false` and throws
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// otherwise.
|
/// representation of the boolean number literal. Throws if conversion fails.
|
||||||
bool convertBoolean(std::string const& _literal);
|
bytes convertBoolean(std::string const& _literal);
|
||||||
|
|
||||||
/// Tries to convert \param _literal to right-aligned, padded `u256`
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// representation of the decimal number literal.
|
/// representation of the decimal number literal. Throws if conversion fails.
|
||||||
/// Throws if conversion fails.
|
bytes convertNumber(std::string const& _literal);
|
||||||
u256 convertNumber(std::string const& _literal);
|
|
||||||
|
|
||||||
/// Tries to convert \param _literal to left-aligned, padded `bytes`
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// representation of the hex literal. Throws if conversion fails.
|
/// representation of the hex literal. Throws if conversion fails.
|
||||||
bytes convertHexNumber(std::string const& _literal);
|
bytes convertHexNumber(std::string const& _literal);
|
||||||
|
|
||||||
|
@ -336,8 +336,8 @@ BOOST_AUTO_TEST_CASE(call_arguments_left_aligned)
|
|||||||
"f(bytes32,bytes32)",
|
"f(bytes32,bytes32)",
|
||||||
false,
|
false,
|
||||||
fmt::encodeArgs(
|
fmt::encodeArgs(
|
||||||
u256("0x6161000000000000000000000000000000000000000000000000000000000000"),
|
fromHex("0x6161"),
|
||||||
u256("0x420000EF00000000000000000000000000000000000000000000000000000000")
|
fromHex("0x420000EF")
|
||||||
),
|
),
|
||||||
fmt::encodeArgs(1)
|
fmt::encodeArgs(1)
|
||||||
);
|
);
|
||||||
@ -347,8 +347,8 @@ BOOST_AUTO_TEST_CASE(call_arguments_left_aligned)
|
|||||||
"g(bytes32,bytes32)",
|
"g(bytes32,bytes32)",
|
||||||
false,
|
false,
|
||||||
fmt::encodeArgs(
|
fmt::encodeArgs(
|
||||||
u256("0x0616000000000000000000000000000000000000000000000000000000000000"),
|
fromHex("0x0616"),
|
||||||
u256("0x0042EF0000000000000000000000000000000000000000000000000000000000")
|
fromHex("0x0042EF00")
|
||||||
),
|
),
|
||||||
fmt::encodeArgs(1)
|
fmt::encodeArgs(1)
|
||||||
);
|
);
|
||||||
@ -493,6 +493,46 @@ BOOST_AUTO_TEST_CASE(call_raw_arguments)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(call_builtin_left_decimal)
|
||||||
|
{
|
||||||
|
char const* source = R"(
|
||||||
|
// f(): left(1), left(0x20) -> left(-2), left(true)
|
||||||
|
)";
|
||||||
|
auto const calls = parse(source);
|
||||||
|
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||||
|
testFunctionCall(
|
||||||
|
calls.at(0),
|
||||||
|
Mode::SingleLine,
|
||||||
|
"f()",
|
||||||
|
false,
|
||||||
|
fmt::encodeArgs(
|
||||||
|
fmt::encode(toCompactBigEndian(u256{1}), false),
|
||||||
|
fmt::encode(fromHex("0x20"), false)
|
||||||
|
),
|
||||||
|
fmt::encodeArgs(
|
||||||
|
fmt::encode(toCompactBigEndian(u256{-2}), false),
|
||||||
|
fmt::encode(bytes{true}, false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(call_builtin_right_decimal)
|
||||||
|
{
|
||||||
|
char const* source = R"(
|
||||||
|
// f(): right(1), right(0x20) -> right(-2), right(true)
|
||||||
|
)";
|
||||||
|
auto const calls = parse(source);
|
||||||
|
BOOST_REQUIRE_EQUAL(calls.size(), 1);
|
||||||
|
testFunctionCall(
|
||||||
|
calls.at(0),
|
||||||
|
Mode::SingleLine,
|
||||||
|
"f()",
|
||||||
|
false,
|
||||||
|
fmt::encodeArgs(1, fromHex("0x20")),
|
||||||
|
fmt::encodeArgs(-2, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(call_newline_invalid)
|
BOOST_AUTO_TEST_CASE(call_newline_invalid)
|
||||||
{
|
{
|
||||||
char const* source = R"(
|
char const* source = R"(
|
||||||
@ -603,6 +643,30 @@ BOOST_AUTO_TEST_CASE(call_hex_number_invalid)
|
|||||||
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(call_signed_bool_invalid)
|
||||||
|
{
|
||||||
|
char const* source = R"(
|
||||||
|
// f() -> -true
|
||||||
|
)";
|
||||||
|
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(call_signed_failure_invalid)
|
||||||
|
{
|
||||||
|
char const* source = R"(
|
||||||
|
// f() -> -FAILURE
|
||||||
|
)";
|
||||||
|
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(call_signed_hex_number_invalid)
|
||||||
|
{
|
||||||
|
char const* source = R"(
|
||||||
|
// f() -> -0x42
|
||||||
|
)";
|
||||||
|
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(call_arguments_colon)
|
BOOST_AUTO_TEST_CASE(call_arguments_colon)
|
||||||
{
|
{
|
||||||
char const* source = R"(
|
char const* source = R"(
|
||||||
|
@ -48,7 +48,11 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
if (!m_call.arguments.rawBytes().empty())
|
if (!m_call.arguments.rawBytes().empty())
|
||||||
{
|
{
|
||||||
string output = formatRawParameters(m_call.arguments.parameters, _linePrefix);
|
string output = formatRawParameters(m_call.arguments.parameters, _linePrefix);
|
||||||
_stream << colon << output;
|
_stream << colon;
|
||||||
|
if (_singleLine)
|
||||||
|
_stream << ws;
|
||||||
|
_stream << output;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats comments on the function parameters and the arrow taking
|
/// Formats comments on the function parameters and the arrow taking
|
||||||
@ -76,13 +80,19 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
{
|
{
|
||||||
bytes output = m_call.expectations.rawBytes();
|
bytes output = m_call.expectations.rawBytes();
|
||||||
bool const isFailure = m_call.expectations.failure;
|
bool const isFailure = m_call.expectations.failure;
|
||||||
result = isFailure ? failure : formatBytesParameters(output, m_call.expectations.result);
|
result = isFailure ?
|
||||||
|
failure :
|
||||||
|
formatRawParameters(m_call.expectations.result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bytes output = m_rawBytes;
|
bytes output = m_rawBytes;
|
||||||
bool const isFailure = m_failure;
|
bool const isFailure = m_failure;
|
||||||
result = isFailure ? failure : formatBytesParameters(output, m_call.expectations.result);
|
result = isFailure ?
|
||||||
|
failure :
|
||||||
|
matchesExpectation() ?
|
||||||
|
formatRawParameters(m_call.expectations.result) :
|
||||||
|
formatBytesParameters(output, m_call.expectations.result);
|
||||||
}
|
}
|
||||||
AnsiColorized(_stream, highlight, {dev::formatting::RED_BACKGROUND}) << result;
|
AnsiColorized(_stream, highlight, {dev::formatting::RED_BACKGROUND}) << result;
|
||||||
|
|
||||||
@ -106,8 +116,6 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
formatOutput(true);
|
formatOutput(true);
|
||||||
else
|
else
|
||||||
formatOutput(false);
|
formatOutput(false);
|
||||||
// _stream << endl;
|
|
||||||
|
|
||||||
return _stream.str();
|
return _stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +139,12 @@ string TestFunctionCall::formatBytesParameters(bytes const& _bytes, dev::solidit
|
|||||||
// be signed. If an unsigned was detected in the expectations,
|
// be signed. If an unsigned was detected in the expectations,
|
||||||
// but the actual result returned a signed, it would be formatted
|
// but the actual result returned a signed, it would be formatted
|
||||||
// incorrectly.
|
// incorrectly.
|
||||||
soltestAssert(param.abiType.align == ABIType::AlignRight, "Unsigned decimals must be right-aligned.");
|
|
||||||
if (*byteRange.begin() & 0x80)
|
if (*byteRange.begin() & 0x80)
|
||||||
resultStream << u2s(fromBigEndian<u256>(byteRange));
|
resultStream << u2s(fromBigEndian<u256>(byteRange));
|
||||||
else
|
else
|
||||||
resultStream << fromBigEndian<u256>(byteRange);
|
resultStream << fromBigEndian<u256>(byteRange);
|
||||||
break;
|
break;
|
||||||
case ABIType::SignedDec:
|
case ABIType::SignedDec:
|
||||||
soltestAssert(param.abiType.align == ABIType::AlignRight, "Signed decimals must be right-aligned.");
|
|
||||||
if (*byteRange.begin() & 0x80)
|
if (*byteRange.begin() & 0x80)
|
||||||
resultStream << u2s(fromBigEndian<u256>(byteRange));
|
resultStream << u2s(fromBigEndian<u256>(byteRange));
|
||||||
else
|
else
|
||||||
@ -146,19 +152,16 @@ string TestFunctionCall::formatBytesParameters(bytes const& _bytes, dev::solidit
|
|||||||
break;
|
break;
|
||||||
case ABIType::Boolean:
|
case ABIType::Boolean:
|
||||||
{
|
{
|
||||||
soltestAssert(param.abiType.align == ABIType::AlignRight, "Booleans must be right-aligned.");
|
|
||||||
u256 result = fromBigEndian<u256>(byteRange);
|
u256 result = fromBigEndian<u256>(byteRange);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
resultStream << "false";
|
resultStream << "false";
|
||||||
else
|
else if (result == 1)
|
||||||
resultStream << "true";
|
resultStream << "true";
|
||||||
|
else
|
||||||
|
resultStream << result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ABIType::Hex:
|
case ABIType::Hex:
|
||||||
soltestAssert(param.abiType.align == ABIType::AlignLeft, "Hex numbers must be left-aligned.");
|
|
||||||
byteRange.erase(
|
|
||||||
std::remove(byteRange.begin(), byteRange.end(), 0), byteRange.end()
|
|
||||||
);
|
|
||||||
resultStream << toHex(byteRange, HexPrefix::Add);
|
resultStream << toHex(byteRange, HexPrefix::Add);
|
||||||
break;
|
break;
|
||||||
case ABIType::Failure:
|
case ABIType::Failure:
|
||||||
@ -180,10 +183,10 @@ string TestFunctionCall::formatRawParameters(dev::solidity::test::ParameterList
|
|||||||
for (auto const& param: _params)
|
for (auto const& param: _params)
|
||||||
{
|
{
|
||||||
if (param.format.newline)
|
if (param.format.newline)
|
||||||
resultStream << endl << _linePrefix << "//";
|
resultStream << endl << _linePrefix << "// ";
|
||||||
resultStream << " " << param.rawString;
|
resultStream << param.rawString;
|
||||||
if (¶m != &_params.back())
|
if (¶m != &_params.back())
|
||||||
resultStream << ",";
|
resultStream << ", ";
|
||||||
}
|
}
|
||||||
return resultStream.str();
|
return resultStream.str();
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,43 @@ BOOST_AUTO_TEST_CASE(format_unsigned_singleline)
|
|||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8): 1 -> 1");
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8): 1 -> 1");
|
||||||
|
|
||||||
|
test.setRawBytes(toBigEndian(u256{2}));
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(uint8): 1 -> 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(format_unsigned_singleline_signed_encoding)
|
||||||
|
{
|
||||||
|
bytes expectedBytes = toBigEndian(u256{1});
|
||||||
|
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
||||||
|
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
|
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
||||||
|
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
||||||
|
FunctionCall call{"f(uint8)", 0, arguments, expectations};
|
||||||
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8): 1 -> 1");
|
||||||
|
|
||||||
|
test.setRawBytes(toBigEndian(u256{-1}));
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(uint8): 1 -> -1");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(format_unsigned_multiline)
|
||||||
|
{
|
||||||
|
bytes expectedBytes = toBigEndian(u256{1});
|
||||||
|
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
||||||
|
Parameter result{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
|
FunctionCallExpectations expectations{vector<Parameter>{result}, false, string{}};
|
||||||
|
FunctionCallArgs arguments{vector<Parameter>{}, string{}};
|
||||||
|
FunctionCall call{"f(uint8)", 0, arguments, expectations};
|
||||||
|
call.displayMode = FunctionCall::DisplayMode::MultiLine;
|
||||||
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8)\n// -> 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_multiple_unsigned_singleline)
|
BOOST_AUTO_TEST_CASE(format_multiple_unsigned_singleline)
|
||||||
@ -73,23 +110,14 @@ BOOST_AUTO_TEST_CASE(format_signed_singleline)
|
|||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(int8): -1 -> -1");
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(int8): -1 -> -1");
|
||||||
|
|
||||||
|
test.setRawBytes(toBigEndian(u256{-2}));
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(int8): -1 -> -2");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_hex_singleline)
|
BOOST_AUTO_TEST_CASE(format_hex_singleline)
|
||||||
{
|
|
||||||
bytes result = fromHex("0x31");
|
|
||||||
bytes expectedBytes = result + bytes(32 - result.size(), 0);
|
|
||||||
ABIType abiType{ABIType::Hex, ABIType::AlignLeft, 32};
|
|
||||||
Parameter param{expectedBytes, "0x31", abiType, FormatInfo{}};
|
|
||||||
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
|
||||||
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
|
||||||
FunctionCall call{"f(bytes32)", 0, arguments, expectations};
|
|
||||||
TestFunctionCall test{call};
|
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(bytes32): 0x31 -> 0x31");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_hex_right_align)
|
|
||||||
{
|
{
|
||||||
bytes result = fromHex("0x31");
|
bytes result = fromHex("0x31");
|
||||||
bytes expectedBytes = result + bytes(32 - result.size(), 0);
|
bytes expectedBytes = result + bytes(32 - result.size(), 0);
|
||||||
@ -100,7 +128,14 @@ BOOST_AUTO_TEST_CASE(format_hex_right_align)
|
|||||||
FunctionCall call{"f(bytes32)", 0, arguments, expectations};
|
FunctionCall call{"f(bytes32)", 0, arguments, expectations};
|
||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_THROW(test.format(), runtime_error);
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(bytes32): 0x31 -> 0x31");
|
||||||
|
|
||||||
|
bytes actualResult = fromHex("0x32");
|
||||||
|
bytes actualBytes = actualResult + bytes(32 - actualResult.size(), 0);
|
||||||
|
test.setRawBytes(actualBytes);
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(bytes32): 0x31 -> 0x3200000000000000000000000000000000000000000000000000000000000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_bool_true_singleline)
|
BOOST_AUTO_TEST_CASE(format_bool_true_singleline)
|
||||||
@ -114,6 +149,13 @@ BOOST_AUTO_TEST_CASE(format_bool_true_singleline)
|
|||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): true -> true");
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): true -> true");
|
||||||
|
|
||||||
|
bytes actualResult = bytes{false};
|
||||||
|
bytes actualBytes = actualResult + bytes(32 - actualResult.size(), 0);
|
||||||
|
test.setRawBytes(actualBytes);
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format("", true), "// f(bool): true -> false");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_bool_false_singleline)
|
BOOST_AUTO_TEST_CASE(format_bool_false_singleline)
|
||||||
@ -129,48 +171,79 @@ BOOST_AUTO_TEST_CASE(format_bool_false_singleline)
|
|||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): false -> false");
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): false -> false");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_bool_left_align_singleline)
|
BOOST_AUTO_TEST_CASE(format_bool_left_singleline)
|
||||||
{
|
{
|
||||||
bytes expectedBytes = toBigEndian(u256{true});
|
bytes expectedBytes = toBigEndian(u256{false});
|
||||||
ABIType abiType{ABIType::Boolean, ABIType::AlignLeft, 32};
|
ABIType abiType{ABIType::Boolean, ABIType::AlignLeft, 32};
|
||||||
Parameter param{expectedBytes, "true", abiType, FormatInfo{}};
|
Parameter param{expectedBytes, "left(false)", abiType, FormatInfo{}};
|
||||||
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
||||||
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
||||||
FunctionCall call{"f(bool)", 0, arguments, expectations};
|
FunctionCall call{"f(bool)", 0, arguments, expectations};
|
||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_THROW(test.format(), runtime_error);
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): left(false) -> left(false)");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(format_hex_number_right_singleline)
|
||||||
|
{
|
||||||
|
bytes result = fromHex("0x42");
|
||||||
|
bytes expectedBytes = result + bytes(32 - result.size(), 0);
|
||||||
|
ABIType abiType{ABIType::Hex, ABIType::AlignRight, 32};
|
||||||
|
Parameter param{expectedBytes, "right(0x42)", abiType, FormatInfo{}};
|
||||||
|
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
||||||
|
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
||||||
|
FunctionCall call{"f(bool)", 0, arguments, expectations};
|
||||||
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(bool): right(0x42) -> right(0x42)");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_empty_byte_range)
|
BOOST_AUTO_TEST_CASE(format_empty_byte_range)
|
||||||
{
|
{
|
||||||
bytes expectedBytes;
|
bytes expectedBytes;
|
||||||
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
ABIType abiType{ABIType::None, ABIType::AlignNone, 0};
|
||||||
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}};
|
||||||
FunctionCallArgs arguments{vector<Parameter>{}, string{}};
|
FunctionCallArgs arguments{vector<Parameter>{}, string{}};
|
||||||
FunctionCall call{"f()", 0, arguments, expectations};
|
FunctionCall call{"f()", 0, arguments, expectations};
|
||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL(test.format(), "// f() -> ");
|
BOOST_REQUIRE_EQUAL(test.format(), "// f() -> 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(format_failure_singleline)
|
||||||
|
{
|
||||||
|
bytes expectedBytes = toBigEndian(u256{1});
|
||||||
|
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
||||||
|
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
|
FunctionCallExpectations expectations{vector<Parameter>{}, true, string{}};
|
||||||
|
FunctionCallArgs arguments{vector<Parameter>{param}, string{}};
|
||||||
|
FunctionCall call{"f(uint8)", 0, arguments, expectations};
|
||||||
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8): 1 -> FAILURE");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_parameter_encoding_too_short)
|
BOOST_AUTO_TEST_CASE(format_parameter_encoding_too_short)
|
||||||
{
|
{
|
||||||
bytes expectedBytes = toBigEndian(u256{1}) + toBigEndian(u256{1});
|
bytes expectedBytes = toBigEndian(u256{1}) + toBigEndian(u256{1});
|
||||||
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 20};
|
||||||
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
FunctionCallExpectations expectations{vector<Parameter>{param, param}, false, string{}};
|
FunctionCallExpectations expectations{vector<Parameter>{param, param}, false, string{}};
|
||||||
FunctionCallArgs arguments{vector<Parameter>{param, param}, string{}};
|
FunctionCallArgs arguments{vector<Parameter>{param, param}, string{}};
|
||||||
FunctionCall call{"f(uint8, uint8)", 0, arguments, expectations};
|
FunctionCall call{"f(uint8, uint8)", 0, arguments, expectations};
|
||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_THROW(test.format(), runtime_error);
|
bytes resultBytes = toBigEndian(u256{1}) + toBigEndian(u256{2});
|
||||||
|
test.setRawBytes(resultBytes);
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_THROW(test.format("", true), runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(format_byte_range_too_short)
|
BOOST_AUTO_TEST_CASE(format_byte_range_too_short)
|
||||||
{
|
{
|
||||||
bytes expectedBytes{0};
|
bytes expectedBytes = toBigEndian(u256{1});
|
||||||
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
|
||||||
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
Parameter param{expectedBytes, "1", abiType, FormatInfo{}};
|
||||||
FunctionCallExpectations expectations{vector<Parameter>{param, param}, false, string{}};
|
FunctionCallExpectations expectations{vector<Parameter>{param, param}, false, string{}};
|
||||||
@ -178,7 +251,11 @@ BOOST_AUTO_TEST_CASE(format_byte_range_too_short)
|
|||||||
FunctionCall call{"f(uint8, uint8)", 0, arguments, expectations};
|
FunctionCall call{"f(uint8, uint8)", 0, arguments, expectations};
|
||||||
TestFunctionCall test{call};
|
TestFunctionCall test{call};
|
||||||
|
|
||||||
BOOST_REQUIRE_THROW(test.format(), runtime_error);
|
bytes resultBytes{0};
|
||||||
|
test.setRawBytes(resultBytes);
|
||||||
|
test.setFailure(false);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_THROW(test.format("", true), runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user