diff options
| author | Leitwolf11 | 2026-10-24 14:21:11 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-24 14:21:11 +0300 |
| commit | 906a47a04fe0be9e7e6769d8cae59b4b1d286460 (patch) | |
| tree | 9193c87437158c60dbb689868bd3722794839dc2 /src | |
| parent | e18f19b7dd70c99fbcf2b3fe812ee18dabc92663 (diff) | |
| download | catch3-906a47a04fe0be9e7e6769d8cae59b4b1d286460.tar.gz | |
Send what listeners print at start-up in the worker's greeting
Listeners that print while they are created raced with the first test:
the text went through the worker's error stream and could reach the
runner after it had given the worker a test, which then claimed it as its
own output. The worker now captures Catch2's standard streams while it
creates the listeners and starts the run, sends the text in its hello
message, and the runner writes it to its standard error.
Catch2's stream redirect now remembers the buffer to restore when a
redirect starts rather than when it is made, so a stream whose buffer
changed in between is restored to the right one.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Progmasoft/Runner/Execution.cpp | 17 | ||||
| -rw-r--r-- | src/Progmasoft/Runner/Scheduler.cpp | 8 | ||||
| -rw-r--r-- | src/catch2/internal/catch_output_redirect.cpp | 10 |
3 files changed, 28 insertions, 7 deletions
diff --git a/src/Progmasoft/Runner/Execution.cpp b/src/Progmasoft/Runner/Execution.cpp index 77a4771a..3a2206d0 100644 --- a/src/Progmasoft/Runner/Execution.cpp +++ b/src/Progmasoft/Runner/Execution.cpp @@ -10,6 +10,7 @@ #include <catch2/internal/catch_context.hpp> #include <catch2/internal/catch_reporter_registry.hpp> #include <catch2/internal/catch_run_context.hpp> +#include <catch2/internal/catch_stdstreams.hpp> #include <catch2/internal/catch_string_manip.hpp> #include <catch2/reporters/catch_reporter_multi.hpp> #include <chrono> @@ -17,6 +18,7 @@ #include <cstdlib> #include <mutex> #include <optional> +#include <sstream> #include "Execution.hpp" #include "Process.hpp" @@ -543,14 +545,23 @@ namespace Progmasoft::Catch3::Runner connected = false; } }; - // Listeners are created and told of the run before the greeting, so - // what they print then is written before the runner assigns a test - // and is not mistaken for that test's output. + // Listeners are created, and told of the run, before the greeting. + // What they print then travels in the greeting: through the error + // stream it could arrive after the runner gave this worker a test, + // and pass for that test's output. + std::ostringstream startup; + auto *const previousOut = Catch::cout().rdbuf(startup.rdbuf()); + auto *const previousErr = Catch::cerr().rdbuf(startup.rdbuf()); + auto *const previousLog = Catch::clog().rdbuf(startup.rdbuf()); TestExecutor executor{ options, *catalog, programName, send }; + Catch::cout().rdbuf(previousOut); + Catch::cerr().rdbuf(previousErr); + Catch::clog().rdbuf(previousLog); std::fflush(stdout); std::fflush(stderr); JsonValue hello = Message("hello"); + hello.Set("output", startup.str()); hello.Set("pid", CurrentProcessId()); hello.Set("identity", catalog->Identity()); hello.Set("tests", catalog->Tests().size()); diff --git a/src/Progmasoft/Runner/Scheduler.cpp b/src/Progmasoft/Runner/Scheduler.cpp index 6a65f289..fce50f2c 100644 --- a/src/Progmasoft/Runner/Scheduler.cpp +++ b/src/Progmasoft/Runner/Scheduler.cpp @@ -728,6 +728,14 @@ namespace Progmasoft::Catch3::Runner } worker.ready = true; startupFailures_ = 0; + // What the listeners printed when the worker started. + const std::string &output = message["output"].AsString(); + if (!output.empty()) + { + AppendBounded(worker.startupOutput, output); + std::fwrite(output.data(), 1, output.size(), stderr); + std::fflush(stderr); + } return; } if (!worker.running) diff --git a/src/catch2/internal/catch_output_redirect.cpp b/src/catch2/internal/catch_output_redirect.cpp index 0ea126a5..7a079cd2 100644 --- a/src/catch2/internal/catch_output_redirect.cpp +++ b/src/catch2/internal/catch_output_redirect.cpp @@ -46,21 +46,23 @@ namespace Catch { * * Redirection can be stopped and started on-demand, assumes * that the underlying stream's rdbuf aren't changed by other - * users. + * users while it is active. The rdbuf to restore is the one the + * stream had when the redirection started, not when this object + * was made. */ class RedirectedStreamNew { std::ostream& m_originalStream; std::ostream& m_redirectionStream; - std::streambuf* m_prevBuf; + std::streambuf* m_prevBuf = nullptr; public: RedirectedStreamNew( std::ostream& originalStream, std::ostream& redirectionStream ): m_originalStream( originalStream ), - m_redirectionStream( redirectionStream ), - m_prevBuf( m_originalStream.rdbuf() ) {} + m_redirectionStream( redirectionStream ) {} void startRedirect() { + m_prevBuf = m_originalStream.rdbuf(); m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); } void stopRedirect() { m_originalStream.rdbuf( m_prevBuf ); } |