mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 07:16:10 +01:00
Provide ConsoleReporter declaration with EXTERNAL_INTERFACES
Related to #991
This commit is contained in:
parent
a096e4b3f2
commit
98d4c49d1c
@ -248,6 +248,7 @@ set(REPORTER_HEADERS
|
|||||||
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
||||||
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
||||||
${HEADER_DIR}/reporters/catch_reporter_compact.h
|
${HEADER_DIR}/reporters/catch_reporter_compact.h
|
||||||
|
${HEADER_DIR}/reporters/catch_reporter_console.h
|
||||||
${HEADER_DIR}/reporters/catch_reporter_junit.h
|
${HEADER_DIR}/reporters/catch_reporter_junit.h
|
||||||
${HEADER_DIR}/reporters/catch_reporter_multi.h
|
${HEADER_DIR}/reporters/catch_reporter_multi.h
|
||||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
// Allow users to base their work off existing reporters
|
// Allow users to base their work off existing reporters
|
||||||
#include "../reporters/catch_reporter_compact.h"
|
#include "../reporters/catch_reporter_compact.h"
|
||||||
|
#include "../reporters/catch_reporter_console.h"
|
||||||
#include "../reporters/catch_reporter_junit.h"
|
#include "../reporters/catch_reporter_junit.h"
|
||||||
#include "../reporters/catch_reporter_xml.h"
|
#include "../reporters/catch_reporter_xml.h"
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_reporter_bases.hpp"
|
#include "catch_reporter_console.h"
|
||||||
|
|
||||||
#include "../internal/catch_reporter_registrars.hpp"
|
#include "../internal/catch_reporter_registrars.hpp"
|
||||||
#include "internal/catch_console_colour.h"
|
#include "internal/catch_console_colour.h"
|
||||||
@ -28,6 +28,147 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Formatter impl for ConsoleReporter
|
||||||
|
class AssertionPrinter {
|
||||||
|
public:
|
||||||
|
AssertionPrinter& operator= (AssertionPrinter const&) = delete;
|
||||||
|
AssertionPrinter(AssertionPrinter const&) = delete;
|
||||||
|
AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
|
||||||
|
: stream(_stream),
|
||||||
|
stats(_stats),
|
||||||
|
result(_stats.assertionResult),
|
||||||
|
colour(Colour::None),
|
||||||
|
message(result.getMessage()),
|
||||||
|
messages(_stats.infoMessages),
|
||||||
|
printInfoMessages(_printInfoMessages) {
|
||||||
|
switch (result.getResultType()) {
|
||||||
|
case ResultWas::Ok:
|
||||||
|
colour = Colour::Success;
|
||||||
|
passOrFail = "PASSED";
|
||||||
|
//if( result.hasMessage() )
|
||||||
|
if (_stats.infoMessages.size() == 1)
|
||||||
|
messageLabel = "with message";
|
||||||
|
if (_stats.infoMessages.size() > 1)
|
||||||
|
messageLabel = "with messages";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
if (result.isOk()) {
|
||||||
|
colour = Colour::Success;
|
||||||
|
passOrFail = "FAILED - but was ok";
|
||||||
|
} else {
|
||||||
|
colour = Colour::Error;
|
||||||
|
passOrFail = "FAILED";
|
||||||
|
}
|
||||||
|
if (_stats.infoMessages.size() == 1)
|
||||||
|
messageLabel = "with message";
|
||||||
|
if (_stats.infoMessages.size() > 1)
|
||||||
|
messageLabel = "with messages";
|
||||||
|
break;
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
colour = Colour::Error;
|
||||||
|
passOrFail = "FAILED";
|
||||||
|
messageLabel = "due to unexpected exception with ";
|
||||||
|
if (_stats.infoMessages.size() == 1)
|
||||||
|
messageLabel += "message";
|
||||||
|
if (_stats.infoMessages.size() > 1)
|
||||||
|
messageLabel += "messages";
|
||||||
|
break;
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
colour = Colour::Error;
|
||||||
|
passOrFail = "FAILED";
|
||||||
|
messageLabel = "due to a fatal error condition";
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
colour = Colour::Error;
|
||||||
|
passOrFail = "FAILED";
|
||||||
|
messageLabel = "because no exception was thrown where one was expected";
|
||||||
|
break;
|
||||||
|
case ResultWas::Info:
|
||||||
|
messageLabel = "info";
|
||||||
|
break;
|
||||||
|
case ResultWas::Warning:
|
||||||
|
messageLabel = "warning";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
passOrFail = "FAILED";
|
||||||
|
colour = Colour::Error;
|
||||||
|
if (_stats.infoMessages.size() == 1)
|
||||||
|
messageLabel = "explicitly with message";
|
||||||
|
if (_stats.infoMessages.size() > 1)
|
||||||
|
messageLabel = "explicitly with messages";
|
||||||
|
break;
|
||||||
|
// These cases are here to prevent compiler warnings
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
passOrFail = "** internal error **";
|
||||||
|
colour = Colour::Error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() const {
|
||||||
|
printSourceInfo();
|
||||||
|
if (stats.totals.assertions.total() > 0) {
|
||||||
|
if (result.isOk())
|
||||||
|
stream << '\n';
|
||||||
|
printResultType();
|
||||||
|
printOriginalExpression();
|
||||||
|
printReconstructedExpression();
|
||||||
|
} else {
|
||||||
|
stream << '\n';
|
||||||
|
}
|
||||||
|
printMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printResultType() const {
|
||||||
|
if (!passOrFail.empty()) {
|
||||||
|
Colour colourGuard(colour);
|
||||||
|
stream << passOrFail << ":\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void printOriginalExpression() const {
|
||||||
|
if (result.hasExpression()) {
|
||||||
|
Colour colourGuard(Colour::OriginalExpression);
|
||||||
|
stream << " ";
|
||||||
|
stream << result.getExpressionInMacro();
|
||||||
|
stream << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void printReconstructedExpression() const {
|
||||||
|
if (result.hasExpandedExpression()) {
|
||||||
|
stream << "with expansion:\n";
|
||||||
|
Colour colourGuard(Colour::ReconstructedExpression);
|
||||||
|
stream << Column(result.getExpandedExpression()).indent(2) << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void printMessage() const {
|
||||||
|
if (!messageLabel.empty())
|
||||||
|
stream << messageLabel << ':' << '\n';
|
||||||
|
for (auto const& msg : messages) {
|
||||||
|
// If this assertion is a warning ignore any INFO messages
|
||||||
|
if (printInfoMessages || msg.type != ResultWas::Info)
|
||||||
|
stream << Column(msg.message).indent(2) << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void printSourceInfo() const {
|
||||||
|
Colour colourGuard(Colour::FileName);
|
||||||
|
stream << result.getSourceInfo() << ": ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& stream;
|
||||||
|
AssertionStats const& stats;
|
||||||
|
AssertionResult const& result;
|
||||||
|
Colour::Code colour;
|
||||||
|
std::string passOrFail;
|
||||||
|
std::string messageLabel;
|
||||||
|
std::string message;
|
||||||
|
std::vector<MessageInfo> messages;
|
||||||
|
bool printInfoMessages;
|
||||||
|
};
|
||||||
|
|
||||||
std::size_t makeRatio(std::size_t number, std::size_t total) {
|
std::size_t makeRatio(std::size_t number, std::size_t total) {
|
||||||
std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
|
std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
|
||||||
return (ratio == 0 && number > 0) ? 1 : ratio;
|
return (ratio == 0 && number > 0) ? 1 : ratio;
|
||||||
@ -51,6 +192,79 @@ namespace Catch {
|
|||||||
struct ColumnBreak {};
|
struct ColumnBreak {};
|
||||||
struct RowBreak {};
|
struct RowBreak {};
|
||||||
|
|
||||||
|
class Duration {
|
||||||
|
enum class Unit {
|
||||||
|
Auto,
|
||||||
|
Nanoseconds,
|
||||||
|
Microseconds,
|
||||||
|
Milliseconds,
|
||||||
|
Seconds,
|
||||||
|
Minutes
|
||||||
|
};
|
||||||
|
static const uint64_t s_nanosecondsInAMicrosecond = 1000;
|
||||||
|
static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
|
||||||
|
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
|
||||||
|
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
|
||||||
|
|
||||||
|
uint64_t m_inNanoseconds;
|
||||||
|
Unit m_units;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
|
||||||
|
: m_inNanoseconds(inNanoseconds),
|
||||||
|
m_units(units) {
|
||||||
|
if (m_units == Unit::Auto) {
|
||||||
|
if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
|
||||||
|
m_units = Unit::Nanoseconds;
|
||||||
|
else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
|
||||||
|
m_units = Unit::Microseconds;
|
||||||
|
else if (m_inNanoseconds < s_nanosecondsInASecond)
|
||||||
|
m_units = Unit::Milliseconds;
|
||||||
|
else if (m_inNanoseconds < s_nanosecondsInAMinute)
|
||||||
|
m_units = Unit::Seconds;
|
||||||
|
else
|
||||||
|
m_units = Unit::Minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value() const -> double {
|
||||||
|
switch (m_units) {
|
||||||
|
case Unit::Microseconds:
|
||||||
|
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
|
||||||
|
case Unit::Milliseconds:
|
||||||
|
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
|
||||||
|
case Unit::Seconds:
|
||||||
|
return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
|
||||||
|
case Unit::Minutes:
|
||||||
|
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
|
||||||
|
default:
|
||||||
|
return static_cast<double>(m_inNanoseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto unitsAsString() const -> std::string {
|
||||||
|
switch (m_units) {
|
||||||
|
case Unit::Nanoseconds:
|
||||||
|
return "ns";
|
||||||
|
case Unit::Microseconds:
|
||||||
|
return "µs";
|
||||||
|
case Unit::Milliseconds:
|
||||||
|
return "ms";
|
||||||
|
case Unit::Seconds:
|
||||||
|
return "s";
|
||||||
|
case Unit::Minutes:
|
||||||
|
return "m";
|
||||||
|
default:
|
||||||
|
return "** internal error **";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
|
||||||
|
return os << duration.value() << " " << duration.unitsAsString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end anon namespace
|
||||||
|
|
||||||
class TablePrinter {
|
class TablePrinter {
|
||||||
std::ostream& m_os;
|
std::ostream& m_os;
|
||||||
std::vector<ColumnInfo> m_columnInfos;
|
std::vector<ColumnInfo> m_columnInfos;
|
||||||
@ -61,8 +275,7 @@ namespace Catch {
|
|||||||
public:
|
public:
|
||||||
TablePrinter(std::ostream& os, std::vector<ColumnInfo> const& columnInfos)
|
TablePrinter(std::ostream& os, std::vector<ColumnInfo> const& columnInfos)
|
||||||
: m_os(os),
|
: m_os(os),
|
||||||
m_columnInfos( columnInfos )
|
m_columnInfos(columnInfos) {}
|
||||||
{}
|
|
||||||
|
|
||||||
auto columnInfos() const -> std::vector<ColumnInfo> const& {
|
auto columnInfos() const -> std::vector<ColumnInfo> const& {
|
||||||
return m_columnInfos;
|
return m_columnInfos;
|
||||||
@ -124,106 +337,27 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Duration {
|
ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
|
||||||
enum class Unit {
|
|
||||||
Auto,
|
|
||||||
Nanoseconds,
|
|
||||||
Microseconds,
|
|
||||||
Milliseconds,
|
|
||||||
Seconds,
|
|
||||||
Minutes
|
|
||||||
};
|
|
||||||
static const uint64_t s_nanosecondsInAMicrosecond = 1000;
|
|
||||||
static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond;
|
|
||||||
static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond;
|
|
||||||
static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond;
|
|
||||||
|
|
||||||
uint64_t m_inNanoseconds;
|
|
||||||
Unit m_units;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Duration( uint64_t inNanoseconds, Unit units = Unit::Auto )
|
|
||||||
: m_inNanoseconds( inNanoseconds ),
|
|
||||||
m_units( units )
|
|
||||||
{
|
|
||||||
if( m_units == Unit::Auto ) {
|
|
||||||
if( m_inNanoseconds < s_nanosecondsInAMicrosecond )
|
|
||||||
m_units = Unit::Nanoseconds;
|
|
||||||
else if( m_inNanoseconds < s_nanosecondsInAMillisecond )
|
|
||||||
m_units = Unit::Microseconds;
|
|
||||||
else if( m_inNanoseconds < s_nanosecondsInASecond )
|
|
||||||
m_units = Unit::Milliseconds;
|
|
||||||
else if( m_inNanoseconds < s_nanosecondsInAMinute )
|
|
||||||
m_units = Unit::Seconds;
|
|
||||||
else
|
|
||||||
m_units = Unit::Minutes;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
auto value() const -> double {
|
|
||||||
switch( m_units ) {
|
|
||||||
case Unit::Microseconds:
|
|
||||||
return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMicrosecond );
|
|
||||||
case Unit::Milliseconds:
|
|
||||||
return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMillisecond );
|
|
||||||
case Unit::Seconds:
|
|
||||||
return m_inNanoseconds / static_cast<double>( s_nanosecondsInASecond );
|
|
||||||
case Unit::Minutes:
|
|
||||||
return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMinute );
|
|
||||||
default:
|
|
||||||
return static_cast<double>( m_inNanoseconds );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto unitsAsString() const -> std::string {
|
|
||||||
switch( m_units ) {
|
|
||||||
case Unit::Nanoseconds:
|
|
||||||
return "ns";
|
|
||||||
case Unit::Microseconds:
|
|
||||||
return "µs";
|
|
||||||
case Unit::Milliseconds:
|
|
||||||
return "ms";
|
|
||||||
case Unit::Seconds:
|
|
||||||
return "s";
|
|
||||||
case Unit::Minutes:
|
|
||||||
return "m";
|
|
||||||
default:
|
|
||||||
return "** internal error **";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& {
|
|
||||||
return os << duration.value() << " " << duration.unitsAsString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anon namespace
|
|
||||||
|
|
||||||
struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
|
|
||||||
TablePrinter m_tablePrinter;
|
|
||||||
|
|
||||||
ConsoleReporter( ReporterConfig const& config )
|
|
||||||
: StreamingReporterBase(config),
|
: StreamingReporterBase(config),
|
||||||
m_tablePrinter( config.stream(),
|
m_tablePrinter(new TablePrinter(config.stream(),
|
||||||
{
|
{
|
||||||
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
|
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
|
||||||
{ "iters", 8, ColumnInfo::Right },
|
{ "iters", 8, ColumnInfo::Right },
|
||||||
{ "elapsed ns", 14, ColumnInfo::Right },
|
{ "elapsed ns", 14, ColumnInfo::Right },
|
||||||
{ "average", 14, ColumnInfo::Right }
|
{ "average", 14, ColumnInfo::Right }
|
||||||
} )
|
})) {}
|
||||||
{}
|
ConsoleReporter::~ConsoleReporter() {}
|
||||||
~ConsoleReporter() override;
|
std::string ConsoleReporter::getDescription() {
|
||||||
static std::string getDescription() {
|
|
||||||
return "Reports test results as plain lines of text";
|
return "Reports test results as plain lines of text";
|
||||||
}
|
}
|
||||||
|
|
||||||
void noMatchingTestCases( std::string const& spec ) override {
|
void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
|
||||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertionStarting( AssertionInfo const& ) override {
|
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
|
||||||
}
|
|
||||||
|
|
||||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
|
||||||
AssertionResult const& result = _assertionStats.assertionResult;
|
AssertionResult const& result = _assertionStats.assertionResult;
|
||||||
|
|
||||||
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
|
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
|
||||||
@ -240,12 +374,12 @@ namespace Catch {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sectionStarting( SectionInfo const& _sectionInfo ) override {
|
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
|
||||||
m_headerPrinted = false;
|
m_headerPrinted = false;
|
||||||
StreamingReporterBase::sectionStarting(_sectionInfo);
|
StreamingReporterBase::sectionStarting(_sectionInfo);
|
||||||
}
|
}
|
||||||
void sectionEnded( SectionStats const& _sectionStats ) override {
|
void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
|
||||||
m_tablePrinter.close();
|
m_tablePrinter->close();
|
||||||
if (_sectionStats.missingAssertions) {
|
if (_sectionStats.missingAssertions) {
|
||||||
lazyPrint();
|
lazyPrint();
|
||||||
Colour colour(Colour::ResultError);
|
Colour colour(Colour::ResultError);
|
||||||
@ -265,35 +399,35 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void benchmarkStarting( BenchmarkInfo const& info ) override {
|
void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
|
||||||
lazyPrintWithoutClosingBenchmarkTable();
|
lazyPrintWithoutClosingBenchmarkTable();
|
||||||
|
|
||||||
auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 );
|
auto nameCol = Column(info.name).width(m_tablePrinter->columnInfos()[0].width - 2);
|
||||||
|
|
||||||
bool firstLine = true;
|
bool firstLine = true;
|
||||||
for (auto line : nameCol) {
|
for (auto line : nameCol) {
|
||||||
if (!firstLine)
|
if (!firstLine)
|
||||||
m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak();
|
(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
|
||||||
else
|
else
|
||||||
firstLine = false;
|
firstLine = false;
|
||||||
|
|
||||||
m_tablePrinter << line << ColumnBreak();
|
(*m_tablePrinter) << line << ColumnBreak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void benchmarkEnded( BenchmarkStats const& stats ) override {
|
void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
|
||||||
Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
|
Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
|
||||||
m_tablePrinter
|
(*m_tablePrinter)
|
||||||
<< stats.iterations << ColumnBreak()
|
<< stats.iterations << ColumnBreak()
|
||||||
<< stats.elapsedTimeInNanoseconds << ColumnBreak()
|
<< stats.elapsedTimeInNanoseconds << ColumnBreak()
|
||||||
<< average << ColumnBreak();
|
<< average << ColumnBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
void testCaseEnded( TestCaseStats const& _testCaseStats ) override {
|
void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
|
||||||
m_tablePrinter.close();
|
m_tablePrinter->close();
|
||||||
StreamingReporterBase::testCaseEnded(_testCaseStats);
|
StreamingReporterBase::testCaseEnded(_testCaseStats);
|
||||||
m_headerPrinted = false;
|
m_headerPrinted = false;
|
||||||
}
|
}
|
||||||
void testGroupEnded( TestGroupStats const& _testGroupStats ) override {
|
void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {
|
||||||
if (currentGroupInfo.used) {
|
if (currentGroupInfo.used) {
|
||||||
printSummaryDivider();
|
printSummaryDivider();
|
||||||
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
||||||
@ -302,164 +436,20 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
StreamingReporterBase::testGroupEnded(_testGroupStats);
|
StreamingReporterBase::testGroupEnded(_testGroupStats);
|
||||||
}
|
}
|
||||||
void testRunEnded( TestRunStats const& _testRunStats ) override {
|
void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
|
||||||
printTotalsDivider(_testRunStats.totals);
|
printTotalsDivider(_testRunStats.totals);
|
||||||
printTotals(_testRunStats.totals);
|
printTotals(_testRunStats.totals);
|
||||||
stream << std::endl;
|
stream << std::endl;
|
||||||
StreamingReporterBase::testRunEnded(_testRunStats);
|
StreamingReporterBase::testRunEnded(_testRunStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void ConsoleReporter::lazyPrint() {
|
||||||
|
|
||||||
class AssertionPrinter {
|
m_tablePrinter->close();
|
||||||
public:
|
|
||||||
AssertionPrinter& operator= ( AssertionPrinter const& ) = delete;
|
|
||||||
AssertionPrinter( AssertionPrinter const& ) = delete;
|
|
||||||
AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
|
|
||||||
: stream( _stream ),
|
|
||||||
stats( _stats ),
|
|
||||||
result( _stats.assertionResult ),
|
|
||||||
colour( Colour::None ),
|
|
||||||
message( result.getMessage() ),
|
|
||||||
messages( _stats.infoMessages ),
|
|
||||||
printInfoMessages( _printInfoMessages )
|
|
||||||
{
|
|
||||||
switch( result.getResultType() ) {
|
|
||||||
case ResultWas::Ok:
|
|
||||||
colour = Colour::Success;
|
|
||||||
passOrFail = "PASSED";
|
|
||||||
//if( result.hasMessage() )
|
|
||||||
if( _stats.infoMessages.size() == 1 )
|
|
||||||
messageLabel = "with message";
|
|
||||||
if( _stats.infoMessages.size() > 1 )
|
|
||||||
messageLabel = "with messages";
|
|
||||||
break;
|
|
||||||
case ResultWas::ExpressionFailed:
|
|
||||||
if( result.isOk() ) {
|
|
||||||
colour = Colour::Success;
|
|
||||||
passOrFail = "FAILED - but was ok";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
colour = Colour::Error;
|
|
||||||
passOrFail = "FAILED";
|
|
||||||
}
|
|
||||||
if( _stats.infoMessages.size() == 1 )
|
|
||||||
messageLabel = "with message";
|
|
||||||
if( _stats.infoMessages.size() > 1 )
|
|
||||||
messageLabel = "with messages";
|
|
||||||
break;
|
|
||||||
case ResultWas::ThrewException:
|
|
||||||
colour = Colour::Error;
|
|
||||||
passOrFail = "FAILED";
|
|
||||||
messageLabel = "due to unexpected exception with ";
|
|
||||||
if (_stats.infoMessages.size() == 1)
|
|
||||||
messageLabel += "message";
|
|
||||||
if (_stats.infoMessages.size() > 1)
|
|
||||||
messageLabel += "messages";
|
|
||||||
break;
|
|
||||||
case ResultWas::FatalErrorCondition:
|
|
||||||
colour = Colour::Error;
|
|
||||||
passOrFail = "FAILED";
|
|
||||||
messageLabel = "due to a fatal error condition";
|
|
||||||
break;
|
|
||||||
case ResultWas::DidntThrowException:
|
|
||||||
colour = Colour::Error;
|
|
||||||
passOrFail = "FAILED";
|
|
||||||
messageLabel = "because no exception was thrown where one was expected";
|
|
||||||
break;
|
|
||||||
case ResultWas::Info:
|
|
||||||
messageLabel = "info";
|
|
||||||
break;
|
|
||||||
case ResultWas::Warning:
|
|
||||||
messageLabel = "warning";
|
|
||||||
break;
|
|
||||||
case ResultWas::ExplicitFailure:
|
|
||||||
passOrFail = "FAILED";
|
|
||||||
colour = Colour::Error;
|
|
||||||
if( _stats.infoMessages.size() == 1 )
|
|
||||||
messageLabel = "explicitly with message";
|
|
||||||
if( _stats.infoMessages.size() > 1 )
|
|
||||||
messageLabel = "explicitly with messages";
|
|
||||||
break;
|
|
||||||
// These cases are here to prevent compiler warnings
|
|
||||||
case ResultWas::Unknown:
|
|
||||||
case ResultWas::FailureBit:
|
|
||||||
case ResultWas::Exception:
|
|
||||||
passOrFail = "** internal error **";
|
|
||||||
colour = Colour::Error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const {
|
|
||||||
printSourceInfo();
|
|
||||||
if( stats.totals.assertions.total() > 0 ) {
|
|
||||||
if( result.isOk() )
|
|
||||||
stream << '\n';
|
|
||||||
printResultType();
|
|
||||||
printOriginalExpression();
|
|
||||||
printReconstructedExpression();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
stream << '\n';
|
|
||||||
}
|
|
||||||
printMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void printResultType() const {
|
|
||||||
if( !passOrFail.empty() ) {
|
|
||||||
Colour colourGuard( colour );
|
|
||||||
stream << passOrFail << ":\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void printOriginalExpression() const {
|
|
||||||
if( result.hasExpression() ) {
|
|
||||||
Colour colourGuard( Colour::OriginalExpression );
|
|
||||||
stream << " ";
|
|
||||||
stream << result.getExpressionInMacro();
|
|
||||||
stream << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void printReconstructedExpression() const {
|
|
||||||
if( result.hasExpandedExpression() ) {
|
|
||||||
stream << "with expansion:\n";
|
|
||||||
Colour colourGuard( Colour::ReconstructedExpression );
|
|
||||||
stream << Column( result.getExpandedExpression() ).indent(2) << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void printMessage() const {
|
|
||||||
if( !messageLabel.empty() )
|
|
||||||
stream << messageLabel << ':' << '\n';
|
|
||||||
for( auto const& msg : messages ) {
|
|
||||||
// If this assertion is a warning ignore any INFO messages
|
|
||||||
if( printInfoMessages || msg.type != ResultWas::Info )
|
|
||||||
stream << Column( msg.message ).indent(2) << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void printSourceInfo() const {
|
|
||||||
Colour colourGuard( Colour::FileName );
|
|
||||||
stream << result.getSourceInfo() << ": ";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& stream;
|
|
||||||
AssertionStats const& stats;
|
|
||||||
AssertionResult const& result;
|
|
||||||
Colour::Code colour;
|
|
||||||
std::string passOrFail;
|
|
||||||
std::string messageLabel;
|
|
||||||
std::string message;
|
|
||||||
std::vector<MessageInfo> messages;
|
|
||||||
bool printInfoMessages;
|
|
||||||
};
|
|
||||||
|
|
||||||
void lazyPrint() {
|
|
||||||
|
|
||||||
m_tablePrinter.close();
|
|
||||||
lazyPrintWithoutClosingBenchmarkTable();
|
lazyPrintWithoutClosingBenchmarkTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lazyPrintWithoutClosingBenchmarkTable() {
|
void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
|
||||||
|
|
||||||
if (!currentTestRunInfo.used)
|
if (!currentTestRunInfo.used)
|
||||||
lazyPrintRunInfo();
|
lazyPrintRunInfo();
|
||||||
@ -471,7 +461,7 @@ namespace Catch {
|
|||||||
m_headerPrinted = true;
|
m_headerPrinted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void lazyPrintRunInfo() {
|
void ConsoleReporter::lazyPrintRunInfo() {
|
||||||
stream << '\n' << getLineOfChars<'~'>() << '\n';
|
stream << '\n' << getLineOfChars<'~'>() << '\n';
|
||||||
Colour colour(Colour::SecondaryText);
|
Colour colour(Colour::SecondaryText);
|
||||||
stream << currentTestRunInfo->name
|
stream << currentTestRunInfo->name
|
||||||
@ -483,13 +473,13 @@ namespace Catch {
|
|||||||
|
|
||||||
currentTestRunInfo.used = true;
|
currentTestRunInfo.used = true;
|
||||||
}
|
}
|
||||||
void lazyPrintGroupInfo() {
|
void ConsoleReporter::lazyPrintGroupInfo() {
|
||||||
if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
|
if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
|
||||||
printClosedHeader("Group: " + currentGroupInfo->name);
|
printClosedHeader("Group: " + currentGroupInfo->name);
|
||||||
currentGroupInfo.used = true;
|
currentGroupInfo.used = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void printTestCaseAndSectionHeader() {
|
void ConsoleReporter::printTestCaseAndSectionHeader() {
|
||||||
assert(!m_sectionStack.empty());
|
assert(!m_sectionStack.empty());
|
||||||
printOpenHeader(currentTestCaseInfo->name);
|
printOpenHeader(currentTestCaseInfo->name);
|
||||||
|
|
||||||
@ -513,11 +503,11 @@ namespace Catch {
|
|||||||
stream << getLineOfChars<'.'>() << '\n' << std::endl;
|
stream << getLineOfChars<'.'>() << '\n' << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printClosedHeader( std::string const& _name ) {
|
void ConsoleReporter::printClosedHeader(std::string const& _name) {
|
||||||
printOpenHeader(_name);
|
printOpenHeader(_name);
|
||||||
stream << getLineOfChars<'.'>() << '\n';
|
stream << getLineOfChars<'.'>() << '\n';
|
||||||
}
|
}
|
||||||
void printOpenHeader( std::string const& _name ) {
|
void ConsoleReporter::printOpenHeader(std::string const& _name) {
|
||||||
stream << getLineOfChars<'-'>() << '\n';
|
stream << getLineOfChars<'-'>() << '\n';
|
||||||
{
|
{
|
||||||
Colour colourGuard(Colour::Headers);
|
Colour colourGuard(Colour::Headers);
|
||||||
@ -527,7 +517,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// if string has a : in first line will set indent to follow it on
|
// if string has a : in first line will set indent to follow it on
|
||||||
// subsequent lines
|
// subsequent lines
|
||||||
void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
|
void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
|
||||||
std::size_t i = _string.find(": ");
|
std::size_t i = _string.find(": ");
|
||||||
if (i != std::string::npos)
|
if (i != std::string::npos)
|
||||||
i += 2;
|
i += 2;
|
||||||
@ -540,8 +530,7 @@ namespace Catch {
|
|||||||
|
|
||||||
SummaryColumn(std::string const& _label, Colour::Code _colour)
|
SummaryColumn(std::string const& _label, Colour::Code _colour)
|
||||||
: label(_label),
|
: label(_label),
|
||||||
colour( _colour )
|
colour(_colour) {}
|
||||||
{}
|
|
||||||
SummaryColumn addRow(std::size_t count) {
|
SummaryColumn addRow(std::size_t count) {
|
||||||
ReusableStringStream rss;
|
ReusableStringStream rss;
|
||||||
rss << count;
|
rss << count;
|
||||||
@ -562,18 +551,16 @@ namespace Catch {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void printTotals( Totals const& totals ) {
|
void ConsoleReporter::printTotals(Totals const& totals) {
|
||||||
if (totals.testCases.total() == 0) {
|
if (totals.testCases.total() == 0) {
|
||||||
stream << Colour(Colour::Warning) << "No tests ran\n";
|
stream << Colour(Colour::Warning) << "No tests ran\n";
|
||||||
}
|
} else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
|
||||||
else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
|
|
||||||
stream << Colour(Colour::ResultSuccess) << "All tests passed";
|
stream << Colour(Colour::ResultSuccess) << "All tests passed";
|
||||||
stream << " ("
|
stream << " ("
|
||||||
<< pluralise(totals.assertions.passed, "assertion") << " in "
|
<< pluralise(totals.assertions.passed, "assertion") << " in "
|
||||||
<< pluralise(totals.testCases.passed, "test case") << ')'
|
<< pluralise(totals.testCases.passed, "test case") << ')'
|
||||||
<< '\n';
|
<< '\n';
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
std::vector<SummaryColumn> columns;
|
std::vector<SummaryColumn> columns;
|
||||||
columns.push_back(SummaryColumn("", Colour::None)
|
columns.push_back(SummaryColumn("", Colour::None)
|
||||||
@ -593,7 +580,7 @@ namespace Catch {
|
|||||||
printSummaryRow("assertions", columns, 1);
|
printSummaryRow("assertions", columns, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
|
void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {
|
||||||
for (auto col : cols) {
|
for (auto col : cols) {
|
||||||
std::string value = col.rows[row];
|
std::string value = col.rows[row];
|
||||||
if (col.label.empty()) {
|
if (col.label.empty()) {
|
||||||
@ -602,8 +589,7 @@ namespace Catch {
|
|||||||
stream << value;
|
stream << value;
|
||||||
else
|
else
|
||||||
stream << Colour(Colour::Warning) << "- none -";
|
stream << Colour(Colour::Warning) << "- none -";
|
||||||
}
|
} else if (value != "0") {
|
||||||
else if( value != "0" ) {
|
|
||||||
stream << Colour(Colour::LightGrey) << " | ";
|
stream << Colour(Colour::LightGrey) << " | ";
|
||||||
stream << Colour(col.colour)
|
stream << Colour(col.colour)
|
||||||
<< value << ' ' << col.label;
|
<< value << ' ' << col.label;
|
||||||
@ -612,7 +598,7 @@ namespace Catch {
|
|||||||
stream << '\n';
|
stream << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
void printTotalsDivider( Totals const& totals ) {
|
void ConsoleReporter::printTotalsDivider(Totals const& totals) {
|
||||||
if (totals.testCases.total() > 0) {
|
if (totals.testCases.total() > 0) {
|
||||||
std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
|
std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
|
||||||
std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
|
std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
|
||||||
@ -628,24 +614,17 @@ namespace Catch {
|
|||||||
stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
|
stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
|
||||||
else
|
else
|
||||||
stream << Colour(Colour::Success) << std::string(passedRatio, '=');
|
stream << Colour(Colour::Success) << std::string(passedRatio, '=');
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
|
stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
|
||||||
}
|
}
|
||||||
stream << '\n';
|
stream << '\n';
|
||||||
}
|
}
|
||||||
void printSummaryDivider() {
|
void ConsoleReporter::printSummaryDivider() {
|
||||||
stream << getLineOfChars<'-'>() << '\n';
|
stream << getLineOfChars<'-'>() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_headerPrinted = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||||
|
|
||||||
ConsoleReporter::~ConsoleReporter() {}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
83
include/reporters/catch_reporter_console.h
Normal file
83
include/reporters/catch_reporter_console.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil on 5/12/2012.
|
||||||
|
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_reporter_bases.hpp"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
|
||||||
|
// Note that 4062 (not all labels are handled
|
||||||
|
// and default is missing) is enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
// Fwd decls
|
||||||
|
struct SummaryColumn;
|
||||||
|
class TablePrinter;
|
||||||
|
|
||||||
|
struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
|
||||||
|
std::unique_ptr<TablePrinter> m_tablePrinter;
|
||||||
|
|
||||||
|
ConsoleReporter(ReporterConfig const& config);
|
||||||
|
~ConsoleReporter() override;
|
||||||
|
static std::string getDescription();
|
||||||
|
|
||||||
|
void noMatchingTestCases(std::string const& spec) override;
|
||||||
|
|
||||||
|
void assertionStarting(AssertionInfo const&) override;
|
||||||
|
|
||||||
|
bool assertionEnded(AssertionStats const& _assertionStats) override;
|
||||||
|
|
||||||
|
void sectionStarting(SectionInfo const& _sectionInfo) override;
|
||||||
|
void sectionEnded(SectionStats const& _sectionStats) override;
|
||||||
|
|
||||||
|
|
||||||
|
void benchmarkStarting(BenchmarkInfo const& info) override;
|
||||||
|
void benchmarkEnded(BenchmarkStats const& stats) override;
|
||||||
|
|
||||||
|
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
|
||||||
|
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
|
||||||
|
void testRunEnded(TestRunStats const& _testRunStats) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void lazyPrint();
|
||||||
|
|
||||||
|
void lazyPrintWithoutClosingBenchmarkTable();
|
||||||
|
void lazyPrintRunInfo();
|
||||||
|
void lazyPrintGroupInfo();
|
||||||
|
void printTestCaseAndSectionHeader();
|
||||||
|
|
||||||
|
void printClosedHeader(std::string const& _name);
|
||||||
|
void printOpenHeader(std::string const& _name);
|
||||||
|
|
||||||
|
// if string has a : in first line will set indent to follow it on
|
||||||
|
// subsequent lines
|
||||||
|
void printHeaderString(std::string const& _string, std::size_t indent = 0);
|
||||||
|
|
||||||
|
|
||||||
|
void printTotals(Totals const& totals);
|
||||||
|
void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);
|
||||||
|
|
||||||
|
void printTotalsDivider(Totals const& totals);
|
||||||
|
void printSummaryDivider();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_headerPrinted = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
Loading…
Reference in New Issue
Block a user