mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Cleans up test file parser and its tests.
This commit is contained in:
		
							parent
							
								
									7fa167977b
								
							
						
					
					
						commit
						161b22bd13
					
				| @ -34,21 +34,13 @@ using namespace std; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| 	bool isDecimalDigit(char c) | ||||
| 	{ | ||||
| 		return '0' <= c && c <= '9'; | ||||
| 	} | ||||
| 	bool isWhiteSpace(char c) | ||||
| 	{ | ||||
| 		return c == ' ' || c == '\n' || c == '\t' || c == '\r'; | ||||
| 	} | ||||
| 	bool isIdentifierStart(char c) | ||||
| 	{ | ||||
| 		return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); | ||||
| 	} | ||||
| 	bool isIdentifierPart(char c) | ||||
| 	{ | ||||
| 		return isIdentifierStart(c) || isDecimalDigit(c); | ||||
| 		return isIdentifierStart(c) || isdigit(c); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -57,33 +49,41 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls() | ||||
| 	vector<FunctionCall> calls; | ||||
| 	if (!accept(SoltToken::EOS)) | ||||
| 	{ | ||||
| 		// TODO: check initial token state
 | ||||
| 		expect(SoltToken::Unknown); | ||||
| 		assert(m_scanner.currentToken() == SoltToken::Unknown); | ||||
| 		m_scanner.scanNextToken(); | ||||
| 
 | ||||
| 		while (!accept(SoltToken::EOS)) | ||||
| 		{ | ||||
| 			if (!accept(SoltToken::Whitespace)) | ||||
| 			{ | ||||
| 				FunctionCall call; | ||||
| 
 | ||||
| 				expect(SoltToken::Newline); | ||||
| 				call.signature = parseFunctionSignature(); | ||||
| 				/// If this is not the first call in the test,
 | ||||
| 				/// the last call to parseParameter could have eaten the
 | ||||
| 				/// new line already. This could only be fixed with a one
 | ||||
| 				/// token lookahead that checks parseParameter
 | ||||
| 				/// if the next token is an identifier.
 | ||||
| 				if (calls.empty()) | ||||
| 					expect(SoltToken::Newline); | ||||
| 				else | ||||
| 					accept(SoltToken::Newline, true); | ||||
| 
 | ||||
| 				call.signature = parseFunctionSignature(); | ||||
| 				if (accept(SoltToken::Comma, true)) | ||||
| 					call.value = parseFunctionCallValue(); | ||||
| 				if (accept(SoltToken::Colon, true)) | ||||
| 					call.arguments = parseFunctionCallArguments(); | ||||
| 
 | ||||
| 				call.displayMode = parseNewline(); | ||||
| 				if (accept(SoltToken::Newline, true)) | ||||
| 					call.displayMode = FunctionCall::DisplayMode::MultiLine; | ||||
| 
 | ||||
| 				call.arguments.comment = parseComment(); | ||||
| 
 | ||||
| 				if (accept(SoltToken::Newline, true)) | ||||
| 					call.displayMode = FunctionCall::DisplayMode::MultiLine; | ||||
| 
 | ||||
| 				expect(SoltToken::Arrow); | ||||
| 
 | ||||
| 				call.expectations = parseFunctionCallExpectations(); | ||||
| 
 | ||||
| 				if (accept(SoltToken::Newline, false)) | ||||
| 					call.displayMode = parseNewline(); | ||||
| 				call.expectations.comment = parseComment(); | ||||
| 
 | ||||
| 				calls.emplace_back(std::move(call)); | ||||
| @ -121,12 +121,12 @@ bool TestFileParser::accept(SoltToken _token, bool const _expect) | ||||
| bool TestFileParser::expect(SoltToken _token, bool const _advance) | ||||
| { | ||||
| 	if (m_scanner.currentToken() != _token) | ||||
| 		throw Error | ||||
| 			(Error::Type::ParserError, | ||||
| 					"Unexpected " + formatToken(m_scanner.currentToken()) + ": \"" + | ||||
| 					m_scanner.currentLiteral() + "\". " + | ||||
| 					"Expected \"" + formatToken(_token) + "\"." | ||||
| 					); | ||||
| 		throw Error( | ||||
| 			Error::Type::ParserError, | ||||
| 			"Unexpected " + formatToken(m_scanner.currentToken()) + ": \"" + | ||||
| 			m_scanner.currentLiteral() + "\". " + | ||||
| 			"Expected \"" + formatToken(_token) + "\"." | ||||
| 			); | ||||
| 	if (_advance) | ||||
| 		m_scanner.scanNextToken(); | ||||
| 	return true; | ||||
| @ -143,13 +143,13 @@ string TestFileParser::parseFunctionSignature() | ||||
| 	while (!accept(SoltToken::RParen)) | ||||
| 	{ | ||||
| 		signature += m_scanner.currentLiteral(); | ||||
| 		expect(SoltToken::UInt); | ||||
| 		expect(SoltToken::Identifier); | ||||
| 		while (accept(SoltToken::Comma)) | ||||
| 		{ | ||||
| 			signature += m_scanner.currentLiteral(); | ||||
| 			expect(SoltToken::Comma); | ||||
| 			signature += m_scanner.currentLiteral(); | ||||
| 			expect(SoltToken::UInt); | ||||
| 			expect(SoltToken::Identifier); | ||||
| 		} | ||||
| 	} | ||||
| 	signature += formatToken(SoltToken::RParen); | ||||
| @ -184,15 +184,18 @@ FunctionCallExpectations TestFileParser::parseFunctionCallExpectations() | ||||
| 
 | ||||
| 	auto param = parseParameter(); | ||||
| 	if (param.abiType.type == ABIType::None) | ||||
| 	{ | ||||
| 		expectations.failure = false; | ||||
| 		return expectations; | ||||
| 	expectations.parameters.emplace_back(param); | ||||
| 	} | ||||
| 	expectations.result.emplace_back(param); | ||||
| 
 | ||||
| 	while (accept(SoltToken::Comma, true)) | ||||
| 		expectations.parameters.emplace_back(parseParameter()); | ||||
| 		expectations.result.emplace_back(parseParameter()); | ||||
| 
 | ||||
| 	/// We have always one virtual parameter in the parameter list.
 | ||||
| 	/// If its type is FAILURE, the expected result is also a REVERT etc.
 | ||||
| 	if (expectations.parameters.at(0).abiType.type != ABIType::Failure) | ||||
| 	if (expectations.result.at(0).abiType.type != ABIType::Failure) | ||||
| 		expectations.failure = false; | ||||
| 	return expectations; | ||||
| } | ||||
| @ -212,8 +215,9 @@ pair<bytes, ABIType> TestFileParser::parseABITypeLiteral() | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		u256 number; | ||||
| 		ABIType abiType; | ||||
| 		u256 number{0}; | ||||
| 		ABIType abiType{ABIType::None, 0}; | ||||
| 
 | ||||
| 		if (accept(SoltToken::Sub)) | ||||
| 		{ | ||||
| 			abiType = ABIType{ABIType::SignedDec, 32}; | ||||
| @ -227,7 +231,7 @@ pair<bytes, ABIType> TestFileParser::parseABITypeLiteral() | ||||
| 				abiType = ABIType{ABIType::UnsignedDec, 32}; | ||||
| 				number = convertNumber(parseNumber()); | ||||
| 			} | ||||
| 			if (accept(SoltToken::Failure, true)) | ||||
| 			else if (accept(SoltToken::Failure, true)) | ||||
| 			{ | ||||
| 				abiType = ABIType{ABIType::Failure, 0}; | ||||
| 				return make_pair(bytes{}, abiType); | ||||
| @ -241,13 +245,6 @@ pair<bytes, ABIType> TestFileParser::parseABITypeLiteral() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| solidity::test::FunctionCall::DisplayMode TestFileParser::parseNewline() | ||||
| { | ||||
| 	if (accept(SoltToken::Newline, true)) | ||||
| 		return FunctionCall::DisplayMode::MultiLine; | ||||
| 	return FunctionCall::DisplayMode::SingleLine; | ||||
| } | ||||
| 
 | ||||
| string TestFileParser::parseComment() | ||||
| { | ||||
| 	string comment = m_scanner.currentLiteral(); | ||||
| @ -286,7 +283,6 @@ void TestFileParser::Scanner::scanNextToken() | ||||
| { | ||||
| 	auto detectToken = [](std::string const& _literal = "") -> TokenDesc { | ||||
| 		if (_literal == "ether") return TokenDesc{SoltToken::Ether, _literal}; | ||||
| 		if (_literal == "uint256") return TokenDesc{SoltToken::UInt, _literal}; | ||||
| 		if (_literal == "FAILURE") return TokenDesc{SoltToken::Failure, _literal}; | ||||
| 		return TokenDesc{SoltToken::Identifier, _literal}; | ||||
| 	}; | ||||
| @ -336,9 +332,9 @@ void TestFileParser::Scanner::scanNextToken() | ||||
| 				TokenDesc detectedToken = detectToken(scanIdentifierOrKeyword()); | ||||
| 				token = selectToken(detectedToken.first, detectedToken.second); | ||||
| 			} | ||||
| 			else if (isDecimalDigit(current())) | ||||
| 			else if (isdigit(current())) | ||||
| 				token = selectToken(SoltToken::Number, scanNumber()); | ||||
| 			else if (isWhiteSpace(current())) | ||||
| 			else if (isspace(current())) | ||||
| 				token = selectToken(SoltToken::Whitespace); | ||||
| 			else if (isEndOfLine()) | ||||
| 				token = selectToken(SoltToken::EOS); | ||||
| @ -348,8 +344,6 @@ void TestFileParser::Scanner::scanNextToken() | ||||
| 		} | ||||
| 	} | ||||
| 	while (token.first == SoltToken::Whitespace); | ||||
| 
 | ||||
| 	m_nextToken = token; | ||||
| 	m_currentToken = token; | ||||
| } | ||||
| 
 | ||||
| @ -382,7 +376,7 @@ string TestFileParser::Scanner::scanNumber() | ||||
| { | ||||
| 	string number; | ||||
| 	number += current(); | ||||
| 	while (isDecimalDigit(peek())) | ||||
| 	while (isdigit(peek())) | ||||
| 	{ | ||||
| 		advance(); | ||||
| 		number += current(); | ||||
|  | ||||
| @ -59,7 +59,6 @@ namespace test | ||||
| 	T(Identifier, "identifier", 0) \ | ||||
| 	/* type keywords */            \ | ||||
| 	K(Ether, "ether", 0)           \ | ||||
| 	K(UInt, "uint256", 0)          \ | ||||
| 	/* special keywords */         \ | ||||
| 	K(Failure, "FAILURE", 0)       \ | ||||
| 
 | ||||
| @ -75,7 +74,9 @@ enum class SoltToken : unsigned int { | ||||
|  * retrieved while parsing a test. This information is used | ||||
|  * for the conversion of human-readable function arguments and | ||||
|  * return values to `bytes` and vice-versa. | ||||
|  * Defaults to an invalid 0-byte representation. | ||||
|  * Defaults to None, a 0-byte representation. 0-bytes | ||||
|  * can also be interpreted as Failure, which means | ||||
|  * either a REVERT or another EVM failure. | ||||
|  */ | ||||
| struct ABIType | ||||
| { | ||||
| @ -85,11 +86,8 @@ struct ABIType | ||||
| 		Failure, | ||||
| 		None | ||||
| 	}; | ||||
| 	ABIType(): type(ABIType::None), size(0) { } | ||||
| 	ABIType(Type _type, size_t _size): type(_type), size(_size) { } | ||||
| 
 | ||||
| 	Type type; | ||||
| 	size_t size; | ||||
| 	Type type = ABIType::None; | ||||
| 	size_t size = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -102,17 +100,19 @@ struct FormatInfo | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Parameter abstraction used for the encoding and decoding | ||||
|  * function parameter lists and expectation lists. | ||||
|  * Parameter abstraction used for the encoding and decoding of | ||||
|  * function parameter and expectation / return value lists. | ||||
|  * A parameter list is usually a comma-separated list of literals. | ||||
|  * It should not be possible to call create a parameter holding | ||||
|  * an identifier, but if so, the ABI type would be invalid. | ||||
|  */ | ||||
| struct Parameter | ||||
| { | ||||
| 	/// ABI encoded `bytes` of parsed expectations. This `bytes`
 | ||||
| 	/// is compared to the actual result of a function call
 | ||||
| 	/// and is taken into account while validating it.
 | ||||
| 	/// ABI encoded / decoded `bytes` of values.
 | ||||
| 	/// These `bytes` are used to pass values to function calls
 | ||||
| 	/// and also to store expected return vales. These are
 | ||||
| 	/// compared to the actual result of a function call
 | ||||
| 	/// and used for validating it.
 | ||||
| 	bytes rawBytes; | ||||
| 	/// Types that were used to encode `rawBytes`. Expectations
 | ||||
| 	/// are usually comma separated literals. Their type is auto-
 | ||||
| @ -133,21 +133,22 @@ using ParameterList = std::vector<Parameter>; | ||||
|  */ | ||||
| struct FunctionCallExpectations | ||||
| { | ||||
| 	/// Representation of the comma-separated (or empty) list of expectation parameters given
 | ||||
| 	/// to a function call.
 | ||||
| 	ParameterList parameters; | ||||
| 	/// Representation of the comma-separated (or empty) list of expectated result values
 | ||||
| 	/// attached to the function call object. It is checked against the actual result of
 | ||||
| 	/// a function call when used in test framework.
 | ||||
| 	ParameterList result; | ||||
| 	/// Expected status of the transaction. It can be either
 | ||||
| 	/// a REVERT or a different EVM failure (e.g. out-of-gas).
 | ||||
| 	bool failure = true; | ||||
| 	/// A Comment that can be attached to the expectations,
 | ||||
| 	/// that is retained and can be displayed.
 | ||||
| 	std::string comment; | ||||
| 	/// ABI encoded `bytes` of parsed parameters. This `bytes`
 | ||||
| 	/// passed to the function call.
 | ||||
| 	/// ABI encoded `bytes` of parsed expected return values. It is checked
 | ||||
| 	/// against the actual result of a function call when used in test framework.
 | ||||
| 	bytes rawBytes() const | ||||
| 	{ | ||||
| 		bytes raw; | ||||
| 		for (auto const& param: parameters) | ||||
| 		for (auto const& param: result) | ||||
| 			raw += param.rawBytes; | ||||
| 		return raw; | ||||
| 	} | ||||
| @ -168,7 +169,7 @@ struct FunctionCallArgs | ||||
| 	/// A Comment that can be attached to the expectations,
 | ||||
| 	/// that is retained and can be displayed.
 | ||||
| 	std::string comment; | ||||
| 	/// ABI encoded `bytes` of parsed parameters. This `bytes`
 | ||||
| 	/// ABI encoded `bytes` of parsed parameters. These `bytes`
 | ||||
| 	/// passed to the function call.
 | ||||
| 	bytes rawBytes() const | ||||
| 	{ | ||||
| @ -257,8 +258,6 @@ private: | ||||
| 		void scanNextToken(); | ||||
| 
 | ||||
| 		SoltToken currentToken() { return m_currentToken.first; } | ||||
| 		SoltToken peekToken() { return m_nextToken.first; } | ||||
| 
 | ||||
| 		std::string currentLiteral() { return m_currentToken.second; } | ||||
| 
 | ||||
| 		std::string scanComment(); | ||||
| @ -283,7 +282,6 @@ private: | ||||
| 		std::string m_currentLiteral; | ||||
| 
 | ||||
| 		TokenDesc m_currentToken; | ||||
| 		TokenDesc m_nextToken; | ||||
| 	}; | ||||
| 
 | ||||
| 	bool accept(SoltToken _token, bool const _expect = false); | ||||
| @ -321,10 +319,6 @@ private: | ||||
| 	/// if data type is not supported.
 | ||||
| 	std::pair<bytes, ABIType> parseABITypeLiteral(); | ||||
| 
 | ||||
| 	/// Accepts a newline `//` and returns DisplayMode::MultiLine
 | ||||
| 	/// if found, DisplayMode::SingleLine otherwise.
 | ||||
| 	FunctionCall::DisplayMode parseNewline(); | ||||
| 
 | ||||
| 	/// Parses a comment
 | ||||
| 	std::string parseComment(); | ||||
| 
 | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| #include <tuple> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <liblangutil/Exceptions.h> | ||||
| #include <test/libsolidity/SolidityExecutionFramework.h> | ||||
| #include <test/ExecutionFramework.h> | ||||
| 
 | ||||
| #include <test/libsolidity/util/TestFileParser.h> | ||||
| 
 | ||||
| @ -37,6 +37,9 @@ namespace solidity | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| using fmt = ExecutionFramework; | ||||
| using Mode = FunctionCall::DisplayMode; | ||||
| 
 | ||||
| vector<FunctionCall> parse(string const& _source) | ||||
| { | ||||
| 	istringstream stream{_source, ios_base::out}; | ||||
| @ -44,51 +47,44 @@ vector<FunctionCall> parse(string const& _source) | ||||
| 	return parser.parseFunctionCalls(); | ||||
| } | ||||
| 
 | ||||
| void testFunctionCall( | ||||
| 		FunctionCall const& _call, | ||||
| 		FunctionCall::DisplayMode _mode, | ||||
| 		string _signature = "", | ||||
| 		bool _failure = true, | ||||
| 		bytes _arguments = bytes{}, | ||||
| 		bytes _expectations = bytes{}, | ||||
| 		u256 _value = 0, | ||||
| 		string _argumentComment = "", | ||||
| 		string _expectationComment = "" | ||||
| ) | ||||
| { | ||||
| 	BOOST_REQUIRE_EQUAL(_call.expectations.failure, _failure); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.signature, _signature); | ||||
| 	ABI_CHECK(_call.arguments.rawBytes(), _arguments); | ||||
| 	ABI_CHECK(_call.expectations.rawBytes(), _expectations); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.displayMode, _mode); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.value, _value); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.arguments.comment, _argumentComment); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.expectations.comment, _expectationComment); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(TestFileParserTest) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(smoke_test) | ||||
| { | ||||
| 	char const* source = R"()"; | ||||
| 	BOOST_CHECK_EQUAL(parse(source).size(), 0); | ||||
| 	BOOST_REQUIRE_EQUAL(parse(source).size(), 0); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(simple_call_succees) | ||||
| BOOST_AUTO_TEST_CASE(call_succees) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256, uint256): 1, 1
 | ||||
| 		// ->
 | ||||
| 		// # This call should not return a value, but still succeed. #
 | ||||
| 		// success() ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "f(uint256,uint256)"); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1}) + toBigEndian(u256{1})); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(simple_single_line_call_success) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): 1 -> # Does not expect a value. #
 | ||||
| 		// f(uint256): 1 -> 1 # Expect return value. #
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 2); | ||||
| 
 | ||||
| 	auto call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "f(uint256)"); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::SingleLine); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1})); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| 
 | ||||
| 	call = calls.at(1); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "f(uint256)"); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::SingleLine); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1})); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), toBigEndian(u256{1})); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "success()", false); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(non_existent_call_revert_single_line) | ||||
| @ -97,31 +93,123 @@ BOOST_AUTO_TEST_CASE(non_existent_call_revert_single_line) | ||||
| 		// i_am_not_there() -> FAILURE
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "i_am_not_there()", true); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_success) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): 1
 | ||||
| 		// ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::MultiLine, "f(uint256)", false, fmt::encodeArgs(u256{1})); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_comments_success) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256, uint256): 1, 1
 | ||||
| 		// ->
 | ||||
| 		// # This call should not return a value, but still succeed. #
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::MultiLine, | ||||
| 		"f(uint256,uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(1, 1), | ||||
| 		fmt::encodeArgs(), | ||||
| 		0, | ||||
| 		"", | ||||
| 		" This call should not return a value, but still succeed. " | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(simple_single_line_call_comment_success) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): 1 -> # f(uint256) does not return a value. #
 | ||||
| 		// f(uint256): 1 -> 1
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 2); | ||||
| 
 | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::SingleLine, | ||||
| 		"f(uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(1), | ||||
| 		fmt::encodeArgs(), | ||||
| 		0, | ||||
| 		"", | ||||
| 		" f(uint256) does not return a value. " | ||||
| 	); | ||||
| 	testFunctionCall(calls.at(1), Mode::SingleLine, "f(uint256)", false, fmt::encode(1), fmt::encode(1)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_single_line) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): 1 -> 1
 | ||||
| 		// g(uint256): 1 ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 2); | ||||
| 
 | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "f(uint256)", false, fmt::encodeArgs(1), fmt::encodeArgs(1)); | ||||
| 	testFunctionCall(calls.at(1), Mode::SingleLine, "g(uint256)", false, fmt::encodeArgs(1)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_single_line_swapped) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): 1 ->
 | ||||
| 		// g(uint256): 1 -> 1
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 2); | ||||
| 
 | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "f(uint256)", false, fmt::encodeArgs(1)); | ||||
| 	testFunctionCall(calls.at(1), Mode::SingleLine, "g(uint256)", false, fmt::encodeArgs(1), fmt::encodeArgs(1)); | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::SingleLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "i_am_not_there()"); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, true); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.parameters.at(0).abiType.type, ABIType::Failure); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(non_existent_call_revert) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// i_am_not_there()
 | ||||
| 		// -> FAILURE # This is can be either REVERT or a different EVM failure #
 | ||||
| 		// -> FAILURE
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::MultiLine, "i_am_not_there()", true); | ||||
| } | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "i_am_not_there()"); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.parameters.at(0).abiType.type, ABIType::Failure); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, true); | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_empty_single_line) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// _exp_() ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "_exp_()", false); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_empty_multiline) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// _exp_()
 | ||||
| 		// ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall(calls.at(0), Mode::MultiLine, "_exp_()", false); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_comments) | ||||
| @ -132,18 +220,29 @@ BOOST_AUTO_TEST_CASE(call_comments) | ||||
| 		// -> 1 # Expectation comment #
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 2); | ||||
| 
 | ||||
| 	BOOST_CHECK_EQUAL(calls.at(0).displayMode, FunctionCall::DisplayMode::SingleLine); | ||||
| 	BOOST_CHECK_EQUAL(calls.at(1).displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 
 | ||||
| 	for (auto const& call: calls) | ||||
| 	{ | ||||
| 		BOOST_CHECK_EQUAL(call.signature, "f()"); | ||||
| 		BOOST_CHECK_EQUAL(call.arguments.comment, " Parameter comment "); | ||||
| 		BOOST_CHECK_EQUAL(call.expectations.comment, " Expectation comment "); | ||||
| 		ABI_CHECK(call.expectations.rawBytes(), toBigEndian(u256{1})); | ||||
| 	} | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 2); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::SingleLine, | ||||
| 		"f()", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(), | ||||
| 		fmt::encodeArgs(1), | ||||
| 		0, | ||||
| 		" Parameter comment ", | ||||
| 		" Expectation comment " | ||||
| 	); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(1), | ||||
| 		Mode::MultiLine, | ||||
| 		"f()", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(), | ||||
| 		fmt::encodeArgs(1), | ||||
| 		0, | ||||
| 		" Parameter comment ", | ||||
| 		" Expectation comment " | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments) | ||||
| @ -153,85 +252,17 @@ BOOST_AUTO_TEST_CASE(call_arguments) | ||||
| 		// -> 4
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "f(uint256)"); | ||||
| 	BOOST_CHECK_EQUAL(call.value, u256{314}); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, false); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{5})); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), toBigEndian(u256{4})); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_empty_single_line) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// _exp_() ->
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::SingleLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "_exp_()"); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), bytes{}); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_empty_multiline) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// _exp_()
 | ||||
| 		// ->
 | ||||
| 		// # This call should not return a value, but still succeed. #
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "_exp_()"); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), bytes{}); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), bytes{}); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_missing) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f())";
 | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_value_expectations_missing) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(), 0)";
 | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): abc -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_value_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256), abc : 1 -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_type_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256), 2 btc : 1 -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::MultiLine, | ||||
| 		"f(uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(5), | ||||
| 		fmt::encodeArgs(4), | ||||
| 		314, | ||||
| 		" optional ether value " | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_mismatch) | ||||
| @ -243,13 +274,17 @@ BOOST_AUTO_TEST_CASE(call_arguments_mismatch) | ||||
| 		// -> 1
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "f(uint256)"); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1}) + toBigEndian(u256{2})); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, false); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::MultiLine, | ||||
| 		"f(uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(1, 2), | ||||
| 		fmt::encodeArgs(1), | ||||
| 		0, | ||||
| 		" This only throws at runtime " | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_multiple_arguments) | ||||
| @ -262,13 +297,15 @@ BOOST_AUTO_TEST_CASE(call_multiple_arguments) | ||||
| 		// 1
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "test(uint256,uint256)"); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1}) + toBigEndian(u256{2})); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, false); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::MultiLine, | ||||
| 		"test(uint256,uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(1, 2), | ||||
| 		fmt::encodeArgs(1, 1) | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_multiple_arguments_mixed_format) | ||||
| @ -279,15 +316,74 @@ BOOST_AUTO_TEST_CASE(call_multiple_arguments_mixed_format) | ||||
| 		// -> -1, 2
 | ||||
| 	)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_CHECK_EQUAL(calls.size(), 1); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||
| 	testFunctionCall( | ||||
| 		calls.at(0), | ||||
| 		Mode::MultiLine, | ||||
| 		"test(uint256,uint256)", | ||||
| 		false, | ||||
| 		fmt::encodeArgs(1, -2), | ||||
| 		fmt::encodeArgs(-1, 2), | ||||
| 		314 | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| 	auto const& call = calls.at(0); | ||||
| 	BOOST_CHECK_EQUAL(call.displayMode, FunctionCall::DisplayMode::MultiLine); | ||||
| 	BOOST_CHECK_EQUAL(call.signature, "test(uint256,uint256)"); | ||||
| 	BOOST_CHECK_EQUAL(call.value, u256{314}); | ||||
| 	ABI_CHECK(call.arguments.rawBytes(), toBigEndian(u256{1}) + toBigEndian(u256{-2})); | ||||
| 	BOOST_CHECK_EQUAL(call.expectations.failure, false); | ||||
| 	ABI_CHECK(call.expectations.rawBytes(), toBigEndian(u256{-1}) + toBigEndian(u256{2})); | ||||
| BOOST_AUTO_TEST_CASE(call_signature) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256, uint8, string) -> FAILURE
 | ||||
| 		// f(invalid, xyz, foo) -> FAILURE
 | ||||
| 		)"; | ||||
| 	auto const calls = parse(source); | ||||
| 	BOOST_REQUIRE_EQUAL(calls.size(), 2); | ||||
| 	testFunctionCall(calls.at(0), Mode::SingleLine, "f(uint256,uint8,string)", true); | ||||
| 	testFunctionCall(calls.at(1), Mode::SingleLine, "f(invalid,xyz,foo)", true); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_signature_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint8,) -> FAILURE
 | ||||
| 		)"; | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_expectations_missing) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f())";
 | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_value_expectations_missing) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(), 0)";
 | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256): abc -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_value_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256), abc : 1 -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_ether_type_invalid) | ||||
| { | ||||
| 	char const* source = R"( | ||||
| 		// f(uint256), 2 btc : 1 -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_colon) | ||||
| @ -296,7 +392,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_colon) | ||||
| 		// h256():
 | ||||
| 		// -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(call_arguments_newline_colon) | ||||
| @ -306,11 +402,9 @@ BOOST_AUTO_TEST_CASE(call_arguments_newline_colon) | ||||
| 		// :
 | ||||
| 		// -> 1
 | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parse(source), langutil::Error); | ||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user