mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #6183 from ethereum/soltest-alignment
[soltest] Introduce explicit alignment
This commit is contained in:
		
						commit
						0eb799424d
					
				| @ -75,12 +75,12 @@ bool SemanticTest::run(ostream& _stream, string const& _linePrefix, bool const _ | ||||
| 		AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; | ||||
| 		for (auto const& test: m_tests) | ||||
| 			_stream << test.format(_linePrefix, false, _formatted) << endl; | ||||
| 
 | ||||
| 		_stream << endl; | ||||
| 		AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; | ||||
| 		for (auto const& test: m_tests) | ||||
| 			_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; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| contract C { | ||||
|     function f() public returns (uint) { | ||||
|         return 1; | ||||
|         return 2; | ||||
|     } | ||||
|     function g(uint x, uint y) public returns (uint) { | ||||
|         return x - y; | ||||
| @ -8,18 +8,20 @@ contract C { | ||||
|     function h() public payable returns (uint) { | ||||
|         return f(); | ||||
|     } | ||||
|     function x(bytes32 b) public returns (bytes32) { | ||||
|     function i(bytes32 b) public returns (bytes32) { | ||||
|         return b; | ||||
|     } | ||||
|     function t(bool b) public returns (bool) { | ||||
|     function j(bool b) public returns (bool) { | ||||
|         return !b; | ||||
|     } | ||||
|     function k(bytes32 b) public returns (bytes32) { | ||||
|         return b; | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // f() -> 1 | ||||
| // f() -> 2 | ||||
| // g(uint256,uint256): 1, -2 -> 3 | ||||
| // h(), 1 ether -> 1 | ||||
| // j() -> FAILURE | ||||
| // i() # Does not exist. # -> FAILURE # Reverts. # | ||||
| // x(bytes32): 0x31 -> 0x31 | ||||
| // t(bool): true -> false | ||||
| // h(), 1 ether -> 2 | ||||
| // i() -> FAILURE | ||||
| // j(bool): true -> false | ||||
| // k(bytes32): 0x31 -> 0x31 | ||||
|  | ||||
							
								
								
									
										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 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<FunctionCall> calls; | ||||
| @ -137,9 +176,16 @@ string TestFileParser::parseFunctionSignature() | ||||
| 
 | ||||
| u256 TestFileParser::parseFunctionCallValue() | ||||
| { | ||||
| 	u256 value = convertNumber(parseDecimalNumber()); | ||||
| 	expect(Token::Ether); | ||||
| 	return value; | ||||
| 	try | ||||
| 	{ | ||||
| 		u256 value{parseDecimalNumber()}; | ||||
| 		expect(Token::Ether); | ||||
| 		return value; | ||||
| 	} | ||||
| 	catch (std::exception const&) | ||||
| 	{ | ||||
| 		throw Error(Error::Type::ParserError, "Ether value encoding invalid."); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| FunctionCallArgs TestFileParser::parseFunctionCallArguments() | ||||
| @ -192,51 +238,75 @@ Parameter TestFileParser::parseParameter() | ||||
| 
 | ||||
| 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 | ||||
| 	{ | ||||
| 		u256 number{0}; | ||||
| 		ABIType abiType{ABIType::None, ABIType::AlignRight, 0}; | ||||
| 		string rawString; | ||||
| 
 | ||||
| 		if (accept(Token::Sub)) | ||||
| 		if (accept(Token::Sub, true)) | ||||
| 		{ | ||||
| 			abiType = ABIType{ABIType::SignedDec, ABIType::AlignRight, 32}; | ||||
| 			expect(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(); | ||||
| 			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)) | ||||
| 			{ | ||||
| 				abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32}; | ||||
| 				string parsed = parseBoolean(); | ||||
| 				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); | ||||
| 			} | ||||
| 			if (isSigned) | ||||
| 				throw Error(Error::Type::ParserError, "Invalid failure literal."); | ||||
| 			abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0}; | ||||
| 			result = bytes{}; | ||||
| 		} | ||||
| 		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&) | ||||
| 	{ | ||||
| @ -307,21 +377,21 @@ string TestFileParser::parseHexNumber() | ||||
| 	return literal; | ||||
| } | ||||
| 
 | ||||
| bool TestFileParser::convertBoolean(string const& _literal) | ||||
| bytes TestFileParser::convertBoolean(string const& _literal) | ||||
| { | ||||
| 	if (_literal == "true") | ||||
| 		return true; | ||||
| 		return bytes{true}; | ||||
| 	else if (_literal == "false") | ||||
| 		return false; | ||||
| 		return bytes{false}; | ||||
| 	else | ||||
| 		throw Error(Error::Type::ParserError, "Boolean literal invalid."); | ||||
| } | ||||
| 
 | ||||
| u256 TestFileParser::convertNumber(string const& _literal) | ||||
| bytes TestFileParser::convertNumber(string const& _literal) | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		return u256{_literal}; | ||||
| 		return toCompactBigEndian(u256{_literal}); | ||||
| 	} | ||||
| 	catch (std::exception const&) | ||||
| 	{ | ||||
| @ -339,8 +409,7 @@ bytes TestFileParser::convertHexNumber(string const& _literal) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			bytes result = fromHex(_literal); | ||||
| 			return result + bytes(32 - result.size(), 0); | ||||
| 			return fromHex(_literal); | ||||
| 		} | ||||
| 	} | ||||
| 	catch (std::exception const&) | ||||
| @ -366,6 +435,8 @@ void TestFileParser::Scanner::scanNextToken() | ||||
| 		if (_literal == "true") return TokenDesc{Token::Boolean, _literal}; | ||||
| 		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 == "right") return TokenDesc{Token::Right, _literal}; | ||||
| 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | ||||
| 		return TokenDesc{Token::Identifier, _literal}; | ||||
| 	}; | ||||
|  | ||||
| @ -62,6 +62,8 @@ namespace test | ||||
| 	K(Ether, "ether", 0)           \ | ||||
| 	K(Boolean, "boolean", 0)       \ | ||||
| 	/* special keywords */         \ | ||||
| 	K(Left, "left", 0)             \ | ||||
| 	K(Right, "right", 0)           \ | ||||
| 	K(Failure, "FAILURE", 0)       \ | ||||
| 
 | ||||
| namespace soltest | ||||
| @ -112,12 +114,13 @@ struct ABIType | ||||
| 	enum Align | ||||
| 	{ | ||||
| 		AlignLeft, | ||||
| 		AlignRight | ||||
| 		AlignRight, | ||||
| 		AlignNone, | ||||
| 	}; | ||||
| 
 | ||||
| 	Type type = ABIType::None; | ||||
| 	Align align = ABIType::AlignRight; | ||||
| 	size_t size = 0; | ||||
| 	bool alignDeclared = false; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -370,16 +373,15 @@ private: | ||||
| 	/// Parses the current hex number literal.
 | ||||
| 	std::string parseHexNumber(); | ||||
| 
 | ||||
| 	/// Coverts "true" to `true`, "false" to `false` and throws
 | ||||
| 	/// otherwise.
 | ||||
| 	bool convertBoolean(std::string const& _literal); | ||||
| 	/// Tries to convert \param _literal to an unpadded `bytes`
 | ||||
| 	/// representation of the boolean number literal. Throws if conversion fails.
 | ||||
| 	bytes convertBoolean(std::string const& _literal); | ||||
| 
 | ||||
| 	/// Tries to convert \param _literal to right-aligned, padded `u256`
 | ||||
| 	/// representation of the decimal number literal.
 | ||||
| 	/// Throws if conversion fails.
 | ||||
| 	u256 convertNumber(std::string const& _literal); | ||||
| 	/// Tries to convert \param _literal to an unpadded `bytes`
 | ||||
| 	/// representation of the decimal number literal. Throws if conversion fails.
 | ||||
| 	bytes 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.
 | ||||
| 	bytes convertHexNumber(std::string const& _literal); | ||||
| 
 | ||||
|  | ||||
| @ -336,8 +336,8 @@ BOOST_AUTO_TEST_CASE(call_arguments_left_aligned) | ||||
| 		"f(bytes32,bytes32)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs( | ||||
| 			u256("0x6161000000000000000000000000000000000000000000000000000000000000"), | ||||
| 			u256("0x420000EF00000000000000000000000000000000000000000000000000000000") | ||||
| 			fromHex("0x6161"), | ||||
| 			fromHex("0x420000EF") | ||||
| 		), | ||||
| 		fmt::encodeArgs(1) | ||||
| 	); | ||||
| @ -347,8 +347,8 @@ BOOST_AUTO_TEST_CASE(call_arguments_left_aligned) | ||||
| 		"g(bytes32,bytes32)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs( | ||||
| 			u256("0x0616000000000000000000000000000000000000000000000000000000000000"), | ||||
| 			u256("0x0042EF0000000000000000000000000000000000000000000000000000000000") | ||||
| 			fromHex("0x0616"), | ||||
| 			fromHex("0x0042EF00") | ||||
| 		), | ||||
| 		fmt::encodeArgs(1) | ||||
| 	); | ||||
| @ -507,6 +507,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) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| @ -617,6 +657,30 @@ BOOST_AUTO_TEST_CASE(call_hex_number_invalid) | ||||
| 	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) | ||||
| { | ||||
| 	char const* source = R"( | ||||
|  | ||||
| @ -48,7 +48,11 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes | ||||
| 		if (!m_call.arguments.rawBytes().empty()) | ||||
| 		{ | ||||
| 			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
 | ||||
| @ -76,13 +80,19 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes | ||||
| 		{ | ||||
| 			bytes output = m_call.expectations.rawBytes(); | ||||
| 			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 | ||||
| 		{ | ||||
| 			bytes output = m_rawBytes; | ||||
| 			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; | ||||
| 
 | ||||
| @ -106,8 +116,6 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes | ||||
| 		formatOutput(true); | ||||
| 	else | ||||
| 		formatOutput(false); | ||||
| //	_stream << endl;
 | ||||
| 
 | ||||
| 	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,
 | ||||
| 			// but the actual result returned a signed, it would be formatted
 | ||||
| 			// incorrectly.
 | ||||
| 			soltestAssert(param.abiType.align == ABIType::AlignRight, "Unsigned decimals must be right-aligned."); | ||||
| 			if (*byteRange.begin() & 0x80) | ||||
| 				resultStream << u2s(fromBigEndian<u256>(byteRange)); | ||||
| 			else | ||||
| 				resultStream << fromBigEndian<u256>(byteRange); | ||||
| 			break; | ||||
| 		case ABIType::SignedDec: | ||||
| 			soltestAssert(param.abiType.align == ABIType::AlignRight, "Signed decimals must be right-aligned."); | ||||
| 			if (*byteRange.begin() & 0x80) | ||||
| 				resultStream << u2s(fromBigEndian<u256>(byteRange)); | ||||
| 			else | ||||
| @ -146,19 +152,16 @@ string TestFunctionCall::formatBytesParameters(bytes const& _bytes, dev::solidit | ||||
| 			break; | ||||
| 		case ABIType::Boolean: | ||||
| 		{ | ||||
| 			soltestAssert(param.abiType.align == ABIType::AlignRight, "Booleans must be right-aligned."); | ||||
| 			u256 result = fromBigEndian<u256>(byteRange); | ||||
| 			if (result == 0) | ||||
| 				resultStream << "false"; | ||||
| 			else | ||||
| 			else if (result == 1) | ||||
| 				resultStream << "true"; | ||||
| 			else | ||||
| 				resultStream << result; | ||||
| 			break; | ||||
| 		} | ||||
| 		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); | ||||
| 			break; | ||||
| 		case ABIType::Failure: | ||||
| @ -180,10 +183,10 @@ string TestFunctionCall::formatRawParameters(dev::solidity::test::ParameterList | ||||
| 	for (auto const& param: _params) | ||||
| 	{ | ||||
| 		if (param.format.newline) | ||||
| 			resultStream << endl << _linePrefix << "//"; | ||||
| 		resultStream << " " << param.rawString; | ||||
| 			resultStream << endl << _linePrefix << "// "; | ||||
| 		resultStream << param.rawString; | ||||
| 		if (¶m != &_params.back()) | ||||
| 			resultStream << ","; | ||||
| 			resultStream << ", "; | ||||
| 	} | ||||
| 	return resultStream.str(); | ||||
| } | ||||
|  | ||||
| @ -47,6 +47,43 @@ BOOST_AUTO_TEST_CASE(format_unsigned_singleline) | ||||
| 	TestFunctionCall test{call}; | ||||
| 
 | ||||
| 	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) | ||||
| @ -73,23 +110,14 @@ BOOST_AUTO_TEST_CASE(format_signed_singleline) | ||||
| 	TestFunctionCall test{call}; | ||||
| 
 | ||||
| 	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) | ||||
| { | ||||
| 	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 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}; | ||||
| 	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) | ||||
| @ -114,6 +149,13 @@ BOOST_AUTO_TEST_CASE(format_bool_true_singleline) | ||||
| 	TestFunctionCall test{call}; | ||||
| 
 | ||||
| 	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) | ||||
| @ -129,48 +171,79 @@ BOOST_AUTO_TEST_CASE(format_bool_false_singleline) | ||||
| 	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}; | ||||
| 	Parameter param{expectedBytes, "true", abiType, FormatInfo{}}; | ||||
| 	Parameter param{expectedBytes, "left(false)", 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_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) | ||||
| { | ||||
| 	bytes expectedBytes; | ||||
| 	ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; | ||||
| 	ABIType abiType{ABIType::None, ABIType::AlignNone, 0}; | ||||
| 	Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; | ||||
| 	FunctionCallExpectations expectations{vector<Parameter>{param}, false, string{}}; | ||||
| 	FunctionCallArgs arguments{vector<Parameter>{}, string{}}; | ||||
| 	FunctionCall call{"f()", 0, arguments, expectations}; | ||||
| 	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) | ||||
| { | ||||
| 	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{}}; | ||||
| 	FunctionCallExpectations expectations{vector<Parameter>{param, param}, false, string{}}; | ||||
| 	FunctionCallArgs arguments{vector<Parameter>{param, param}, string{}}; | ||||
| 	FunctionCall call{"f(uint8, uint8)", 0, arguments, expectations}; | ||||
| 	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) | ||||
| { | ||||
| 	bytes expectedBytes{0}; | ||||
| 	bytes expectedBytes = toBigEndian(u256{1}); | ||||
| 	ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; | ||||
| 	Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; | ||||
| 	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}; | ||||
| 	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() | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user