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,