mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Adds error reporter for auto-updates in (i)soltest.
This commit is contained in:
parent
39d153b7a1
commit
a6cc296cd9
@ -80,12 +80,19 @@ bool SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _format
|
|||||||
{
|
{
|
||||||
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;
|
{
|
||||||
|
ErrorReporter errorReporter;
|
||||||
|
_stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl;
|
||||||
|
_stream << errorReporter.format(_linePrefix, _formatted);
|
||||||
|
}
|
||||||
_stream << 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;
|
{
|
||||||
|
ErrorReporter errorReporter;
|
||||||
|
_stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl;
|
||||||
|
_stream << errorReporter.format(_linePrefix, _formatted);
|
||||||
|
}
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _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;
|
||||||
|
@ -22,12 +22,18 @@ using namespace solidity;
|
|||||||
using namespace dev::solidity::test;
|
using namespace dev::solidity::test;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string TestFunctionCall::format(string const& _linePrefix, bool const _renderResult, bool const _highlight) const
|
string TestFunctionCall::format(
|
||||||
|
ErrorReporter& _errorReporter,
|
||||||
|
string const& _linePrefix,
|
||||||
|
bool const _renderResult,
|
||||||
|
bool const _highlight
|
||||||
|
) const
|
||||||
{
|
{
|
||||||
using namespace soltest;
|
using namespace soltest;
|
||||||
using Token = soltest::Token;
|
using Token = soltest::Token;
|
||||||
|
|
||||||
stringstream _stream;
|
stringstream stream;
|
||||||
|
|
||||||
bool highlight = !matchesExpectation() && _highlight;
|
bool highlight = !matchesExpectation() && _highlight;
|
||||||
|
|
||||||
auto formatOutput = [&](bool const _singleLine)
|
auto formatOutput = [&](bool const _singleLine)
|
||||||
@ -42,16 +48,16 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
string failure = formatToken(Token::Failure);
|
string failure = formatToken(Token::Failure);
|
||||||
|
|
||||||
/// Formats the function signature. This is the same independent from the display-mode.
|
/// Formats the function signature. This is the same independent from the display-mode.
|
||||||
_stream << _linePrefix << newline << ws << m_call.signature;
|
stream << _linePrefix << newline << ws << m_call.signature;
|
||||||
if (m_call.value > u256(0))
|
if (m_call.value > u256(0))
|
||||||
_stream << comma << ws << m_call.value << ws << ether;
|
stream << comma << ws << m_call.value << ws << ether;
|
||||||
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;
|
stream << colon;
|
||||||
if (_singleLine)
|
if (_singleLine)
|
||||||
_stream << ws;
|
stream << ws;
|
||||||
_stream << output;
|
stream << output;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,18 +66,18 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
if (_singleLine)
|
if (_singleLine)
|
||||||
{
|
{
|
||||||
if (!m_call.arguments.comment.empty())
|
if (!m_call.arguments.comment.empty())
|
||||||
_stream << ws << comment << m_call.arguments.comment << comment;
|
stream << ws << comment << m_call.arguments.comment << comment;
|
||||||
_stream << ws << arrow << ws;
|
stream << ws << arrow << ws;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_stream << endl << _linePrefix << newline << ws;
|
stream << endl << _linePrefix << newline << ws;
|
||||||
if (!m_call.arguments.comment.empty())
|
if (!m_call.arguments.comment.empty())
|
||||||
{
|
{
|
||||||
_stream << comment << m_call.arguments.comment << comment;
|
stream << comment << m_call.arguments.comment << comment;
|
||||||
_stream << endl << _linePrefix << newline << ws;
|
stream << endl << _linePrefix << newline << ws;
|
||||||
}
|
}
|
||||||
_stream << arrow << ws;
|
stream << arrow << ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format either the expected output or the actual result output
|
/// Format either the expected output or the actual result output
|
||||||
@ -92,47 +98,49 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
|||||||
failure :
|
failure :
|
||||||
matchesExpectation() ?
|
matchesExpectation() ?
|
||||||
formatRawParameters(m_call.expectations.result) :
|
formatRawParameters(m_call.expectations.result) :
|
||||||
formatBytesParameters(output, m_call.expectations.result);
|
formatBytesParameters(_errorReporter, output, m_call.expectations.result);
|
||||||
}
|
}
|
||||||
AnsiColorized(_stream, highlight, {dev::formatting::RED_BACKGROUND}) << result;
|
AnsiColorized(stream, highlight, {dev::formatting::RED_BACKGROUND}) << result;
|
||||||
|
|
||||||
/// Format comments on expectations taking the display-mode into account.
|
/// Format comments on expectations taking the display-mode into account.
|
||||||
if (_singleLine)
|
if (_singleLine)
|
||||||
{
|
{
|
||||||
if (!m_call.expectations.comment.empty())
|
if (!m_call.expectations.comment.empty())
|
||||||
_stream << ws << comment << m_call.expectations.comment << comment;
|
stream << ws << comment << m_call.expectations.comment << comment;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!m_call.expectations.comment.empty())
|
if (!m_call.expectations.comment.empty())
|
||||||
{
|
{
|
||||||
_stream << endl << _linePrefix << newline << ws;
|
stream << endl << _linePrefix << newline << ws;
|
||||||
_stream << comment << m_call.expectations.comment << comment;
|
stream << comment << m_call.expectations.comment << comment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_call.displayMode == FunctionCall::DisplayMode::SingleLine)
|
formatOutput(m_call.displayMode == FunctionCall::DisplayMode::SingleLine);
|
||||||
formatOutput(true);
|
return stream.str();
|
||||||
else
|
|
||||||
formatOutput(false);
|
|
||||||
return _stream.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string TestFunctionCall::formatBytesParameters(bytes const& _bytes, dev::solidity::test::ParameterList const& _params) const
|
string TestFunctionCall::formatBytesParameters(
|
||||||
|
ErrorReporter& _errorReporter,
|
||||||
|
bytes const& _bytes,
|
||||||
|
dev::solidity::test::ParameterList const& _params
|
||||||
|
) const
|
||||||
{
|
{
|
||||||
stringstream resultStream;
|
stringstream resultStream;
|
||||||
|
|
||||||
if (_bytes.empty())
|
if (_bytes.empty())
|
||||||
return {};
|
return {};
|
||||||
auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; };
|
auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; };
|
||||||
size_t encodingSize = std::accumulate(_params.begin(), _params.end(), size_t{0}, sizeFold);
|
size_t encodingSize = std::accumulate(_params.begin(), _params.end(), size_t{0}, sizeFold);
|
||||||
|
|
||||||
soltestAssert(
|
if (encodingSize != _bytes.size())
|
||||||
encodingSize == _bytes.size(),
|
_errorReporter.warning(
|
||||||
"Encoding does not match byte range: the call returned " +
|
"Encoding does not match byte range. The call returned " +
|
||||||
to_string(_bytes.size()) + " bytes, but " +
|
to_string(_bytes.size()) + " bytes, but " +
|
||||||
to_string(encodingSize) + " bytes were expected."
|
to_string(encodingSize) + " bytes were expected."
|
||||||
);
|
);
|
||||||
|
|
||||||
auto it = _bytes.begin();
|
auto it = _bytes.begin();
|
||||||
for (auto const& param: _params)
|
for (auto const& param: _params)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
#include <libdevcore/AnsiColorized.h>
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
@ -34,6 +35,99 @@ namespace solidity
|
|||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a notice, warning or error that can occur while
|
||||||
|
* formatting and therefore updating an interactive function call test.
|
||||||
|
*/
|
||||||
|
struct FormatError
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Notice,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit FormatError(Type _type, std::string _message):
|
||||||
|
type(_type),
|
||||||
|
message(std::move(_message))
|
||||||
|
{}
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
using FormatErrors = std::vector<FormatError>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class that collects notices, warnings and errors and is able
|
||||||
|
* to format them for ANSI colorized output during the interactive update
|
||||||
|
* process in isoltest.
|
||||||
|
* It's purpose is to help users of isoltest to automatically
|
||||||
|
* update test files but always keep track of what is happening.
|
||||||
|
*/
|
||||||
|
class ErrorReporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ErrorReporter() {}
|
||||||
|
|
||||||
|
/// Adds a new FormatError of type Notice with the given message.
|
||||||
|
void notice(std::string _notice)
|
||||||
|
{
|
||||||
|
m_errors.push_back(FormatError{FormatError::Notice, std::move(_notice)});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a new FormatError of type Warning with the given message.
|
||||||
|
void warning(std::string _warning)
|
||||||
|
{
|
||||||
|
m_errors.push_back(FormatError{FormatError::Warning, std::move(_warning)});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a new FormatError of type Error with the given message.
|
||||||
|
void error(std::string _error)
|
||||||
|
{
|
||||||
|
m_errors.push_back(FormatError{FormatError::Error, std::move(_error)});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints all errors depending on their type using ANSI colorized output.
|
||||||
|
/// It will be used to print notices, warnings and errors during the
|
||||||
|
/// interactive update process.
|
||||||
|
std::string format(std::string const& _linePrefix, bool _formatted)
|
||||||
|
{
|
||||||
|
std::stringstream os;
|
||||||
|
for (auto const& error: m_errors)
|
||||||
|
{
|
||||||
|
switch (error.type)
|
||||||
|
{
|
||||||
|
case FormatError::Notice:
|
||||||
|
AnsiColorized(
|
||||||
|
os,
|
||||||
|
_formatted,
|
||||||
|
{formatting::WHITE}
|
||||||
|
) << _linePrefix << "Notice: " << error.message << std::endl;
|
||||||
|
break;
|
||||||
|
case FormatError::Warning:
|
||||||
|
AnsiColorized(
|
||||||
|
os,
|
||||||
|
_formatted,
|
||||||
|
{formatting::YELLOW}
|
||||||
|
) << _linePrefix << "Warning: " << error.message << std::endl;
|
||||||
|
break;
|
||||||
|
case FormatError::Error:
|
||||||
|
AnsiColorized(
|
||||||
|
os,
|
||||||
|
_formatted,
|
||||||
|
{formatting::RED}
|
||||||
|
) << _linePrefix << "Error: " << error.message << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FormatErrors m_errors;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a function call and the result it returned. It stores the call
|
* Represents a function call and the result it returned. It stores the call
|
||||||
* representation itself, the actual byte result (if any) and a string representation
|
* representation itself, the actual byte result (if any) and a string representation
|
||||||
@ -51,7 +145,25 @@ public:
|
|||||||
/// the actual result is used.
|
/// the actual result is used.
|
||||||
/// If _highlight is false, it's formatted without colorized highlighting. If it's true, AnsiColorized is
|
/// If _highlight is false, it's formatted without colorized highlighting. If it's true, AnsiColorized is
|
||||||
/// used to apply a colorized highlighting.
|
/// used to apply a colorized highlighting.
|
||||||
std::string format(std::string const& _linePrefix = "", bool const _renderResult = false, bool const _highlight = false) const;
|
/// Reports warnings and errors to the error reporter.
|
||||||
|
std::string format(
|
||||||
|
ErrorReporter& _errorReporter,
|
||||||
|
std::string const& _linePrefix = "",
|
||||||
|
bool const _renderResult = false,
|
||||||
|
bool const _highlight = false
|
||||||
|
) const;
|
||||||
|
|
||||||
|
/// Overloaded version that passes an error reporter which is never used outside
|
||||||
|
/// of this function.
|
||||||
|
std::string format(
|
||||||
|
std::string const& _linePrefix = "",
|
||||||
|
bool const _renderResult = false,
|
||||||
|
bool const _highlight = false
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
ErrorReporter reporter;
|
||||||
|
return format(reporter, _linePrefix, _renderResult, _highlight);
|
||||||
|
}
|
||||||
|
|
||||||
/// Resets current results in case the function was called and the result
|
/// Resets current results in case the function was called and the result
|
||||||
/// stored already (e.g. if test case was updated via isoltest).
|
/// stored already (e.g. if test case was updated via isoltest).
|
||||||
@ -65,7 +177,12 @@ private:
|
|||||||
/// Tries to format the given `bytes`, applying the detected ABI types that have be set for each parameter.
|
/// Tries to format the given `bytes`, applying the detected ABI types that have be set for each parameter.
|
||||||
/// Throws if there's a mismatch in the size of `bytes` and the desired formats that are specified
|
/// Throws if there's a mismatch in the size of `bytes` and the desired formats that are specified
|
||||||
/// in the ABI type.
|
/// in the ABI type.
|
||||||
std::string formatBytesParameters(bytes const& _bytes, ParameterList const& _params) const;
|
/// Reports warnings and errors to the error reporter.
|
||||||
|
std::string formatBytesParameters(
|
||||||
|
ErrorReporter& _errorReporter,
|
||||||
|
bytes const& _bytes,
|
||||||
|
ParameterList const& _params
|
||||||
|
) const;
|
||||||
|
|
||||||
/// Formats the given parameters using their raw string representation.
|
/// Formats the given parameters using their raw string representation.
|
||||||
std::string formatRawParameters(ParameterList const& _params, std::string const& _linePrefix = "") const;
|
std::string formatRawParameters(ParameterList const& _params, std::string const& _linePrefix = "") const;
|
||||||
|
Loading…
Reference in New Issue
Block a user