From 61d0f7a9afb88c12f8931f80321e58f2cfbc62db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Wed, 23 Feb 2022 23:46:45 +0100 Subject: [PATCH] Pass the whole IStream wrapper into reporter This will become useful when reworking colour support, because Win32 colour support requires checking whether the output is stdout, which is done through the `IStream` wrapper. --- src/catch2/catch_config.cpp | 6 ++--- src/catch2/catch_config.hpp | 6 ++--- src/catch2/catch_session.cpp | 4 ++-- .../interfaces/catch_interfaces_config.hpp | 3 ++- .../interfaces/catch_interfaces_reporter.cpp | 6 ++--- .../interfaces/catch_interfaces_reporter.hpp | 7 +++--- src/catch2/internal/catch_console_colour.cpp | 2 +- src/catch2/internal/catch_stream.hpp | 3 ++- .../reporters/catch_reporter_common_base.hpp | 11 +++++++-- .../reporters/catch_reporter_console.cpp | 2 +- src/catch2/reporters/catch_reporter_xml.cpp | 2 +- .../IntrospectiveTests/Reporters.tests.cpp | 23 ++++++++++++++----- 12 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/catch2/catch_config.cpp b/src/catch2/catch_config.cpp index e6a5b2ed..6d6e0831 100644 --- a/src/catch2/catch_config.cpp +++ b/src/catch2/catch_config.cpp @@ -107,8 +107,8 @@ namespace Catch { return m_data.reporterSpecifications; } - std::ostream& Config::getReporterOutputStream(std::size_t reporterIdx) const { - return m_reporterStreams.at(reporterIdx)->stream(); + IStream const* Config::getReporterOutputStream(std::size_t reporterIdx) const { + return m_reporterStreams.at(reporterIdx).get(); } TestSpec const& Config::testSpec() const { return m_testSpec; } @@ -118,7 +118,7 @@ namespace Catch { // IConfig interface bool Config::allowThrows() const { return !m_data.noThrow; } - std::ostream& Config::defaultStream() const { return m_defaultStream->stream(); } + IStream const* Config::defaultStream() const { return m_defaultStream.get(); } StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } bool Config::warnAboutMissingAssertions() const { diff --git a/src/catch2/catch_config.hpp b/src/catch2/catch_config.hpp index 2795d42e..7b33fa71 100644 --- a/src/catch2/catch_config.hpp +++ b/src/catch2/catch_config.hpp @@ -21,7 +21,7 @@ namespace Catch { - struct IStream; + class IStream; struct ConfigData { struct ReporterAndFile { @@ -91,7 +91,7 @@ namespace Catch { bool listReporters() const; std::vector const& getReportersAndOutputFiles() const; - std::ostream& getReporterOutputStream(std::size_t reporterIdx) const; + IStream const* getReporterOutputStream(std::size_t reporterIdx) const; std::vector const& getTestsOrTags() const override; std::vector const& getSectionsToRun() const override; @@ -103,7 +103,7 @@ namespace Catch { // IConfig interface bool allowThrows() const override; - std::ostream& defaultStream() const override; + IStream const* defaultStream() const override; StringRef name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; diff --git a/src/catch2/catch_session.cpp b/src/catch2/catch_session.cpp index a4a78bb6..f20531e3 100644 --- a/src/catch2/catch_session.cpp +++ b/src/catch2/catch_session.cpp @@ -44,7 +44,7 @@ namespace Catch { IStreamingReporterPtr makeReporter(Config const* config) { if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty() && config->getReportersAndOutputFiles().size() == 1) { - auto& stream = config->getReporterOutputStream(0); + auto stream = config->getReporterOutputStream(0); return createReporter(config->getReportersAndOutputFiles()[0].reporterName, ReporterConfig(config, stream)); } @@ -57,7 +57,7 @@ namespace Catch { std::size_t reporterIdx = 0; for (auto const& reporterAndFile : config->getReportersAndOutputFiles()) { - auto& stream = config->getReporterOutputStream(reporterIdx); + auto stream = config->getReporterOutputStream(reporterIdx); multi->addReporter(createReporter(reporterAndFile.reporterName, ReporterConfig(config, stream))); reporterIdx++; } diff --git a/src/catch2/interfaces/catch_interfaces_config.hpp b/src/catch2/interfaces/catch_interfaces_config.hpp index 4b2bd365..6c17081a 100644 --- a/src/catch2/interfaces/catch_interfaces_config.hpp +++ b/src/catch2/interfaces/catch_interfaces_config.hpp @@ -55,13 +55,14 @@ namespace Catch { }; }; class TestSpec; + class IStream; struct IConfig : Detail::NonCopyable { virtual ~IConfig(); virtual bool allowThrows() const = 0; - virtual std::ostream& defaultStream() const = 0; + virtual IStream const* defaultStream() const = 0; virtual StringRef name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; diff --git a/src/catch2/interfaces/catch_interfaces_reporter.cpp b/src/catch2/interfaces/catch_interfaces_reporter.cpp index e5d3921f..5f5d274a 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.cpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.cpp @@ -20,10 +20,10 @@ namespace Catch { - ReporterConfig::ReporterConfig( IConfig const* _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + ReporterConfig::ReporterConfig( IConfig const* _fullConfig, IStream const* _stream ) + : m_stream( _stream ), m_fullConfig( _fullConfig ) {} - std::ostream& ReporterConfig::stream() const { return *m_stream; } + IStream const* ReporterConfig::stream() const { return m_stream; } IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; } AssertionStats::AssertionStats( AssertionResult const& _assertionResult, diff --git a/src/catch2/interfaces/catch_interfaces_reporter.hpp b/src/catch2/interfaces/catch_interfaces_reporter.hpp index c05648b7..41cf426b 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.hpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.hpp @@ -30,15 +30,16 @@ namespace Catch { struct TestCaseInfo; class TestCaseHandle; struct IConfig; + class IStream; struct ReporterConfig { - ReporterConfig( IConfig const* _fullConfig, std::ostream& _stream ); + ReporterConfig( IConfig const* _fullConfig, IStream const* _stream ); - std::ostream& stream() const; + IStream const* stream() const; IConfig const* fullConfig() const; private: - std::ostream* m_stream; + IStream const* m_stream; IConfig const* m_fullConfig; }; diff --git a/src/catch2/internal/catch_console_colour.cpp b/src/catch2/internal/catch_console_colour.cpp index b3e4934e..b3d583d2 100644 --- a/src/catch2/internal/catch_console_colour.cpp +++ b/src/catch2/internal/catch_console_colour.cpp @@ -160,7 +160,7 @@ namespace { void setColour( const char* _escapeCode ) { // The escape sequence must be flushed to console, otherwise if // stdin and stderr are intermixed, we'd get accidentally coloured output. - getCurrentContext().getConfig()->defaultStream() + getCurrentContext().getConfig()->defaultStream()->stream() << '\033' << _escapeCode << std::flush; } }; diff --git a/src/catch2/internal/catch_stream.hpp b/src/catch2/internal/catch_stream.hpp index 77a35760..1b92b4dc 100644 --- a/src/catch2/internal/catch_stream.hpp +++ b/src/catch2/internal/catch_stream.hpp @@ -22,7 +22,8 @@ namespace Catch { std::ostream& cerr(); std::ostream& clog(); - struct IStream { + class IStream { + public: virtual ~IStream(); // = default virtual std::ostream& stream() const = 0; // Win32 colour supports requires us to identify whether a stream diff --git a/src/catch2/reporters/catch_reporter_common_base.hpp b/src/catch2/reporters/catch_reporter_common_base.hpp index 235c2606..b7610a93 100644 --- a/src/catch2/reporters/catch_reporter_common_base.hpp +++ b/src/catch2/reporters/catch_reporter_common_base.hpp @@ -9,6 +9,7 @@ #define CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED #include +#include namespace Catch { /** @@ -23,13 +24,19 @@ namespace Catch { */ class ReporterBase : public IEventListener { protected: - //! Stream to write the output to + //! The stream wrapper as passed to us by outside code + IStream const* m_wrapped_stream; + //! Cached output stream from `m_wrapped_stream` to reduce + //! number of indirect calls needed to write output. std::ostream& m_stream; + + public: ReporterBase( ReporterConfig const& config ): IEventListener( config.fullConfig() ), - m_stream( config.stream() ) {} + m_wrapped_stream( config.stream() ), + m_stream( m_wrapped_stream->stream() ) {} /** diff --git a/src/catch2/reporters/catch_reporter_console.cpp b/src/catch2/reporters/catch_reporter_console.cpp index d5dd89c5..e79d6a63 100644 --- a/src/catch2/reporters/catch_reporter_console.cpp +++ b/src/catch2/reporters/catch_reporter_console.cpp @@ -355,7 +355,7 @@ public: ConsoleReporter::ConsoleReporter(ReporterConfig const& config) : StreamingReporterBase(config), - m_tablePrinter(Detail::make_unique(config.stream(), + m_tablePrinter(Detail::make_unique(m_stream, [&config]() -> std::vector { if (config.fullConfig()->benchmarkNoAnalysis()) { diff --git a/src/catch2/reporters/catch_reporter_xml.cpp b/src/catch2/reporters/catch_reporter_xml.cpp index 8c3338cb..78fa8647 100644 --- a/src/catch2/reporters/catch_reporter_xml.cpp +++ b/src/catch2/reporters/catch_reporter_xml.cpp @@ -24,7 +24,7 @@ namespace Catch { XmlReporter::XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), - m_xml(_config.stream()) + m_xml(m_stream) { m_preferences.shouldRedirectStdOut = true; m_preferences.shouldReportAllAssertions = true; diff --git a/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp b/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp index 40ae0179..a2416042 100644 --- a/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,16 @@ #include +namespace { + class StringIStream : public Catch::IStream { + public: + std::ostream& stream() const override { return sstr; } + std::string str() const { return sstr.str(); } + private: + mutable std::stringstream sstr; + }; +} + TEST_CASE( "The default listing implementation write to provided stream", "[reporters][reporter-helpers]" ) { using Catch::Matchers::ContainsSubstring; @@ -72,11 +83,11 @@ TEST_CASE( "Reporter's write listings to provided stream", "[reporters]" ) { for (auto const& factory : factories) { INFO("Tested reporter: " << factory.first); - std::stringstream sstream; + StringIStream sstream; Catch::ConfigData config_data; Catch::Config config( config_data ); - Catch::ReporterConfig rep_config( &config, sstream ); + Catch::ReporterConfig rep_config( &config, &sstream ); auto reporter = factory.second->create( rep_config ); DYNAMIC_SECTION( factory.first << " reporter lists tags" ) { @@ -162,8 +173,8 @@ TEST_CASE("Multireporter calls reporters and listeners in correct order", Catch::ConfigData config_data; Catch::Config config( config_data ); - std::stringstream sstream; - Catch::ReporterConfig rep_config( &config, sstream ); + StringIStream sstream; + Catch::ReporterConfig rep_config( &config, &sstream ); // We add reporters before listeners, to check that internally they // get sorted properly, and listeners are called first anyway. @@ -215,8 +226,8 @@ TEST_CASE("Multireporter updates ReporterPreferences properly", Catch::ConfigData config_data; Catch::Config config( config_data ); - std::stringstream sstream; - Catch::ReporterConfig rep_config( &config, sstream ); + StringIStream sstream; + Catch::ReporterConfig rep_config( &config, &sstream ); Catch::MultiReporter multiReporter( &config ); // Post init defaults