From f55edf19aed12ba4af7e20c184657c2e73e5db2e Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Fri, 29 Apr 2022 11:44:18 -0700 Subject: [PATCH 1/8] Fix #2481 - Only flush output frequently for ProgressFormatter --- .../cucumber/core/plugin/NiceAppendable.java | 6 ++- .../cucumber/core/plugin/PrettyFormatter.java | 2 +- .../core/plugin/ProgressFormatter.java | 2 +- .../cucumber/core/plugin/RerunFormatter.java | 2 +- .../plugin/UnusedStepsSummaryPrinter.java | 4 +- .../core/plugin/NiceAppendableTest.java | 53 +++++++++++++++++++ .../core/plugin/PluginFactoryTest.java | 2 +- 7 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java diff --git a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java index 15178104b9..3dee93a2e8 100644 --- a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java +++ b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java @@ -11,9 +11,11 @@ final class NiceAppendable implements Appendable { private static final CharSequence NL = "\n"; private final Appendable out; + private final boolean flushEveryWrite; - public NiceAppendable(Appendable out) { + public NiceAppendable(Appendable out, boolean flushEveryWrite) { this.out = out; + this.flushEveryWrite = flushEveryWrite; } public NiceAppendable println() { @@ -51,7 +53,7 @@ public NiceAppendable append(char c) { } private void tryFlush() { - if (!(out instanceof Flushable)) { + if (!(out instanceof Flushable && flushEveryWrite)) { return; } diff --git a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java index 04033f53c8..18286f704e 100644 --- a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java @@ -49,7 +49,7 @@ public final class PrettyFormatter implements ConcurrentEventListener, ColorAwar private Formats formats = ansi(); public PrettyFormatter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); } @Override diff --git a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java index 44283c9268..b5a17cb06e 100644 --- a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java @@ -39,7 +39,7 @@ public final class ProgressFormatter implements ConcurrentEventListener, ColorAw private boolean monochrome = false; public ProgressFormatter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), true); } @Override diff --git a/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java b/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java index b487fa76e2..16da46ddca 100644 --- a/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java @@ -27,7 +27,7 @@ public final class RerunFormatter implements ConcurrentEventListener { private final Map> featureAndFailedLinesMapping = new HashMap<>(); public RerunFormatter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); } @Override diff --git a/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java b/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java index 7cdb6cda22..56117627ad 100644 --- a/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java +++ b/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java @@ -27,7 +27,7 @@ public final class UnusedStepsSummaryPrinter implements ColorAware, ConcurrentEv private Formats formats = ansi(); public UnusedStepsSummaryPrinter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); } @Override @@ -68,6 +68,8 @@ private void finishReport() { String pattern = entry.getValue(); out.println(format.text(location) + " # " + pattern); } + + out.close(); } @Override diff --git a/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java b/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java new file mode 100644 index 0000000000..713649185f --- /dev/null +++ b/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java @@ -0,0 +1,53 @@ +package io.cucumber.core.plugin; + +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; + +import static io.cucumber.core.plugin.BytesEqualTo.isBytesEqualTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class NiceAppendableTest { + + @Test + public void should_flush_every_call_if_configured() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamWriter writer = spy(new OutputStreamWriter(out)); + NiceAppendable appendable = new NiceAppendable(writer, true); + + appendable + .append("First String,") + .append("__Second String__", 2, 15) + .append("\n") + .println("Second line") + .println() + .close(); + + assertThat(out, isBytesEqualTo("First String,Second String\nSecond line\n\n")); + verify(writer, times(6)).flush(); // Each method call flushes + } + + @Test + public void should_not_flush_unless_configured() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamWriter writer = spy(new OutputStreamWriter(out)); + NiceAppendable appendable = new NiceAppendable(writer, false); + + appendable + .append("First String,") + .append("__Second String__", 2, 15) + .append("\n") + .println("Second line") + .println() + .close(); + + assertThat(out, isBytesEqualTo("First String,Second String\nSecond line\n\n")); + verify(writer, times(0)).flush(); + } + +} diff --git a/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java b/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java index 82c6e40395..06f5145f68 100644 --- a/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java @@ -356,7 +356,7 @@ public static class WantsAppendable extends StubFormatter { public final NiceAppendable arg; public WantsAppendable(Appendable arg) { - this.arg = new NiceAppendable(Objects.requireNonNull(arg)); + this.arg = new NiceAppendable(Objects.requireNonNull(arg), false); } public void writeAndClose(String s) { From 4e020ded54179322aaf1b0974359258135321245 Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Fri, 29 Apr 2022 14:01:03 -0700 Subject: [PATCH 2/8] Address code review comments --- .../src/main/java/io/cucumber/core/plugin/NiceAppendable.java | 4 ++++ .../main/java/io/cucumber/core/plugin/PrettyFormatter.java | 2 +- .../main/java/io/cucumber/core/plugin/ProgressFormatter.java | 2 ++ .../src/main/java/io/cucumber/core/plugin/RerunFormatter.java | 2 +- .../io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java | 2 +- .../test/java/io/cucumber/core/plugin/NiceAppendableTest.java | 2 +- .../test/java/io/cucumber/core/plugin/PluginFactoryTest.java | 2 +- 7 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java index 3dee93a2e8..ea6b6fb0b4 100644 --- a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java +++ b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java @@ -13,6 +13,10 @@ final class NiceAppendable implements Appendable { private final Appendable out; private final boolean flushEveryWrite; + public NiceAppendable(Appendable out) { + this(out, false); + } + public NiceAppendable(Appendable out, boolean flushEveryWrite) { this.out = out; this.flushEveryWrite = flushEveryWrite; diff --git a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java index 18286f704e..04033f53c8 100644 --- a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java @@ -49,7 +49,7 @@ public final class PrettyFormatter implements ConcurrentEventListener, ColorAwar private Formats formats = ansi(); public PrettyFormatter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); } @Override diff --git a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java index b5a17cb06e..12fa364a99 100644 --- a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java @@ -39,6 +39,8 @@ public final class ProgressFormatter implements ConcurrentEventListener, ColorAw private boolean monochrome = false; public ProgressFormatter(OutputStream out) { + // Configure the NiceAppendable to flush on every append, since the + // point of this formatter is to display a progress bar. this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), true); } diff --git a/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java b/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java index 16da46ddca..b487fa76e2 100644 --- a/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java @@ -27,7 +27,7 @@ public final class RerunFormatter implements ConcurrentEventListener { private final Map> featureAndFailedLinesMapping = new HashMap<>(); public RerunFormatter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); } @Override diff --git a/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java b/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java index 56117627ad..637ae52654 100644 --- a/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java +++ b/core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java @@ -27,7 +27,7 @@ public final class UnusedStepsSummaryPrinter implements ColorAware, ConcurrentEv private Formats formats = ansi(); public UnusedStepsSummaryPrinter(OutputStream out) { - this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), false); + this.out = new NiceAppendable(new UTF8OutputStreamWriter(out)); } @Override diff --git a/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java b/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java index 713649185f..0269503189 100644 --- a/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java @@ -36,7 +36,7 @@ public void should_flush_every_call_if_configured() throws IOException { public void should_not_flush_unless_configured() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); OutputStreamWriter writer = spy(new OutputStreamWriter(out)); - NiceAppendable appendable = new NiceAppendable(writer, false); + NiceAppendable appendable = new NiceAppendable(writer); appendable .append("First String,") diff --git a/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java b/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java index 06f5145f68..82c6e40395 100644 --- a/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java @@ -356,7 +356,7 @@ public static class WantsAppendable extends StubFormatter { public final NiceAppendable arg; public WantsAppendable(Appendable arg) { - this.arg = new NiceAppendable(Objects.requireNonNull(arg), false); + this.arg = new NiceAppendable(Objects.requireNonNull(arg)); } public void writeAndClose(String s) { From 6d01075614796a115afcbda52848dc7aa9808e71 Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Fri, 29 Apr 2022 14:29:04 -0700 Subject: [PATCH 3/8] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3936627fbd..f9088cc7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Removed ### Fixed +* [Core] Pretty print plugin performance issues; incorrect DataTable format in Gradle console ([#2541](https://github.com/cucumber/cucumber-jvm/pull/2541) Scott Davis) ## [7.3.2] (2022-04-22) From 26b481174a41b9cebeab2154f87e8a9a0a07409b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 30 Apr 2022 21:32:09 +0200 Subject: [PATCH 4/8] Prevent tearing in progress formatter output --- .../core/plugin/ProgressFormatter.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java index 12fa364a99..e3d01fd7f2 100644 --- a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java @@ -56,15 +56,21 @@ public void setEventPublisher(EventPublisher publisher) { } private void handleTestStepFinished(TestStepFinished event) { - if (event.getTestStep() instanceof PickleStepTestStep || event.getResult().getStatus().is(Status.FAILED)) { - if (!monochrome) { - ANSI_ESCAPES.get(event.getResult().getStatus()).appendTo(out); - } - out.append(CHARS.get(event.getResult().getStatus())); - if (!monochrome) { - AnsiEscapes.RESET.appendTo(out); - } + boolean isTestStep = event.getTestStep() instanceof PickleStepTestStep; + boolean isFailedHookOrTestStep = event.getResult().getStatus().is(Status.FAILED); + if (!(isTestStep || isFailedHookOrTestStep)) { + return; } + // Prevent tearing in output when multiple threads write to System.out + StringBuilder buffer = new StringBuilder(); + if (!monochrome) { + ANSI_ESCAPES.get(event.getResult().getStatus()).appendTo(buffer); + } + out.append(CHARS.get(event.getResult().getStatus())); + if (!monochrome) { + AnsiEscapes.RESET.appendTo(buffer); + } + out.append(buffer); } private void handleTestRunFinished() { From 8aea1e30212ac9c41ba5ff0397187ff18da1883e Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 30 Apr 2022 21:43:30 +0200 Subject: [PATCH 5/8] Prevent interleaving in pretty formatter output --- .../main/java/io/cucumber/core/plugin/PrettyFormatter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java index 04033f53c8..940e9c84b9 100644 --- a/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java @@ -181,14 +181,17 @@ private void printError(Result result) { } private void printText(WriteEvent event) { + // Prevent interleaving when multiple threads write to System.out + StringBuilder builder = new StringBuilder(); try (BufferedReader lines = new BufferedReader(new StringReader(event.getText()))) { String line; while ((line = lines.readLine()) != null) { - out.println(STEP_SCENARIO_INDENT + line); + builder.append(String.format(STEP_SCENARIO_INDENT + line + "%n")); } } catch (IOException e) { throw new CucumberException(e); } + out.append(builder); } private void printEmbedding(EmbedEvent event) { @@ -230,7 +233,6 @@ private String calculateLocationIndent(TestCase testStep, String prefix) { if (padding < 0) { return " "; } - StringBuilder builder = new StringBuilder(padding); for (int i = 0; i < padding; i++) { builder.append(" "); From ceaf870a0536771aa0fccd4c58cd7323d48cc353 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 30 Apr 2022 22:29:24 +0200 Subject: [PATCH 6/8] Separate flag condition from instance of condition --- .../main/java/io/cucumber/core/plugin/NiceAppendable.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java index ea6b6fb0b4..0dded5f9c5 100644 --- a/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java +++ b/core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java @@ -57,7 +57,11 @@ public NiceAppendable append(char c) { } private void tryFlush() { - if (!(out instanceof Flushable && flushEveryWrite)) { + if (!(out instanceof Flushable)) { + return; + } + + if (!flushEveryWrite) { return; } From 42a33b9e1378eb5ea58f37dc32627b5620bcf26b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 30 Apr 2022 22:49:23 +0200 Subject: [PATCH 7/8] Add test coverage for progress formatter --- .../core/plugin/ProgressFormatter.java | 6 +- .../core/plugin/ProgressFormatterTest.java | 82 +++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java diff --git a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java index e3d01fd7f2..3843393c1c 100644 --- a/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java @@ -52,7 +52,7 @@ public void setMonochrome(boolean monochrome) { @Override public void setEventPublisher(EventPublisher publisher) { publisher.registerHandlerFor(TestStepFinished.class, this::handleTestStepFinished); - publisher.registerHandlerFor(TestRunFinished.class, event -> handleTestRunFinished()); + publisher.registerHandlerFor(TestRunFinished.class, this::handleTestRunFinished); } private void handleTestStepFinished(TestStepFinished event) { @@ -66,14 +66,14 @@ private void handleTestStepFinished(TestStepFinished event) { if (!monochrome) { ANSI_ESCAPES.get(event.getResult().getStatus()).appendTo(buffer); } - out.append(CHARS.get(event.getResult().getStatus())); + buffer.append(CHARS.get(event.getResult().getStatus())); if (!monochrome) { AnsiEscapes.RESET.appendTo(buffer); } out.append(buffer); } - private void handleTestRunFinished() { + private void handleTestRunFinished(TestRunFinished testRunFinished) { out.println(); out.close(); } diff --git a/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java b/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java new file mode 100644 index 0000000000..6a180d2292 --- /dev/null +++ b/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java @@ -0,0 +1,82 @@ +package io.cucumber.core.plugin; + +import io.cucumber.core.eventbus.EventBus; +import io.cucumber.core.runtime.TimeServiceEventBus; +import io.cucumber.plugin.event.HookTestStep; +import io.cucumber.plugin.event.PickleStepTestStep; +import io.cucumber.plugin.event.Result; +import io.cucumber.plugin.event.TestCase; +import io.cucumber.plugin.event.TestRunFinished; +import io.cucumber.plugin.event.TestRunStarted; +import io.cucumber.plugin.event.TestStepFinished; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.UUID; + +import static io.cucumber.core.plugin.BytesEqualTo.isBytesEqualTo; +import static io.cucumber.plugin.event.Status.FAILED; +import static io.cucumber.plugin.event.Status.PASSED; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.mock; + +class ProgressFormatterTest { + + final EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ProgressFormatter formatter = new ProgressFormatter(out); + + @BeforeEach + void setup() { + formatter.setEventPublisher(bus); + } + + @Test + void prints_empty_line_for_empty_test_run() { + bus.send(new TestRunStarted(Instant.now())); + Result runResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestRunFinished(Instant.now(), runResult)); + assertThat(out, isBytesEqualTo("\n")); + } + + @Test + void print_green_dot_for_passing_scenario() { + bus.send(new TestRunStarted(Instant.now())); + Result stepResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); + Result hookResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); + Result runResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestRunFinished(Instant.now(), runResult)); + assertThat(out, isBytesEqualTo(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET + "\n")); + } + + @Test + void print_red_F_for_failed_scenario() { + bus.send(new TestRunStarted(Instant.now())); + Result stepResult = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); + Result hookResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); + Result runResult = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestRunFinished(Instant.now(), runResult)); + assertThat(out, isBytesEqualTo(AnsiEscapes.RED + "F" + AnsiEscapes.RESET + "\n")); + } + + @Test + void print_red_F_for_failed_hook() { + bus.send(new TestRunStarted(Instant.now())); + Result stepResult = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); + Result hookResult = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); + Result runResult = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestRunFinished(Instant.now(), runResult)); + assertThat(out, isBytesEqualTo(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET + AnsiEscapes.RED + "F" + AnsiEscapes.RESET + "\n")); + } + +} From d2722a8202a5908b8eb1beb12dcd1ea0a0ab0777 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 30 Apr 2022 23:02:48 +0200 Subject: [PATCH 8/8] Simplify ProgressFormatterTests --- .../core/plugin/ProgressFormatterTest.java | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java b/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java index 6a180d2292..2aa184ea19 100644 --- a/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java @@ -7,7 +7,6 @@ import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestRunFinished; -import io.cucumber.plugin.event.TestRunStarted; import io.cucumber.plugin.event.TestStepFinished; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,6 +20,7 @@ import static io.cucumber.core.plugin.BytesEqualTo.isBytesEqualTo; import static io.cucumber.plugin.event.Status.FAILED; import static io.cucumber.plugin.event.Status.PASSED; +import static io.cucumber.plugin.event.Status.UNDEFINED; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; @@ -37,46 +37,49 @@ void setup() { @Test void prints_empty_line_for_empty_test_run() { - bus.send(new TestRunStarted(Instant.now())); Result runResult = new Result(PASSED, Duration.ZERO, null); bus.send(new TestRunFinished(Instant.now(), runResult)); assertThat(out, isBytesEqualTo("\n")); } @Test - void print_green_dot_for_passing_scenario() { - bus.send(new TestRunStarted(Instant.now())); - Result stepResult = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); - Result hookResult = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); - Result runResult = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestRunFinished(Instant.now(), runResult)); + void print_green_dot_for_passing_step() { + Result result = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestRunFinished(Instant.now(), result)); assertThat(out, isBytesEqualTo(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET + "\n")); } @Test - void print_red_F_for_failed_scenario() { - bus.send(new TestRunStarted(Instant.now())); - Result stepResult = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); - Result hookResult = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); - Result runResult = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestRunFinished(Instant.now(), runResult)); + void print_yellow_U_for_undefined_step() { + Result result = new Result(UNDEFINED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestRunFinished(Instant.now(), result)); + assertThat(out, isBytesEqualTo(AnsiEscapes.YELLOW + "U" + AnsiEscapes.RESET + "\n")); + } + + @Test + void print_nothing_for_passed_hook() { + Result result = new Result(PASSED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), result)); + bus.send(new TestRunFinished(Instant.now(), result)); + assertThat(out, isBytesEqualTo("\n")); + } + + @Test + void print_red_F_for_failed_step() { + Result result = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestRunFinished(Instant.now(), result)); assertThat(out, isBytesEqualTo(AnsiEscapes.RED + "F" + AnsiEscapes.RESET + "\n")); } @Test void print_red_F_for_failed_hook() { - bus.send(new TestRunStarted(Instant.now())); - Result stepResult = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), stepResult)); - Result hookResult = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), hookResult)); - Result runResult = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestRunFinished(Instant.now(), runResult)); - assertThat(out, isBytesEqualTo(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET + AnsiEscapes.RED + "F" + AnsiEscapes.RESET + "\n")); + Result result = new Result(FAILED, Duration.ZERO, null); + bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), result)); + bus.send(new TestRunFinished(Instant.now(), result)); + assertThat(out, isBytesEqualTo(AnsiEscapes.RED + "F" + AnsiEscapes.RESET + "\n")); } }