diff options
| author | Leitwolf11 | 2026-10-24 12:41:08 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-24 12:41:08 +0300 |
| commit | e18f19b7dd70c99fbcf2b3fe812ee18dabc92663 (patch) | |
| tree | 4cfc1a3c51ade9b8281925d1c122c12c87f8e381 /src/catch2 | |
| parent | e104b694513964d5a84e77f751203cda970d741b (diff) | |
| download | catch3-e18f19b7dd70c99fbcf2b3fe812ee18dabc92663.tar.gz | |
End the output capture when a test exits, fail on missing reports
A test that called exit() crashed its worker with SIGSEGV on Linux and
macOS. The exit hook read Catch2's captured output through a scoped
deactivation, which switched the capture back on; libstdc++ then flushed
std::cout at exit into a capture buffer that static destruction had
already freed. RunContext::endCapture() now ends the capture for good and
returns what it held, so the standard streams are their own again.
A JUnit, JSON or trace report that could not be written was only
reported on stderr, and a run whose tests passed still exited with 0, so a
build server could miss it. Such a run now exits with 1; failed tests
still exit with 42.
Integration tests of the runner's output move their helpers into
RunnerFixtureClient.hpp and cover --version, --help, the listing modes, a
bad option, exit codes 1 to 4, -v, -q, --slowest, colours, --analytics
in text and JSON, and Bazel's test environment.
Diffstat (limited to 'src/catch2')
| -rw-r--r-- | src/catch2/internal/catch_run_context.cpp | 4 | ||||
| -rw-r--r-- | src/catch2/internal/catch_run_context.hpp | 9 |
2 files changed, 8 insertions, 5 deletions
diff --git a/src/catch2/internal/catch_run_context.cpp b/src/catch2/internal/catch_run_context.cpp index 5c57ef18..30fa3edd 100644 --- a/src/catch2/internal/catch_run_context.cpp +++ b/src/catch2/internal/catch_run_context.cpp @@ -748,11 +748,11 @@ namespace Catch { return m_atomicAssertionCount.failed >= m_abortAfterXFailedAssertions; } - std::string RunContext::capturedOutput() { + std::string RunContext::endCapture() { if ( !m_outputRedirect->isActive() ) { return {}; } - auto _ = scopedDeactivate( *m_outputRedirect ); + m_outputRedirect->deactivate(); return m_outputRedirect->getStdout() + m_outputRedirect->getStderr(); } diff --git a/src/catch2/internal/catch_run_context.hpp b/src/catch2/internal/catch_run_context.hpp index c7bee285..5feb8890 100644 --- a/src/catch2/internal/catch_run_context.hpp +++ b/src/catch2/internal/catch_run_context.hpp @@ -106,9 +106,12 @@ namespace Catch { // !TBD We need to do this another way! bool aborting() const; - //! What the running test printed so far and was captured; for a - //! process that ends inside a test, whose end is never reported. - std::string capturedOutput(); + //! Ends the capture of the running test's output and returns what + //! it captured; for a process that ends inside a test, whose end is + //! never reported. The standard streams are their own again, so + //! flushing them at exit no longer reaches the capture buffers, + //! which may be gone by then. + std::string endCapture(); private: void assertionPassedFastPath( SourceLineInfo lineInfo ); |