Right-aligns hex numbers and introduces alignment built-ins.

This commit is contained in:
Erik Kundt 2019-02-28 14:16:16 +01:00
parent eb5bde95b3
commit a40fbf0fc4
8 changed files with 359 additions and 112 deletions

View File

@ -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;
} }

View File

@ -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

View 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)

View File

@ -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};
}; };

View File

@ -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);

View File

@ -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"(

View File

@ -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 (&param != &_params.back()) if (&param != &_params.back())
resultStream << ","; resultStream << ", ";
} }
return resultStream.str(); return resultStream.str();
} }

View File

@ -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()