Further refactoring of StreamingReporterBase

This commit is contained in:
Martin Hořeňovský 2021-11-14 11:40:06 +01:00
parent b2ac27423a
commit edc2f6e8a3
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
8 changed files with 76 additions and 91 deletions

View File

@ -16,20 +16,20 @@ namespace Catch {
void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
stream << ":test-result: "; m_stream << ":test-result: ";
if (_testCaseStats.totals.assertions.allPassed()) { if (_testCaseStats.totals.assertions.allPassed()) {
stream << "PASS"; m_stream << "PASS";
} else if (_testCaseStats.totals.assertions.allOk()) { } else if (_testCaseStats.totals.assertions.allOk()) {
stream << "XFAIL"; m_stream << "XFAIL";
} else { } else {
stream << "FAIL"; m_stream << "FAIL";
} }
stream << ' ' << _testCaseStats.testInfo->name << '\n'; m_stream << ' ' << _testCaseStats.testInfo->name << '\n';
StreamingReporterBase::testCaseEnded(_testCaseStats); StreamingReporterBase::testCaseEnded(_testCaseStats);
} }
void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) { void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) {
stream << ":test-result: SKIP " << testInfo.name << '\n'; m_stream << ":test-result: SKIP " << testInfo.name << '\n';
} }
} // end namespace Catch } // end namespace Catch

View File

@ -259,7 +259,7 @@ private:
} }
void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) { void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
stream << "No test cases matched '" << unmatchedSpec << "'\n"; m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
} }
void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
@ -274,22 +274,22 @@ private:
printInfoMessages = false; printInfoMessages = false;
} }
AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages );
printer.print(); printer.print();
stream << '\n' << std::flush; m_stream << '\n' << std::flush;
} }
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
double dur = _sectionStats.durationInSeconds; double dur = _sectionStats.durationInSeconds;
if ( shouldShowDuration( *m_config, dur ) ) { if ( shouldShowDuration( *m_config, dur ) ) {
stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush; m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
} }
} }
void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
printTotals( stream, _testRunStats.totals ); printTotals( m_stream, _testRunStats.totals );
stream << "\n\n" << std::flush; m_stream << "\n\n" << std::flush;
StreamingReporterBase::testRunEnded( _testRunStats ); StreamingReporterBase::testRunEnded( _testRunStats );
} }

View File

@ -382,11 +382,11 @@ std::string ConsoleReporter::getDescription() {
} }
void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) { void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
stream << "No test cases matched '" << unmatchedSpec << "'\n"; m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
} }
void ConsoleReporter::reportInvalidArguments( StringRef arg ) { void ConsoleReporter::reportInvalidArguments( StringRef arg ) {
stream << "Invalid Filter: " << arg << '\n'; m_stream << "Invalid Filter: " << arg << '\n';
} }
void ConsoleReporter::assertionStarting(AssertionInfo const&) {} void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
@ -402,9 +402,9 @@ void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
lazyPrint(); lazyPrint();
ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); ConsoleAssertionPrinter printer(m_stream, _assertionStats, includeResults);
printer.print(); printer.print();
stream << '\n' << std::flush; m_stream << '\n' << std::flush;
} }
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
@ -418,14 +418,14 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
lazyPrint(); lazyPrint();
Colour colour(Colour::ResultError); Colour colour(Colour::ResultError);
if (m_sectionStack.size() > 1) if (m_sectionStack.size() > 1)
stream << "\nNo assertions in section"; m_stream << "\nNo assertions in section";
else else
stream << "\nNo assertions in test case"; m_stream << "\nNo assertions in test case";
stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush; m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush;
} }
double dur = _sectionStats.durationInSeconds; double dur = _sectionStats.durationInSeconds;
if (shouldShowDuration(*m_config, dur)) { if (shouldShowDuration(*m_config, dur)) {
stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush; m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
} }
if (m_headerPrinted) { if (m_headerPrinted) {
m_headerPrinted = false; m_headerPrinted = false;
@ -489,7 +489,7 @@ void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
printTotalsDivider(_testRunStats.totals); printTotalsDivider(_testRunStats.totals);
printTotals(_testRunStats.totals); printTotals(_testRunStats.totals);
stream << '\n' << std::flush; m_stream << '\n' << std::flush;
StreamingReporterBase::testRunEnded(_testRunStats); StreamingReporterBase::testRunEnded(_testRunStats);
} }
void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
@ -505,7 +505,7 @@ void ConsoleReporter::lazyPrint() {
void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
if ( !currentTestRunInfo.used ) { if ( !m_testRunInfoPrinted ) {
lazyPrintRunInfo(); lazyPrintRunInfo();
} }
if (!m_headerPrinted) { if (!m_headerPrinted) {
@ -514,15 +514,15 @@ void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
} }
} }
void ConsoleReporter::lazyPrintRunInfo() { void ConsoleReporter::lazyPrintRunInfo() {
stream << '\n' << lineOfChars('~') << '\n'; m_stream << '\n' << lineOfChars('~') << '\n';
Colour colour(Colour::SecondaryText); Colour colour(Colour::SecondaryText);
stream << currentTestRunInfo->name m_stream << currentTestRunInfo.name
<< " is a Catch v" << libraryVersion() << " host application.\n" << " is a Catch v" << libraryVersion() << " host application.\n"
<< "Run with -? for options\n\n"; << "Run with -? for options\n\n";
stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; m_stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
currentTestRunInfo.used = true; m_testRunInfoPrinted = true;
} }
void ConsoleReporter::printTestCaseAndSectionHeader() { void ConsoleReporter::printTestCaseAndSectionHeader() {
assert(!m_sectionStack.empty()); assert(!m_sectionStack.empty());
@ -541,18 +541,18 @@ void ConsoleReporter::printTestCaseAndSectionHeader() {
SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
stream << lineOfChars('-') << '\n'; m_stream << lineOfChars('-') << '\n';
Colour colourGuard(Colour::FileName); Colour colourGuard(Colour::FileName);
stream << lineInfo << '\n'; m_stream << lineInfo << '\n';
stream << lineOfChars('.') << "\n\n" << std::flush; m_stream << lineOfChars('.') << "\n\n" << std::flush;
} }
void ConsoleReporter::printClosedHeader(std::string const& _name) { void ConsoleReporter::printClosedHeader(std::string const& _name) {
printOpenHeader(_name); printOpenHeader(_name);
stream << lineOfChars('.') << '\n'; m_stream << lineOfChars('.') << '\n';
} }
void ConsoleReporter::printOpenHeader(std::string const& _name) { void ConsoleReporter::printOpenHeader(std::string const& _name) {
stream << lineOfChars('-') << '\n'; m_stream << lineOfChars('-') << '\n';
{ {
Colour colourGuard(Colour::Headers); Colour colourGuard(Colour::Headers);
printHeaderString(_name); printHeaderString(_name);
@ -586,7 +586,7 @@ void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t
} else { } else {
idx = 0; idx = 0;
} }
stream << TextFlow::Column( _string ) m_stream << TextFlow::Column( _string )
.indent( indent + idx ) .indent( indent + idx )
.initialIndent( indent ) .initialIndent( indent )
<< '\n'; << '\n';
@ -619,10 +619,10 @@ struct SummaryColumn {
void ConsoleReporter::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"; m_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"; m_stream << Colour(Colour::ResultSuccess) << "All tests passed";
stream << " (" m_stream << " ("
<< pluralise(totals.assertions.passed, "assertion"_sr) << " in " << pluralise(totals.assertions.passed, "assertion"_sr) << " in "
<< pluralise(totals.testCases.passed, "test case"_sr) << ')' << pluralise(totals.testCases.passed, "test case"_sr) << ')'
<< '\n'; << '\n';
@ -650,18 +650,18 @@ void ConsoleReporter::printSummaryRow(StringRef label, std::vector<SummaryColumn
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()) {
stream << label << ": "; m_stream << label << ": ";
if (value != "0") if (value != "0")
stream << value; m_stream << value;
else else
stream << Colour(Colour::Warning) << "- none -"; m_stream << Colour(Colour::Warning) << "- none -";
} else if (value != "0") { } else if (value != "0") {
stream << Colour(Colour::LightGrey) << " | "; m_stream << Colour(Colour::LightGrey) << " | ";
stream << Colour(col.colour) m_stream << Colour(col.colour)
<< value << ' ' << col.label; << value << ' ' << col.label;
} }
} }
stream << '\n'; m_stream << '\n';
} }
void ConsoleReporter::printTotalsDivider(Totals const& totals) { void ConsoleReporter::printTotalsDivider(Totals const& totals) {
@ -674,25 +674,25 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) {
while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
findMax(failedRatio, failedButOkRatio, passedRatio)--; findMax(failedRatio, failedButOkRatio, passedRatio)--;
stream << Colour(Colour::Error) << std::string(failedRatio, '='); m_stream << Colour(Colour::Error) << std::string(failedRatio, '=');
stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); m_stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
if (totals.testCases.allPassed()) if (totals.testCases.allPassed())
stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); m_stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
else else
stream << Colour(Colour::Success) << std::string(passedRatio, '='); m_stream << Colour(Colour::Success) << std::string(passedRatio, '=');
} else { } else {
stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); m_stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
} }
stream << '\n'; m_stream << '\n';
} }
void ConsoleReporter::printSummaryDivider() { void ConsoleReporter::printSummaryDivider() {
stream << lineOfChars('-') << '\n'; m_stream << lineOfChars('-') << '\n';
} }
void ConsoleReporter::printTestFilters() { void ConsoleReporter::printTestFilters() {
if (m_config->testSpec().hasFilters()) { if (m_config->testSpec().hasFilters()) {
Colour guard(Colour::BrightYellow); Colour guard(Colour::BrightYellow);
stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; m_stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
} }
} }

View File

@ -66,6 +66,7 @@ namespace Catch {
private: private:
bool m_headerPrinted = false; bool m_headerPrinted = false;
bool m_testRunInfoPrinted = false;
}; };
} // end namespace Catch } // end namespace Catch

View File

@ -19,22 +19,21 @@ namespace Catch {
void StreamingReporterBase::testRunEnded( TestRunStats const& ) { void StreamingReporterBase::testRunEnded( TestRunStats const& ) {
currentTestCaseInfo = nullptr; currentTestCaseInfo = nullptr;
currentTestRunInfo.reset();
} }
void StreamingReporterBase::listReporters(std::vector<ReporterDescription> const& descriptions) { void StreamingReporterBase::listReporters(std::vector<ReporterDescription> const& descriptions) {
defaultListReporters( stream, descriptions, m_config->verbosity() ); defaultListReporters( m_stream, descriptions, m_config->verbosity() );
} }
void StreamingReporterBase::listTests(std::vector<TestCaseHandle> const& tests) { void StreamingReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
defaultListTests(stream, defaultListTests(m_stream,
tests, tests,
m_config->hasTestFilters(), m_config->hasTestFilters(),
m_config->verbosity()); m_config->verbosity());
} }
void StreamingReporterBase::listTags(std::vector<TagInfo> const& tags) { void StreamingReporterBase::listTags(std::vector<TagInfo> const& tags) {
defaultListTags( stream, tags, m_config->hasTestFilters() ); defaultListTags( m_stream, tags, m_config->hasTestFilters() );
} }
} // end namespace Catch } // end namespace Catch

View File

@ -10,34 +10,17 @@
#include <catch2/interfaces/catch_interfaces_reporter.hpp> #include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_optional.hpp>
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <vector> #include <vector>
namespace Catch { namespace Catch {
template<typename T>
struct LazyStat : Optional<T> {
LazyStat& operator=(T const& _value) {
Optional<T>::operator=(_value);
used = false;
return *this;
}
void reset() {
Optional<T>::reset();
used = false;
}
bool used = false;
};
class StreamingReporterBase : public IStreamingReporter { class StreamingReporterBase : public IStreamingReporter {
public: public:
StreamingReporterBase( ReporterConfig const& _config ): StreamingReporterBase( ReporterConfig const& _config ):
IStreamingReporter( _config.fullConfig() ), IStreamingReporter( _config.fullConfig() ),
stream( _config.stream() ) {} m_stream( _config.stream() ) {}
~StreamingReporterBase() override; ~StreamingReporterBase() override;
@ -83,11 +66,13 @@ namespace Catch {
void listTags( std::vector<TagInfo> const& tags ) override; void listTags( std::vector<TagInfo> const& tags ) override;
protected: protected:
std::ostream& stream; //! Stream that the reporter output should be written to
std::ostream& m_stream;
LazyStat<TestRunInfo> currentTestRunInfo; TestRunInfo currentTestRunInfo{ "test run has not started yet"_sr };
TestCaseInfo const* currentTestCaseInfo = nullptr; TestCaseInfo const* currentTestCaseInfo = nullptr;
//! Stack of all _active_ sections in the _current_ test case
std::vector<SectionInfo> m_sectionStack; std::vector<SectionInfo> m_sectionStack;
}; };

View File

@ -195,25 +195,25 @@ namespace Catch {
} // End anonymous namespace } // End anonymous namespace
void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) { void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
stream << "# No test cases matched '" << unmatchedSpec << "'\n"; m_stream << "# No test cases matched '" << unmatchedSpec << "'\n";
} }
void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) { void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) {
++counter; ++counter;
stream << "# " << currentTestCaseInfo->name << '\n'; m_stream << "# " << currentTestCaseInfo->name << '\n';
TapAssertionPrinter printer(stream, _assertionStats, counter); TapAssertionPrinter printer(m_stream, _assertionStats, counter);
printer.print(); printer.print();
stream << '\n' << std::flush; m_stream << '\n' << std::flush;
} }
void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) { void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) {
stream << "1.." << _testRunStats.totals.assertions.total(); m_stream << "1.." << _testRunStats.totals.assertions.total();
if (_testRunStats.totals.testCases.total() == 0) { if (_testRunStats.totals.testCases.total() == 0) {
stream << " # Skipped: No tests ran."; m_stream << " # Skipped: No tests ran.";
} }
stream << "\n\n" << std::flush; m_stream << "\n\n" << std::flush;
StreamingReporterBase::testRunEnded(_testRunStats); StreamingReporterBase::testRunEnded(_testRunStats);
} }

View File

@ -47,12 +47,12 @@ namespace Catch {
TeamCityReporter::~TeamCityReporter() {} TeamCityReporter::~TeamCityReporter() {}
void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) { void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) {
stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name ) m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name )
<< "']\n"; << "']\n";
} }
void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) { void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) {
stream << "##teamcity[testSuiteFinished name='" m_stream << "##teamcity[testSuiteFinished name='"
<< escape( runStats.runInfo.name ) << "']\n"; << escape( runStats.runInfo.name ) << "']\n";
} }
@ -112,43 +112,43 @@ namespace Catch {
if (currentTestCaseInfo->okToFail()) { if (currentTestCaseInfo->okToFail()) {
msg << "- failure ignore as test marked as 'ok to fail'\n"; msg << "- failure ignore as test marked as 'ok to fail'\n";
stream << "##teamcity[testIgnored" m_stream << "##teamcity[testIgnored"
<< " name='" << escape(currentTestCaseInfo->name) << '\'' << " name='" << escape(currentTestCaseInfo->name) << '\''
<< " message='" << escape(msg.str()) << '\'' << " message='" << escape(msg.str()) << '\''
<< "]\n"; << "]\n";
} else { } else {
stream << "##teamcity[testFailed" m_stream << "##teamcity[testFailed"
<< " name='" << escape(currentTestCaseInfo->name) << '\'' << " name='" << escape(currentTestCaseInfo->name) << '\''
<< " message='" << escape(msg.str()) << '\'' << " message='" << escape(msg.str()) << '\''
<< "]\n"; << "]\n";
} }
} }
stream.flush(); m_stream.flush();
} }
void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) { void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) {
m_testTimer.start(); m_testTimer.start();
StreamingReporterBase::testCaseStarting(testInfo); StreamingReporterBase::testCaseStarting(testInfo);
stream << "##teamcity[testStarted name='" m_stream << "##teamcity[testStarted name='"
<< escape(testInfo.name) << "']\n"; << escape(testInfo.name) << "']\n";
stream.flush(); m_stream.flush();
} }
void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) { void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) {
StreamingReporterBase::testCaseEnded(testCaseStats); StreamingReporterBase::testCaseEnded(testCaseStats);
auto const& testCaseInfo = *testCaseStats.testInfo; auto const& testCaseInfo = *testCaseStats.testInfo;
if (!testCaseStats.stdOut.empty()) if (!testCaseStats.stdOut.empty())
stream << "##teamcity[testStdOut name='" m_stream << "##teamcity[testStdOut name='"
<< escape(testCaseInfo.name) << escape(testCaseInfo.name)
<< "' out='" << escape(testCaseStats.stdOut) << "']\n"; << "' out='" << escape(testCaseStats.stdOut) << "']\n";
if (!testCaseStats.stdErr.empty()) if (!testCaseStats.stdErr.empty())
stream << "##teamcity[testStdErr name='" m_stream << "##teamcity[testStdErr name='"
<< escape(testCaseInfo.name) << escape(testCaseInfo.name)
<< "' out='" << escape(testCaseStats.stdErr) << "']\n"; << "' out='" << escape(testCaseStats.stdErr) << "']\n";
stream << "##teamcity[testFinished name='" m_stream << "##teamcity[testFinished name='"
<< escape(testCaseInfo.name) << "' duration='" << escape(testCaseInfo.name) << "' duration='"
<< m_testTimer.getElapsedMilliseconds() << "']\n"; << m_testTimer.getElapsedMilliseconds() << "']\n";
stream.flush(); m_stream.flush();
} }
void TeamCityReporter::printSectionHeader(std::ostream& os) { void TeamCityReporter::printSectionHeader(std::ostream& os) {