-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test file parser. #5860
Test file parser. #5860
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #5860 +/- ##
===========================================
+ Coverage 88.35% 88.44% +0.09%
===========================================
Files 353 356 +3
Lines 33692 34127 +435
Branches 4029 4056 +27
===========================================
+ Hits 29767 30184 +417
- Misses 2559 2564 +5
- Partials 1366 1379 +13
|
namespace test | ||
{ | ||
|
||
class TestFileParser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is it used for more than the semantics tests? If not, please add that into the name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should also be used for the syntax tests (upcoming refactoring) which is why I've chosen this name. I'll think of a better name, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, it's of course fine!
std::vector<FunctionCall> parseFunctionCalls(); | ||
|
||
private: | ||
class Scanner { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class Scanner { | |
class Scanner | |
{ |
u256 value; | ||
}; | ||
|
||
static std::string bytesToString(bytes const& _bytes, ByteFormat const& _format); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document. Also, the name sounds too generic. It might also be an option to add that to CommonIO.h.
}; | ||
|
||
static std::string bytesToString(bytes const& _bytes, ByteFormat const& _format); | ||
static std::pair<bytes, ByteFormat> stringToBytes(std::string _string); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
result += newBytes; | ||
} | ||
else | ||
BOOST_THROW_EXCEPTION(std::runtime_error("Test expectations contain invalidly formatted data.")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
solAssert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in testing we don't use solAssert
. BOOST_FAIL_MSG
or BOOST_REQUIRE(false, "Test...")
would be more appropriate?
|
||
vector<TestFileParser::FunctionCall> TestFileParser::parseFunctionCalls() | ||
{ | ||
vector<TestFileParser::FunctionCall> calls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vector<TestFileParser::FunctionCall> calls; | |
vector<FunctionCall> calls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or would that be ambiguous?
void advance() { ++m_char; } | ||
bool advanceLine() | ||
{ | ||
auto& line = getline(m_stream, m_line); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is getline
defined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is declared in <basic_string.h>
for, forwared by <string>
. After reading it again, I'm not sure why the compiler is not complaining about the missing namespace.
{ | ||
auto& line = getline(m_stream, m_line); | ||
m_char = m_line.begin(); | ||
return line ? true : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the type of line
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I think I get your point :) Declared the type explicitly.
call.arguments = parseFunctionCallArgument(); | ||
|
||
if (!advanceLine()) | ||
throw runtime_error("Invalid test expectation. No result specified."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should define a new exception here? What does the syntax tests parser do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should even be BOOST_THROW_EXCEPTION(runtime_error(...))
. And that's what the syntax test also does. They are then being handled by isoltest
and boostTest
, respectively. I think introducing a new exception is a good idea.
2a5ebeb
to
95f1063
Compare
What is the syntax for sending ether and arguments? |
If it is split like this, I suggest:
|
void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c) | ||
{ | ||
if (_it == _end || *_it != _c) | ||
throw std::runtime_error(std::string("Invalid test expectation. Expected: \"") + _c + "\"."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to have explicit std
prefixes in this file since it is imported above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
I previously proposed to split the function arguments. What I meant was that it is possible to add newlines whenever space is allowed and that a line that starts with Example:
|
@axic Oh, the syntax is even wrong. Sorry about that. It would be (note the colon):
or following what @chriseth proposed:
I fear that this might become hard to read. What do you think about making the ether value a "second optional parameter" like below. Something, that I also considered is the potential support of arrays and the current usage of
|
12bd280
to
980aaf2
Compare
There was an error when running
Please check that your changes are working as intended. |
980aaf2
to
8f8f6f8
Compare
Updated. It now parses the following syntax:
I'd like to get some feedback on the ether value. This was my first shot to separate it from the other arguments. Here, I'd now vote for taking @chriseth proposal: #5860 (comment) |
83eb987
to
471908e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments, but I'd say this looks good already!
ad80816
to
f5fa62d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's at least the typo to fix - the other comment would be great, but could be optional for now.
return true; | ||
} | ||
|
||
string TestFileParser::parseFunctionSignature() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this now won't work for signatures involving structs... In the ABI structs are considered tuples, so for f(S memory s, uint256 b) public pure {}
with struct S { uint256 a; bytes32 b; }
the signature would be f((uint256,bytes32),uint256)
.
I would be fine with skipping this for now, but we should at least add a TODO comment about that here. It would be straightforward to count opening and closing parentheses, though, so we could just do it now, as you like... It's not that important, because I think we don't have any test case at the moment that would use it - on the other hand it would be really handy for #1603 of course :-D.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, function signatures do now allow recursive tuples e.g. f(((((bytes, bytes, (bytes)), bytes), bytes), (bytes, bytes)), (bytes, bytes))
. I thought that might be useful.
Let's get this merged soon, #5872 after and then you'll be able to run those tests ;)
6fcb42b
to
f07e4a2
Compare
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature); | ||
|
||
signature += parameters; | ||
/// The last `)` could have been consumed already by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why that could happen...
{ | ||
char const* source = R"( | ||
// f(((((bytes, bytes, bytes), bytes), bytes), bytes), bytes) -> | ||
// f(((((bytes, bytes, (bytes)), bytes), bytes), (bytes, bytes)), (bytes, bytes)) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arguably signatures with spaces in them could/should actually be an error... but since that will probably in fact complicate parsing, I guess we can leave it as it is - we can just not put spaces in there in the tests...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's good point. That should go into the documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A very very common source of problems is using a function that does not exist because of a problem in the signature. The new semantics test infrastructure should detect that, but perhaps not as part of this pull request.
@bit-shift what is the current design? Is the description on the top updated and reflecting what is being implemented? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is nice now! And with this nice parser we can easily change the actual formatting later on, if we want, so I think we should merge it.
NUM_TOKENS | ||
#undef T | ||
}; | ||
namespace solt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not soltest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be also soltest
:) I don't have a strong opinion an that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we just not use any further namespace and still define Token
? We're in namespace dev::solidity::test
already and the other Token
is in dev::solidity
, isn't it? No, it's actually even in langutil
now - in fact I'm not sure whether that's the right place for the other one, but it means there's even less danger of conflict.
But to me this doesn't seem too important - I'm fine with solt
, soltest
or no sub-namespace.
9c97937
to
a10982e
Compare
a10982e
to
c9c4578
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be squashed before merging, but I'd still say it's fine!
Ah damn... looking through #5872 I just realized: |
Description
This PR adds a parser (part of #4223) that will be used in our file-based unit test environment (esp. for semantic tests ran by
isoltest
: #5872). It can parse function call definitions and expected results produced when those are executed later on:Core ideas
Scanner
SoltToken
(meaningsol_t
orSOLT
which stands for "Solidity Test (Language)")(
,)
,:
,->
,,
,#
,[
,]
,identifiers
, type keyword:ether
, special keywordFAILURE
FunctionCall
,FunctionCallArgs
andFunctionCallExpectations
.Single-line / multi-line mode
//
) in source results in a function call that has its display mode set to multi-mode. Function parameter and result value (or expectation parameter) lists are an exception: a single parameter stores a format information that contains a newline definition.Formatting information for semantic tests #5872:
//
, these are also retained, such that they can be printed correctly afterwards.ABIType
, which can beSigned
,Unsigned
,Failure
andNone
for now. These are the types that are used to encode the actual number literals and the special typeFailure
.None
is used to encode no parameters and no return values, resulting in an emptybytes
.Failure
results in an emptybytes
as well, but has different semantics and needs to be handled accordingly.Further development ideas
boost::spirit
that does not change the current interface