Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add formatted printing to SyntaxTest and expand its public interface.
  • Loading branch information
ekpyron committed Mar 15, 2018
commit 269241e9105a3b3014002bf711ade985d87febe4
66 changes: 66 additions & 0 deletions test/libsolidity/FormattedScope.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
This file is part of solidity.

solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <boost/noncopyable.hpp>

#include <ostream>
#include <vector>

namespace dev
{
namespace solidity
{
namespace test
{

namespace formatting
{

static constexpr char const* RESET = "\033[0m";
static constexpr char const* RED = "\033[1;31m";
static constexpr char const* GREEN = "\033[1;32m";
static constexpr char const* YELLOW = "\033[1;33m";
static constexpr char const* CYAN = "\033[1;36m";
static constexpr char const* BOLD = "\033[1m";
static constexpr char const* INVERSE = "\033[7m";

}

class FormattedScope: boost::noncopyable
{
public:
/// @arg _formatting List of formatting strings (e.g. colors) defined in the formatting namespace.
FormattedScope(std::ostream& _stream, bool const _enabled, std::vector<char const*> const& _formatting):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment that _formatting is supposed to be a vector of colours from the formatted namespace.

m_stream(_stream), m_enabled(_enabled)
{
if (m_enabled)
for (auto const& format: _formatting)
m_stream << format;
}
~FormattedScope() { if (m_enabled) m_stream << formatting::RESET; }
template<typename T>
std::ostream& operator<<(T&& _t) { return m_stream << std::forward<T>(_t); }
private:
std::ostream& m_stream;
bool m_enabled;
};

}
}
}
56 changes: 43 additions & 13 deletions test/libsolidity/SyntaxTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using namespace dev;
using namespace solidity;
using namespace dev::solidity::test;
using namespace dev::solidity::test::formatting;
using namespace std;
namespace fs = boost::filesystem;
using namespace boost::unit_test;
Expand Down Expand Up @@ -56,41 +57,70 @@ SyntaxTest::SyntaxTest(string const& _filename)
m_expectations = parseExpectations(file);
}

bool SyntaxTest::run(ostream& _stream, string const& _indent)
bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
{
m_errorList = parseAnalyseAndReturnError(m_source, true, true, true).second;
if (!matchesExpectations(m_errorList))
{
std::string nextIndentLevel = _indent + "\t";
_stream << _indent << "Expected result:" << endl;
printExpected(_stream, nextIndentLevel);
_stream << _indent << "Obtained result:\n";
printErrorList(_stream, m_errorList, nextIndentLevel);
std::string nextIndentLevel = _linePrefix + " ";
FormattedScope(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
printExpected(_stream, nextIndentLevel, _formatted);
FormattedScope(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:\n";
printErrorList(_stream, m_errorList, nextIndentLevel, false, false, _formatted);
return false;
}
return true;
}

void SyntaxTest::printExpected(ostream& _stream, string const& _indent) const
void SyntaxTest::printExpected(ostream& _stream, string const& _linePrefix, bool const _formatted) const
{
if (m_expectations.empty())
_stream << _indent << "Success" << endl;
FormattedScope(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl;
else
for (auto const& expectation: m_expectations)
_stream << _indent << expectation.type << ": " << expectation.message << endl;
FormattedScope(_stream, _formatted, {BOLD, expectation.type == "Warning" ? YELLOW : RED}) <<
_linePrefix << expectation.type << ": " << expectation.message << endl;
}

void SyntaxTest::printErrorList(
ostream& _stream,
ErrorList const& _errorList,
string const& _indent
string const& _linePrefix,
bool const _ignoreWarnings,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use enums instead? I'm fine with named bit fields, too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure it makes sense to define an enum/bit field for this single function alone?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because then you know what the bools mean.

bool const _lineNumbers,
bool const _formatted
) const
{
if (_errorList.empty())
_stream << _indent << "Success" << endl;
FormattedScope(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl;
else
for (auto const& error: _errorList)
_stream << _indent << error->typeName() << ": " << errorMessage(*error) << endl;
{
bool isWarning = (error->type() == Error::Type::Warning);
if (isWarning && _ignoreWarnings) continue;

FormattedScope scope(_stream, _formatted, {BOLD, isWarning ? YELLOW : RED});
_stream << _linePrefix;
if (_lineNumbers)
{
int line = offsetToLineNumber(
boost::get_error_info<errinfo_sourceLocation>(*error)->start
);
if (line >= 0)
_stream << "(" << line << "): ";
}
_stream << error->typeName() << ": " << errorMessage(*error) << endl;
}
}

int SyntaxTest::offsetToLineNumber(int _location) const
{
// parseAnalyseAndReturnError(...) prepends a version pragma
_location -= strlen("pragma solidity >=0.0;\n");
if (_location < 0 || static_cast<size_t>(_location) >= m_source.size())
return -1;
else
return 1 + std::count(m_source.begin(), m_source.begin() + _location, '\n');
}

bool SyntaxTest::matchesExpectations(ErrorList const& _errorList) const
Expand Down Expand Up @@ -196,7 +226,7 @@ int SyntaxTest::registerTests(
[fullpath]
{
std::stringstream errorStream;
if (!SyntaxTest(fullpath.string()).run(errorStream, ""))
if (!SyntaxTest(fullpath.string()).run(errorStream))
BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str());
},
_path.stem().string(),
Expand Down
17 changes: 14 additions & 3 deletions test/libsolidity/SyntaxTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#pragma once

#include <test/libsolidity/AnalysisFramework.h>
#include <test/libsolidity/FormattedScope.h>
#include <libsolidity/interface/Exceptions.h>

#include <boost/noncopyable.hpp>
Expand Down Expand Up @@ -47,13 +48,22 @@ class SyntaxTest: AnalysisFramework
public:
SyntaxTest(std::string const& _filename);

bool run(std::ostream& _stream, std::string const& _indent);
bool run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false);

std::vector<SyntaxTestExpectation> const& expectations() const { return m_expectations; }
std::string const& source() const { return m_source; }
ErrorList const& errorList() const { return m_errorList; }
ErrorList const& compilerErrors() const { return m_compiler.errors(); }

void printExpected(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted = false) const;

void printExpected(std::ostream& _stream, std::string const& _indent) const;
void printErrorList(
std::ostream& _stream,
ErrorList const& _errors,
std::string const& _indent
std::string const& _linePrefix,
bool const _ignoreWarnings,
bool const _lineNumbers,
bool const _formatted = false
) const;

static int registerTests(
Expand All @@ -66,6 +76,7 @@ class SyntaxTest: AnalysisFramework
static std::string errorMessage(Error const& _e);
static std::string parseSource(std::istream& _stream);
static std::vector<SyntaxTestExpectation> parseExpectations(std::istream& _stream);
int offsetToLineNumber(int _location) const;

std::string m_source;
std::vector<SyntaxTestExpectation> m_expectations;
Expand Down