diff --git a/include/catch.hpp b/include/catch.hpp index e4fd40fe..88a9abe6 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -215,6 +215,7 @@ #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index de21955e..303e891a 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -130,6 +130,10 @@ #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ + Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) + /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 950d498d..36f27a33 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -20,6 +20,7 @@ namespace Catch { struct SectionInfo; struct SectionEndInfo; struct MessageInfo; + struct MessageBuilder; struct Counts; struct BenchmarkInfo; struct BenchmarkStats; @@ -46,6 +47,8 @@ namespace Catch { virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; + virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; + virtual void handleFatalErrorCondition( StringRef message ) = 0; virtual void handleExpr diff --git a/include/internal/catch_message.cpp b/include/internal/catch_message.cpp index 98a4dae1..fa7e8746 100644 --- a/include/internal/catch_message.cpp +++ b/include/internal/catch_message.cpp @@ -47,14 +47,20 @@ namespace Catch { ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) + : m_info( builder.m_info ), m_moved() { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } + ScopedMessage::ScopedMessage( ScopedMessage&& old ) + : m_info( old.m_info ), m_moved() + { + old.m_moved = true; + } + ScopedMessage::~ScopedMessage() { - if ( !uncaught_exceptions() ){ + if ( !uncaught_exceptions() && !m_moved ){ getResultCapture().popScopedMessage(m_info); } } diff --git a/include/internal/catch_message.h b/include/internal/catch_message.h index e81069bf..748f5ac5 100644 --- a/include/internal/catch_message.h +++ b/include/internal/catch_message.h @@ -64,9 +64,12 @@ namespace Catch { class ScopedMessage { public: explicit ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage& duplicate ) = delete; + ScopedMessage( ScopedMessage&& old ); ~ScopedMessage(); MessageInfo m_info; + bool m_moved; }; class Capturer { diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index c4defc9d..bc3a5151 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -161,6 +161,9 @@ namespace Catch { // and should be let to clear themselves out. static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + if (result.getResultType() != ResultWas::Warning) + m_messageScopes.clear(); + // Reset working state resetAssertionInfo(); m_lastResult = result; @@ -215,6 +218,7 @@ namespace Catch { m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); m_messages.clear(); + m_messageScopes.clear(); } void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { @@ -241,6 +245,10 @@ namespace Catch { m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); } + void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { + m_messageScopes.emplace_back( builder ); + } + std::string RunContext::getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name @@ -301,6 +309,7 @@ namespace Catch { m_lastAssertionPassed = true; ++m_totals.assertions.passed; resetAssertionInfo(); + m_messageScopes.clear(); } bool RunContext::aborting() const { @@ -352,6 +361,7 @@ namespace Catch { m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); + m_messageScopes.clear(); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h index 259fecd3..c530a7b2 100644 --- a/include/internal/catch_run_context.h +++ b/include/internal/catch_run_context.h @@ -88,6 +88,8 @@ namespace Catch { void pushScopedMessage( MessageInfo const& message ) override; void popScopedMessage( MessageInfo const& message ) override; + void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + std::string getCurrentTestName() const override; const AssertionResult* getLastResult() const override; @@ -135,6 +137,7 @@ namespace Catch { Totals m_totals; IStreamingReporterPtr m_reporter; std::vector m_messages; + std::vector m_messageScopes; /* Keeps owners of so-called unscoped messages. */ AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector m_activeSections;