diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java
index da4d81625f6d..0d2314bb7687 100644
--- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java
+++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java
@@ -60,6 +60,21 @@ public class LauncherConstants {
*/
public static final String CAPTURE_STDERR_PROPERTY_NAME = "junit.platform.output.capture.stderr";
+ /**
+ * Property name used to enable merging and capturing output to {@link System#err} and {@link System#out}:
+ * {@value}
+ *
+ *
If enabled, the JUnit Platform merges stdout and stderr and publishes
+ * it as a {@link ReportEntry} using the
+ * {@value #STDOUT_REPORT_ENTRY_KEY} key immediately before reporting the
+ * test identifier as finished.
+ *
+ * @see #STDOUT_REPORT_ENTRY_KEY
+ * @see ReportEntry
+ * @see TestExecutionListener#reportingEntryPublished(TestIdentifier, ReportEntry)
+ */
+ public static final String CAPTURE_MERGED_STANDARD_STREAMS_PROPERTY_NAME = "junit.platform.output.capture.merge";
+
/**
* Property name used to configure the maximum number of bytes for buffering
* to use per thread and output type if output capturing is enabled:
diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java
index 32a135896554..a9e7e647f218 100644
--- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java
+++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListener.java
@@ -12,6 +12,7 @@
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_MAX_BUFFER_DEFAULT;
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_MAX_BUFFER_PROPERTY_NAME;
+import static org.junit.platform.launcher.LauncherConstants.CAPTURE_MERGED_STANDARD_STREAMS_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDERR_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDOUT_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.STDERR_REPORT_ENTRY_KEY;
@@ -43,17 +44,28 @@ static Optional create(ConfigurationPar
boolean captureStdout = configurationParameters.getBoolean(CAPTURE_STDOUT_PROPERTY_NAME).orElse(false);
boolean captureStderr = configurationParameters.getBoolean(CAPTURE_STDERR_PROPERTY_NAME).orElse(false);
- if (!captureStdout && !captureStderr) {
+ boolean captureMergeStandardStreams = configurationParameters.getBoolean(
+ CAPTURE_MERGED_STANDARD_STREAMS_PROPERTY_NAME).orElse(false);
+
+ if (!captureStdout && !captureStderr && !captureMergeStandardStreams) {
return Optional.empty();
}
int maxSize = configurationParameters.get(CAPTURE_MAX_BUFFER_PROPERTY_NAME, Integer::valueOf) //
.orElse(CAPTURE_MAX_BUFFER_DEFAULT);
- Optional stdoutInterceptor = captureStdout ? StreamInterceptor.registerStdout(maxSize)
- : Optional.empty();
- Optional stderrInterceptor = captureStderr ? StreamInterceptor.registerStderr(maxSize)
- : Optional.empty();
+ Optional stdoutInterceptor = Optional.empty();
+ Optional stderrInterceptor = Optional.empty();
+
+ if (captureMergeStandardStreams) {
+ stdoutInterceptor = StreamInterceptor.registerMergedStandardStreams(maxSize);
+ captureStderr = false;
+ captureStdout = true;
+ }
+ else {
+ stdoutInterceptor = captureStdout ? StreamInterceptor.registerStdout(maxSize) : Optional.empty();
+ stderrInterceptor = captureStderr ? StreamInterceptor.registerStderr(maxSize) : Optional.empty();
+ }
if ((!stdoutInterceptor.isPresent() && captureStdout) || (!stderrInterceptor.isPresent() && captureStderr)) {
stdoutInterceptor.ifPresent(StreamInterceptor::unregister);
diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java
index b34fd72c1a15..150b15880dab 100644
--- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java
+++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StreamInterceptor.java
@@ -37,6 +37,12 @@ static Optional registerStderr(int maxNumberOfBytesPerThread)
return register(System.err, System::setErr, maxNumberOfBytesPerThread);
}
+ static Optional registerMergedStandardStreams(int maxNumberOfBytesPerThread) {
+ Optional interceptor = registerStdout(maxNumberOfBytesPerThread);
+ interceptor.ifPresent((System::setErr));
+ return interceptor;
+ }
+
static Optional register(PrintStream originalStream, Consumer streamSetter,
int maxNumberOfBytesPerThread) {
if (originalStream instanceof StreamInterceptor) {
diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java
index 01aacc458db0..b6ffc1c049f8 100644
--- a/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java
+++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/StreamInterceptingTestExecutionListenerIntegrationTests.java
@@ -15,6 +15,7 @@
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.junit.platform.engine.TestExecutionResult.successful;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId;
+import static org.junit.platform.launcher.LauncherConstants.CAPTURE_MERGED_STANDARD_STREAMS_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDERR_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.CAPTURE_STDOUT_PROPERTY_NAME;
import static org.junit.platform.launcher.LauncherConstants.STDERR_REPORT_ENTRY_KEY;
@@ -119,7 +120,8 @@ void doesNotInterceptStreamWhenAlreadyBeingIntercepted(String configParam,
private static Stream systemStreams() {
return Stream.of(//
streamType(CAPTURE_STDOUT_PROPERTY_NAME, () -> System.out, STDOUT_REPORT_ENTRY_KEY), //
- streamType(CAPTURE_STDERR_PROPERTY_NAME, () -> System.err, STDERR_REPORT_ENTRY_KEY));
+ streamType(CAPTURE_STDERR_PROPERTY_NAME, () -> System.err, STDERR_REPORT_ENTRY_KEY), //
+ streamType(CAPTURE_MERGED_STANDARD_STREAMS_PROPERTY_NAME, () -> System.out, STDOUT_REPORT_ENTRY_KEY));
}
private static Arguments streamType(String configParam, Supplier printStreamSupplier,