Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- [Core] Use a message based `RerunFormatter` ([#3075](https://github.com/cucumber/cucumber-jvm/pull/3075) M.P. Korstanje)
- [Core] Use a message based `TeamCityPlugin` ([#3050](https://github.com/cucumber/cucumber-jvm/pull/3050) M.P. Korstanje)
- [Core] Use a message based `DefaultSummaryPrinter` ([#3028](https://github.com/cucumber/cucumber-jvm/pull/3028) M.P. Korstanje)
- [Core] Use a message based `ProgressFormatter` ([#3028](https://github.com/cucumber/cucumber-jvm/pull/3028) M.P. Korstanje)
- [Core] Update dependency io.cucumber:cucumber-json-formatter to v0.2.0
- [Core] Update dependency io.cucumber:gherkin to v35.0.0
- [Core] Update dependency io.cucumber:html-formatter to v21.15.0
- [Core] Update dependency io.cucumber:junit-xml-formatter to v0.9.0
- [Core] Update dependency io.cucumber:messages to v29.0.1
- [Core] Update dependency io.cucumber:pretty-formatter to v2.2.0
- [Core] Update dependency io.cucumber:query to v14.0.1
- [Core] Update dependency io.cucumber:pretty-formatter to v2.3.0
- [Core] Update dependency io.cucumber:query to v14.3.0
- [Core] Update dependency io.cucumber:testng-xml-formatter to v0.6.0

## [7.28.2] - 2025-09-09
Expand Down
2 changes: 1 addition & 1 deletion cucumber-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<html-formatter.version>21.15.1</html-formatter.version>
<junit-xml-formatter.version>0.9.0</junit-xml-formatter.version>
<messages.version>29.0.1</messages.version>
<pretty-formatter.version>2.2.0</pretty-formatter.version>
<pretty-formatter.version>2.3.0</pretty-formatter.version>
<query.version>14.3.0</query.version>
<tag-expressions.version>6.1.2</tag-expressions.version>
<teamcity-formatter.version>0.1.1</teamcity-formatter.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,86 +1,66 @@
package io.cucumber.core.plugin;

import io.cucumber.messages.types.Envelope;
import io.cucumber.plugin.ColorAware;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.SnippetsSuggestedEvent;
import io.cucumber.plugin.event.TestRunFinished;
import io.cucumber.prettyformatter.MessagesToSummaryWriter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import static io.cucumber.prettyformatter.Theme.cucumber;
import static io.cucumber.prettyformatter.Theme.plain;

public final class DefaultSummaryPrinter implements ColorAware, ConcurrentEventListener {

private final Set<String> snippets = new LinkedHashSet<>();
private final Stats stats;
private final PrintStream out;
private final OutputStream out;
private MessagesToSummaryWriter writer;

public DefaultSummaryPrinter() {
this(System.out, Locale.getDefault());
}

DefaultSummaryPrinter(OutputStream out, Locale locale) {
this.out = new PrintStream(out);
this.stats = new Stats(locale);
this(new PrintStream(System.out) {
@Override
public void close() {
// Don't close System.out
}
});
}

@Override
public void setEventPublisher(EventPublisher publisher) {
stats.setEventPublisher(publisher);
publisher.registerHandlerFor(SnippetsSuggestedEvent.class, this::handleSnippetsSuggestedEvent);
publisher.registerHandlerFor(TestRunFinished.class, event -> print());
DefaultSummaryPrinter(OutputStream out) {
this.out = out;
this.writer = createBuilder().build(out);
}

private void handleSnippetsSuggestedEvent(SnippetsSuggestedEvent event) {
this.snippets.addAll(event.getSuggestion().getSnippets());
private static MessagesToSummaryWriter.Builder createBuilder() {
return MessagesToSummaryWriter.builder()
.theme(cucumber());
}

private void print() {
out.println();
printStats();
printErrors();
printSnippets();
out.println();
}

private void printStats() {
stats.printStats(out);
out.println();
@Override
public void setMonochrome(boolean monochrome) {
if (monochrome) {
writer = createBuilder().theme(plain()).build(out);
}
}

private void printErrors() {
List<Throwable> errors = stats.getErrors();
if (errors.isEmpty()) {
return;
}
out.println();
for (Throwable error : errors) {
error.printStackTrace(out);
out.println();
}
@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(Envelope.class, this::write);
}

private void printSnippets() {
if (snippets.isEmpty()) {
return;
private void write(Envelope event) {
try {
writer.write(event);
} catch (IOException e) {
throw new IllegalStateException(e);
}

out.println();
out.println("You can implement missing steps with the snippets below:");
out.println();
for (String snippet : snippets) {
out.println(snippet);
out.println();
// TODO: Plugins should implement the closable interface
// and be closed by Cucumber
if (event.getTestRunFinished().isPresent()) {
writer.close();
}
}

@Override
public void setMonochrome(boolean monochrome) {
stats.setMonochrome(monochrome);
}

}
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
package io.cucumber.core.plugin;

import io.cucumber.messages.types.Envelope;
import io.cucumber.messages.types.TestRunFinished;
import io.cucumber.messages.types.TestStepFinished;
import io.cucumber.messages.types.TestStepResultStatus;
import io.cucumber.plugin.ColorAware;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.prettyformatter.MessagesToProgressWriter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.EnumMap;
import java.util.Map;

import static io.cucumber.core.plugin.ProgressFormatter.Ansi.Attributes.FOREGROUND_CYAN;
import static io.cucumber.core.plugin.ProgressFormatter.Ansi.Attributes.FOREGROUND_DEFAULT;
import static io.cucumber.core.plugin.ProgressFormatter.Ansi.Attributes.FOREGROUND_GREEN;
import static io.cucumber.core.plugin.ProgressFormatter.Ansi.Attributes.FOREGROUND_RED;
import static io.cucumber.core.plugin.ProgressFormatter.Ansi.Attributes.FOREGROUND_YELLOW;
import static io.cucumber.messages.types.TestStepResultStatus.AMBIGUOUS;
import static io.cucumber.messages.types.TestStepResultStatus.FAILED;
import static io.cucumber.messages.types.TestStepResultStatus.PASSED;
import static io.cucumber.messages.types.TestStepResultStatus.PENDING;
import static io.cucumber.messages.types.TestStepResultStatus.SKIPPED;
import static io.cucumber.messages.types.TestStepResultStatus.UNDEFINED;
import static java.lang.System.lineSeparator;
import static java.util.Objects.requireNonNull;
import static io.cucumber.prettyformatter.Theme.cucumber;
import static io.cucumber.prettyformatter.Theme.plain;

/**
* Renders a rudimentary progress bar.
Expand All @@ -37,143 +20,42 @@
*/
public final class ProgressFormatter implements ConcurrentEventListener, ColorAware {

private static final int MAX_WIDTH = 80;
private static final Map<TestStepResultStatus, String> SYMBOLS = new EnumMap<>(TestStepResultStatus.class);
private static final Map<TestStepResultStatus, Ansi> ESCAPES = new EnumMap<>(TestStepResultStatus.class);
private static final Ansi RESET = Ansi.with(FOREGROUND_DEFAULT);
static {
SYMBOLS.put(PASSED, ".");
SYMBOLS.put(UNDEFINED, "U");
SYMBOLS.put(PENDING, "P");
SYMBOLS.put(SKIPPED, "-");
SYMBOLS.put(FAILED, "F");
SYMBOLS.put(AMBIGUOUS, "A");

ESCAPES.put(PASSED, Ansi.with(FOREGROUND_GREEN));
ESCAPES.put(UNDEFINED, Ansi.with(FOREGROUND_YELLOW));
ESCAPES.put(PENDING, Ansi.with(FOREGROUND_YELLOW));
ESCAPES.put(SKIPPED, Ansi.with(FOREGROUND_CYAN));
ESCAPES.put(FAILED, Ansi.with(FOREGROUND_RED));
ESCAPES.put(AMBIGUOUS, Ansi.with(FOREGROUND_RED));
}

private final PrintWriter writer;
private boolean monochrome = false;
private int width = 0;
private final OutputStream out;
private MessagesToProgressWriter writer;

public ProgressFormatter(OutputStream out) {
this.writer = createPrintWriter(out);
this.out = out;
this.writer = createBuilder().build(out);
}

private static PrintWriter createPrintWriter(OutputStream out) {
return new PrintWriter(
new OutputStreamWriter(
requireNonNull(out),
StandardCharsets.UTF_8));
private static MessagesToProgressWriter.Builder createBuilder() {
return MessagesToProgressWriter.builder()
.theme(cucumber());
}

@Override
public void setMonochrome(boolean monochrome) {
this.monochrome = monochrome;
if (monochrome) {
writer = createBuilder().theme(plain()).build(out);
}
}

@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(Envelope.class, event -> {
event.getTestStepFinished().ifPresent(this::handleTestStepFinished);
event.getTestRunFinished().ifPresent(this::handleTestRunFinished);
});
publisher.registerHandlerFor(Envelope.class, this::write);
}

private void handleTestStepFinished(TestStepFinished event) {
TestStepResultStatus status = event.getTestStepResult().getStatus();
// Prevent tearing in output when multiple threads write to System.out
StringBuilder buffer = new StringBuilder();
if (!monochrome) {
buffer.append(ESCAPES.get(status));
}
buffer.append(SYMBOLS.get(status));
if (!monochrome) {
buffer.append(RESET);
}
// Start a new line if at the end of this one
if (++width % MAX_WIDTH == 0) {
width = 0;
buffer.append(lineSeparator());
}
writer.append(buffer);
// Flush to provide immediate feedback.
writer.flush();
}

private void handleTestRunFinished(TestRunFinished testRunFinished) {
writer.println();
writer.close();
}

/**
* Represents an
* <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI escape
* code</a> in the format {@code CSI n m}.
*/
static final class Ansi {

private static final char FIRST_ESCAPE = 27;
private static final char SECOND_ESCAPE = '[';
private static final String END_SEQUENCE = "m";
private final String controlSequence;

/**
* Constructs an ANSI escape code with the given attributes.
*
* @param attributes to include.
* @return an ANSI escape code with the given attributes
*/
public static Ansi with(Ansi.Attributes... attributes) {
return new Ansi(requireNonNull(attributes));
private void write(Envelope event) {
try {
writer.write(event);
} catch (IOException e) {
throw new IllegalStateException(e);
}

private Ansi(Ansi.Attributes... attributes) {
this.controlSequence = createControlSequence(attributes);
}

private String createControlSequence(Ansi.Attributes... attributes) {
StringBuilder a = new StringBuilder(attributes.length * 5);

for (Ansi.Attributes attribute : attributes) {
a.append(FIRST_ESCAPE).append(SECOND_ESCAPE);
a.append(attribute.value);
a.append(END_SEQUENCE);
}

return a.toString();
}

@Override
public String toString() {
return controlSequence;
}

/**
* A select number of attributes from all the available <a
* href=https://en.wikipedia.org/wiki/ANSI_escape_code#Select_Graphic_Rendition_parameters>Select
* Graphic Rendition attributes</a>.
*/
enum Attributes {

// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
FOREGROUND_RED(31),
FOREGROUND_GREEN(32),
FOREGROUND_YELLOW(33),
FOREGROUND_CYAN(36),
FOREGROUND_DEFAULT(39);

private final int value;

Attributes(int index) {
this.value = index;
}
// TODO: Plugins should implement the closable interface
// and be closed by Cucumber
if (event.getTestRunFinished().isPresent()) {
writer.close();
}
}

}
Loading
Loading