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;
|
||||
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;
|
||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
|
||||
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
|
||||
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
|
||||
return false;
|
||||
|
@ -22,12 +22,18 @@ using namespace solidity;
|
||||
using namespace dev::solidity::test;
|
||||
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 Token = soltest::Token;
|
||||
|
||||
stringstream _stream;
|
||||
stringstream stream;
|
||||
|
||||
bool highlight = !matchesExpectation() && _highlight;
|
||||
|
||||
auto formatOutput = [&](bool const _singleLine)
|
||||
@ -42,16 +48,16 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
||||
string failure = formatToken(Token::Failure);
|
||||
|
||||
/// 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))
|
||||
_stream << comma << ws << m_call.value << ws << ether;
|
||||
stream << comma << ws << m_call.value << ws << ether;
|
||||
if (!m_call.arguments.rawBytes().empty())
|
||||
{
|
||||
string output = formatRawParameters(m_call.arguments.parameters, _linePrefix);
|
||||
_stream << colon;
|
||||
stream << colon;
|
||||
if (_singleLine)
|
||||
_stream << ws;
|
||||
_stream << output;
|
||||
stream << ws;
|
||||
stream << output;
|
||||
|
||||
}
|
||||
|
||||
@ -60,18 +66,18 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
||||
if (_singleLine)
|
||||
{
|
||||
if (!m_call.arguments.comment.empty())
|
||||
_stream << ws << comment << m_call.arguments.comment << comment;
|
||||
_stream << ws << arrow << ws;
|
||||
stream << ws << comment << m_call.arguments.comment << comment;
|
||||
stream << ws << arrow << ws;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream << endl << _linePrefix << newline << ws;
|
||||
stream << endl << _linePrefix << newline << ws;
|
||||
if (!m_call.arguments.comment.empty())
|
||||
{
|
||||
_stream << comment << m_call.arguments.comment << comment;
|
||||
_stream << endl << _linePrefix << newline << ws;
|
||||
stream << comment << m_call.arguments.comment << comment;
|
||||
stream << endl << _linePrefix << newline << ws;
|
||||
}
|
||||
_stream << arrow << ws;
|
||||
stream << arrow << ws;
|
||||
}
|
||||
|
||||
/// Format either the expected output or the actual result output
|
||||
@ -92,47 +98,49 @@ string TestFunctionCall::format(string const& _linePrefix, bool const _renderRes
|
||||
failure :
|
||||
matchesExpectation() ?
|
||||
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.
|
||||
if (_singleLine)
|
||||
{
|
||||
if (!m_call.expectations.comment.empty())
|
||||
_stream << ws << comment << m_call.expectations.comment << comment;
|
||||
stream << ws << comment << m_call.expectations.comment << comment;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_call.expectations.comment.empty())
|
||||
{
|
||||
_stream << endl << _linePrefix << newline << ws;
|
||||
_stream << comment << m_call.expectations.comment << comment;
|
||||
stream << endl << _linePrefix << newline << ws;
|
||||
stream << comment << m_call.expectations.comment << comment;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (m_call.displayMode == FunctionCall::DisplayMode::SingleLine)
|
||||
formatOutput(true);
|
||||
else
|
||||
formatOutput(false);
|
||||
return _stream.str();
|
||||
formatOutput(m_call.displayMode == FunctionCall::DisplayMode::SingleLine);
|
||||
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;
|
||||
|
||||
if (_bytes.empty())
|
||||
return {};
|
||||
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);
|
||||
|
||||
soltestAssert(
|
||||
encodingSize == _bytes.size(),
|
||||
"Encoding does not match byte range: the call returned " +
|
||||
to_string(_bytes.size()) + " bytes, but " +
|
||||
to_string(encodingSize) + " bytes were expected."
|
||||
);
|
||||
if (encodingSize != _bytes.size())
|
||||
_errorReporter.warning(
|
||||
"Encoding does not match byte range. The call returned " +
|
||||
to_string(_bytes.size()) + " bytes, but " +
|
||||
to_string(encodingSize) + " bytes were expected."
|
||||
);
|
||||
|
||||
auto it = _bytes.begin();
|
||||
for (auto const& param: _params)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <libdevcore/AnsiColorized.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
#include <iosfwd>
|
||||
@ -34,6 +35,99 @@ namespace solidity
|
||||
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
|
||||
* representation itself, the actual byte result (if any) and a string representation
|
||||
@ -51,7 +145,25 @@ public:
|
||||
/// the actual result is used.
|
||||
/// If _highlight is false, it's formatted without colorized highlighting. If it's true, AnsiColorized is
|
||||
/// 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
|
||||
/// 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.
|
||||
/// Throws if there's a mismatch in the size of `bytes` and the desired formats that are specified
|
||||
/// 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.
|
||||
std::string formatRawParameters(ParameterList const& _params, std::string const& _linePrefix = "") const;
|
||||
|
Loading…
Reference in New Issue
Block a user