Skip to content

Commit

Permalink
Enable auto-flushing of output to fix testfeed details mode (#4153)
Browse files Browse the repository at this point in the history
Prior to this commit, `ConsoleLauncher` created `PrintWriters` that 
wouldn't flush automatically when `println` is called which stopped the 
`testfeed` details mode from being useful. Moreover, it didn't 
initialized them with the right `Charsets`. Now, we rely on Picocli's 
initialization again which does both correctly.
  • Loading branch information
marcphilipp authored Nov 26, 2024
1 parent de40dbe commit b8b5dc4
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ JUnit repository on GitHub.

* Fix support for disabling ANSI colors on the console when the `NO_COLOR` environment
variable is available.
* Enable auto-flushing of output in the `ConsoleLauncher` to fix issues with buffering,
in particular when using the `--details=testfeed` option.

[[release-notes-5.12.0-M1-junit-platform-deprecations-and-breaking-changes]]
==== Deprecations and Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.jvm.toolchain.JavaLauncher
import org.gradle.jvm.toolchain.JavaToolchainService
Expand All @@ -16,7 +22,6 @@ import org.gradle.process.CommandLineArgumentProvider
import org.gradle.process.ExecOperations
import trackOperationSystemAsInput
import java.io.ByteArrayOutputStream
import java.util.*
import javax.inject.Inject

@CacheableTask
Expand Down Expand Up @@ -97,4 +102,13 @@ abstract class RunConsoleLauncher @Inject constructor(private val execOperations
debugging.set(enabled)
}

@Suppress("unused")
@Option(
option = "show-output",
description = "Show output"
)
fun setShowOutput(showOutput: Boolean) {
hideOutput.set(!showOutput)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,17 @@
public class ConsoleLauncher {

public static void main(String... args) {
PrintWriter out = new PrintWriter(System.out);
PrintWriter err = new PrintWriter(System.err);
CommandResult<?> result = run(out, err, args);
CommandResult<?> result = newCommandFacade().run(args);
System.exit(result.getExitCode());
}

@API(status = INTERNAL, since = "1.0")
public static CommandResult<?> run(PrintWriter out, PrintWriter err, String... args) {
ConsoleLauncher consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, out, err);
return consoleLauncher.run(args);
return newCommandFacade().run(args, out, err);
}

private final ConsoleTestExecutor.Factory consoleTestExecutorFactory;
private final PrintWriter out;
private final PrintWriter err;

ConsoleLauncher(ConsoleTestExecutor.Factory consoleTestExecutorFactory, PrintWriter out, PrintWriter err) {
this.consoleTestExecutorFactory = consoleTestExecutorFactory;
this.out = out;
this.err = err;
}

CommandResult<?> run(String... args) {
try {
return new CommandFacade(consoleTestExecutorFactory).run(out, err, args);
}
finally {
out.flush();
err.flush();
}
private static CommandFacade newCommandFacade() {
return new CommandFacade(ConsoleTestExecutor::new);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,24 @@ public CommandFacade(ConsoleTestExecutor.Factory consoleTestExecutorFactory) {
this.consoleTestExecutorFactory = consoleTestExecutorFactory;
}

public CommandResult<?> run(PrintWriter out, PrintWriter err, String[] args) {
public CommandResult<?> run(String[] args) {
return run(args, Optional.empty());
}

public CommandResult<?> run(String[] args, PrintWriter out, PrintWriter err) {
try {
return run(args, Optional.of(new OutputStreamConfig(out, err)));
}
finally {
out.flush();
err.flush();
}
}

private CommandResult<?> run(String[] args, Optional<OutputStreamConfig> outputStreamConfig) {
Optional<String> version = ManifestVersionProvider.getImplementationVersion();
System.setProperty("junit.docs.version",
version.map(it -> it.endsWith("-SNAPSHOT") ? "snapshot" : it).orElse("current"));
return new MainCommand(consoleTestExecutorFactory).run(out, err, args);
return new MainCommand(consoleTestExecutorFactory).run(args, outputStreamConfig);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ private Object runCommand(String subcommand, Optional<String> triggeringOption)

List<String> args = new ArrayList<>(commandLine.getParseResult().expandedArgs());
triggeringOption.ifPresent(args::remove);
CommandResult<?> result = runCommand(commandLine.getOut(), //
commandLine.getErr(), //
CommandResult<?> result = runCommand( //
new CommandLine(command), //
args.toArray(new String[0]), //
command);
Optional.of(new OutputStreamConfig(commandLine)) //
);
this.commandResult = result;

printDeprecationWarning(subcommand, triggeringOption, commandLine);
Expand All @@ -130,24 +131,19 @@ private static void printDeprecationWarning(String subcommand, Optional<String>
err.flush();
}

CommandResult<?> run(PrintWriter out, PrintWriter err, String[] args) {
CommandResult<?> run(String[] args, Optional<OutputStreamConfig> outputStreamConfig) {
CommandLine commandLine = new CommandLine(this) //
.addSubcommand(new DiscoverTestsCommand(consoleTestExecutorFactory)) //
.addSubcommand(new ExecuteTestsCommand(consoleTestExecutorFactory)) //
.addSubcommand(new ListTestEnginesCommand());
return runCommand(out, err, args, commandLine);
return runCommand(commandLine, args, outputStreamConfig);
}

private static CommandResult<?> runCommand(PrintWriter out, PrintWriter err, String[] args, Object command) {
return runCommand(out, err, args, new CommandLine(command));
}

private static CommandResult<Object> runCommand(PrintWriter out, PrintWriter err, String[] args,
CommandLine commandLine) {
int exitCode = BaseCommand.initialize(commandLine) //
.setOut(out) //
.setErr(err) //
.execute(args);
private static CommandResult<?> runCommand(CommandLine commandLine, String[] args,
Optional<OutputStreamConfig> outputStreamConfig) {
BaseCommand.initialize(commandLine);
outputStreamConfig.ifPresent(it -> it.applyTo(commandLine));
int exitCode = commandLine.execute(args);
return CommandResult.create(exitCode, getLikelyExecutedCommand(commandLine).getExecutionResult());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2015-2024 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* https://www.eclipse.org/legal/epl-v20.html
*/

package org.junit.platform.console.options;

import java.io.PrintWriter;

import picocli.CommandLine;

class OutputStreamConfig {

private final PrintWriter out;
private final PrintWriter err;

OutputStreamConfig(CommandLine commandLine) {
this(commandLine.getOut(), commandLine.getErr());
}

OutputStreamConfig(PrintWriter out, PrintWriter err) {
this.out = out;
this.err = err;
}

void applyTo(CommandLine commandLine) {
commandLine.setOut(out).setErr(err);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.platform.console.tasks.ConsoleTestExecutor;

/**
* @since 1.0
Expand All @@ -36,8 +35,7 @@ class ConsoleLauncherTests {
@EmptySource
@MethodSource("commandsWithEmptyOptionExitCodes")
void displayHelp(String command) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
var exitCode = consoleLauncher.run(command, "--help").getExitCode();
var exitCode = ConsoleLauncher.run(printSink, printSink, command, "--help").getExitCode();

assertEquals(0, exitCode);
assertThat(output()).contains("--help");
Expand All @@ -47,8 +45,7 @@ void displayHelp(String command) {
@EmptySource
@MethodSource("commandsWithEmptyOptionExitCodes")
void displayVersion(String command) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
var exitCode = consoleLauncher.run(command, "--version").getExitCode();
var exitCode = ConsoleLauncher.run(printSink, printSink, command, "--version").getExitCode();

assertEquals(0, exitCode);
assertThat(output()).contains("JUnit Platform Console Launcher");
Expand All @@ -57,17 +54,15 @@ void displayVersion(String command) {
@ParameterizedTest(name = "{0}")
@MethodSource("commandsWithEmptyOptionExitCodes")
void displayBanner(String command) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
consoleLauncher.run(command);
ConsoleLauncher.run(printSink, printSink, command);

assertThat(output()).contains("Thanks for using JUnit!");
}

@ParameterizedTest(name = "{0}")
@MethodSource("commandsWithEmptyOptionExitCodes")
void disableBanner(String command, int expectedExitCode) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
var exitCode = consoleLauncher.run(command, "--disable-banner").getExitCode();
var exitCode = ConsoleLauncher.run(printSink, printSink, command, "--disable-banner").getExitCode();

assertEquals(expectedExitCode, exitCode);
assertThat(output()).doesNotContain("Thanks for using JUnit!");
Expand All @@ -76,8 +71,7 @@ void disableBanner(String command, int expectedExitCode) {
@ParameterizedTest(name = "{0}")
@MethodSource("commandsWithEmptyOptionExitCodes")
void executeWithUnknownCommandLineOption(String command) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
var exitCode = consoleLauncher.run(command, "--all").getExitCode();
var exitCode = ConsoleLauncher.run(printSink, printSink, command, "--all").getExitCode();

assertEquals(-1, exitCode);
assertThat(output()).contains("Unknown option: '--all'").contains("Usage:");
Expand All @@ -90,8 +84,7 @@ private String output() {
@ParameterizedTest(name = "{0}")
@MethodSource("commandsWithEmptyOptionExitCodes")
void executeWithoutCommandLineOptions(String command, int expectedExitCode) {
var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink);
var actualExitCode = consoleLauncher.run(command).getExitCode();
var actualExitCode = ConsoleLauncher.run(printSink, printSink, command).getExitCode();

assertEquals(expectedExitCode, actualExitCode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.io.StringWriter;
import java.util.Optional;

import org.junit.platform.console.options.CommandFacade;
import org.junit.platform.console.tasks.ConsoleTestExecutor;

/**
Expand All @@ -26,16 +27,14 @@ class ConsoleLauncherWrapper {

private final StringWriter out = new StringWriter();
private final StringWriter err = new StringWriter();
private final ConsoleLauncher consoleLauncher;
private final ConsoleTestExecutor.Factory consoleTestExecutorFactory;

ConsoleLauncherWrapper() {
this(ConsoleTestExecutor::new);
}

private ConsoleLauncherWrapper(ConsoleTestExecutor.Factory consoleTestExecutorFactory) {
var outWriter = new PrintWriter(out, false);
var errWriter = new PrintWriter(err, false);
this.consoleLauncher = new ConsoleLauncher(consoleTestExecutorFactory, outWriter, errWriter);
this.consoleTestExecutorFactory = consoleTestExecutorFactory;
}

public ConsoleLauncherWrapperResult execute(String... args) {
Expand All @@ -47,7 +46,9 @@ public ConsoleLauncherWrapperResult execute(int expectedExitCode, String... args
}

public ConsoleLauncherWrapperResult execute(Optional<Integer> expectedCode, String... args) {
var result = consoleLauncher.run(args);
var outWriter = new PrintWriter(out, false);
var errWriter = new PrintWriter(err, false);
var result = new CommandFacade(consoleTestExecutorFactory).run(args, outWriter, errWriter);
var code = result.getExitCode();
var outText = out.toString();
var errText = err.toString();
Expand Down

0 comments on commit b8b5dc4

Please sign in to comment.