diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index 88c56603..8cd637c6 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -22,6 +22,7 @@ #include "catch_result_builder.h" #include "catch_fatal_condition.hpp" + #include #include @@ -50,6 +51,29 @@ namespace Catch { std::string& m_targetString; }; + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes and cannot use StreamRedirect on its own + class StdErrRedirect { + public: + StdErrRedirect(std::string& targetString) + :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), + m_targetString(targetString){ + cerr().rdbuf(m_oss.rdbuf()); + clog().rdbuf(m_oss.rdbuf()); + } + ~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { @@ -305,7 +329,7 @@ namespace Catch { timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + StdErrRedirect errRedir( redirectedCerr ); invokeActiveTestCase(); } else { diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index d8deebab..4323c318 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -21,6 +21,7 @@ namespace Catch { std::ostream& cout(); std::ostream& cerr(); + std::ostream& clog(); struct IStream { diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp index 42f51e82..b8838d34 100644 --- a/include/internal/catch_stream.hpp +++ b/include/internal/catch_stream.hpp @@ -103,6 +103,9 @@ namespace Catch { std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { + return std::clog; + } #endif } diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 19e545ba..439da767 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -622,6 +622,9 @@ with messages: A string sent directly to stdout A string sent directly to stderr +Write to std::cerr +Write to std::clog +Interleaved writes to error streams Message from section one Message from section two ------------------------------------------------------------------------------- @@ -953,6 +956,6 @@ with expansion: "first" == "second" =============================================================================== -test cases: 168 | 119 passed | 45 failed | 4 failed as expected +test cases: 169 | 120 passed | 45 failed | 4 failed as expected assertions: 968 | 859 passed | 88 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index cdc414a4..9cb93b13 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -6786,6 +6786,39 @@ PASSED: with expansion: Approx( 1.23 ) != 1.24 +Write to std::cerr +------------------------------------------------------------------------------- +Standard error is reported and redirected + std::cerr +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'std::cerr' + +Write to std::clog +------------------------------------------------------------------------------- +Standard error is reported and redirected + std::clog +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'std::clog' + +Interleaved writes to error streams +------------------------------------------------------------------------------- +Standard error is reported and redirected + Interleaved writes to cerr and clog +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'Interleaved writes to cerr and clog' + Message from section one ------------------------------------------------------------------------------- Standard output from all sections is reported @@ -9483,6 +9516,6 @@ MiscTests.cpp:: PASSED: =============================================================================== -test cases: 168 | 118 passed | 46 failed | 4 failed as expected -assertions: 970 | 859 passed | 90 failed | 21 failed as expected +test cases: 169 | 118 passed | 47 failed | 4 failed as expected +assertions: 973 | 859 passed | 93 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index b723f207..d8b788e3 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,6 +1,6 @@ - + @@ -475,6 +475,13 @@ A string sent directly to stderr + + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + Message from section one @@ -750,6 +757,9 @@ hello A string sent directly to stderr +Write to std::cerr +Write to std::clog +Interleaved writes to error streams diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 6361fee3..e1030964 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -7309,6 +7309,24 @@ A string sent directly to stderr + +
+ +
+
+ +
+
+ +
+ + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + +
@@ -10143,7 +10161,7 @@ spanner
- + - + diff --git a/projects/SelfTest/MessageTests.cpp b/projects/SelfTest/MessageTests.cpp index bed9c137..047bead7 100644 --- a/projects/SelfTest/MessageTests.cpp +++ b/projects/SelfTest/MessageTests.cpp @@ -99,6 +99,23 @@ TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) } } +TEST_CASE( "Standard error is reported and redirected", "[messages][.]" ) { + SECTION( "std::cerr" ) { + std::cerr << "Write to std::cerr" << std::endl; + } + SECTION( "std::clog" ) { + std::clog << "Write to std::clog" << std::endl; + } + SECTION( "Interleaved writes to cerr and clog" ) { + std::cerr << "Inter"; + std::clog << "leaved"; + std::cerr << ' '; + std::clog << "writes"; + std::cerr << " to error"; + std::clog << " streams\n"; + } +} + TEST_CASE( "SCOPED_INFO is reset for each loop", "[messages][failing][.]" ) { for( int i=0; i<100; i++ )