Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2
diff options
context:
space:
mode:
authorLeitwolf112026-10-24 12:41:08 +0300
committerLeitwolf112026-10-24 12:41:08 +0300
commite18f19b7dd70c99fbcf2b3fe812ee18dabc92663 (patch)
tree4cfc1a3c51ade9b8281925d1c122c12c87f8e381 /src/catch2
parente104b694513964d5a84e77f751203cda970d741b (diff)
downloadcatch3-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.cpp4
-rw-r--r--src/catch2/internal/catch_run_context.hpp9
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 );