Skip to content

Commit

Permalink
[JUnit/TestNG] Print snippets for undefined steps as needed
Browse files Browse the repository at this point in the history
(cherry picked from commit 93659b9)
  • Loading branch information
mpkorstanje committed Oct 5, 2019
1 parent e353575 commit 1b5db2b
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 37 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/io/cucumber/core/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public static byte run(String[] argv, ClassLoader classLoader) {

RuntimeOptions runtimeOptions = new CommandlineOptionsParser()
.parse(argv)
.addDefaultFormatterIfNotPresent()
.addDefaultSummaryPrinterIfNotPresent()
.addDefaultFormatterIfAbsent()
.addDefaultSummaryPrinterIfAbsent()
.build(systemOptions);


Expand Down
24 changes: 13 additions & 11 deletions core/src/main/java/io/cucumber/core/options/PluginOption.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package io.cucumber.core.options;

import io.cucumber.plugin.Plugin;
import io.cucumber.plugin.SummaryPrinter;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.EventListener;
import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.logging.Logger;
import io.cucumber.core.logging.LoggerFactory;
Expand All @@ -18,8 +14,13 @@
import io.cucumber.core.plugin.RerunFormatter;
import io.cucumber.core.plugin.TestNGFormatter;
import io.cucumber.core.plugin.TimelineFormatter;
import io.cucumber.core.plugin.UndefinedStepsPrinter;
import io.cucumber.core.plugin.UnusedStepsSummaryPrinter;
import io.cucumber.core.plugin.UsageFormatter;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.EventListener;
import io.cucumber.plugin.Plugin;
import io.cucumber.plugin.SummaryPrinter;

import java.util.HashMap;
import java.util.regex.Matcher;
Expand All @@ -31,19 +32,20 @@ public class PluginOption implements Options.Plugin {

private static final Pattern PLUGIN_WITH_ARGUMENT_PATTERN = Pattern.compile("([^:]+):(.*)");
private static final HashMap<String, Class<? extends Plugin>> PLUGIN_CLASSES = new HashMap<String, Class<? extends Plugin>>() {{
put("junit", JUnitFormatter.class);
put("testng", TestNGFormatter.class);
put("default_summary", DefaultSummaryPrinter.class);
put("html", HTMLFormatter.class);
put("json", JSONFormatter.class);
put("junit", JUnitFormatter.class);
put("null_summary", NullSummaryPrinter.class);
put("pretty", PrettyFormatter.class);
put("progress", ProgressFormatter.class);
put("json", JSONFormatter.class);
put("usage", UsageFormatter.class);
put("rerun", RerunFormatter.class);
put("summary", DefaultSummaryPrinter.class);
put("default_summary", DefaultSummaryPrinter.class);
put("null_summary", NullSummaryPrinter.class);
put("unused", UnusedStepsSummaryPrinter.class);
put("testng", TestNGFormatter.class);
put("timeline", TimelineFormatter.class);
put("undefined", UndefinedStepsPrinter.class);
put("unused", UnusedStepsSummaryPrinter.class);
put("usage", UsageFormatter.class);
}};

// Refuse plugins known to implement the old API
Expand Down
17 changes: 17 additions & 0 deletions core/src/main/java/io/cucumber/core/options/RuntimeOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ public static RuntimeOptions defaultOptions() {
return new RuntimeOptions();
}

void addUndefinedStepsSummaryPrinterIfAbsent() {
if (summaryPrinters.isEmpty()) {
summaryPrinters.add(PluginOption.parse("undefined"));
}
}

void addDefaultFormatterIfAbsent(){
if (formatters.isEmpty()) {
formatters.add(PluginOption.parse("progress"));
}
}
void addDefaultSummaryPrinterIfAbsent(){
if (summaryPrinters.isEmpty()) {
summaryPrinters.add(PluginOption.parse("default_summary"));
}
}

public int getCount() {
return count;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public final class RuntimeOptionsBuilder {
private PickleOrder parsedPickleOrder = null;
private Integer parsedCount = null;
private Class<? extends ObjectFactory> parsedObjectFactoryClass = null;
private boolean addDefaultSummaryPrinterIfAbsent;
private boolean addDefaultFormatterIfAbsent;
private boolean addUndefinedStepsSummaryPrinterIfAbsent;

public RuntimeOptionsBuilder addRerun(Collection<FeatureWithLines> featureWithLines) {
if (parsedRerunPaths == null) {
Expand Down Expand Up @@ -124,6 +127,18 @@ public RuntimeOptions build(RuntimeOptions runtimeOptions) {
runtimeOptions.setObjectFactoryClass(parsedObjectFactoryClass);
}

if(addDefaultFormatterIfAbsent) {
runtimeOptions.addDefaultFormatterIfAbsent();
}

if(addDefaultSummaryPrinterIfAbsent) {
runtimeOptions.addDefaultSummaryPrinterIfAbsent();
}

if(addUndefinedStepsSummaryPrinterIfAbsent) {
runtimeOptions.addUndefinedStepsSummaryPrinterIfAbsent();
}

return runtimeOptions;
}

Expand Down Expand Up @@ -185,13 +200,19 @@ public RuntimeOptionsBuilder setWip(boolean wip) {
return this;
}

public RuntimeOptionsBuilder addDefaultSummaryPrinterIfNotPresent() {
parsedPluginData.addDefaultSummaryPrinterIfNotPresent();
public RuntimeOptionsBuilder addDefaultSummaryPrinterIfAbsent() {
this.addDefaultSummaryPrinterIfAbsent = true;
return this;
}

public RuntimeOptionsBuilder addDefaultFormatterIfAbsent() {
this.addDefaultFormatterIfAbsent = true;
return this;
}

public RuntimeOptionsBuilder addDefaultFormatterIfNotPresent() {
parsedPluginData.addDefaultFormatterIfNotPresent();

public RuntimeOptionsBuilder addUndefinedStepsSummaryPrinterIfAbsent() {
this.addUndefinedStepsSummaryPrinterIfAbsent = true;
return this;
}

Expand All @@ -214,18 +235,6 @@ void addPluginName(String name, boolean isAddPlugin) {
}
}

void addDefaultSummaryPrinterIfNotPresent() {
if (summaryPrinters.names.isEmpty()) {
addPluginName("summary", false);
}
}

void addDefaultFormatterIfNotPresent() {
if (formatters.names.isEmpty()) {
addPluginName("progress", false);
}
}

void updateFormatters(List<Options.Plugin> formatter) {
this.formatters.updateNameList(formatter);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.cucumber.core.plugin;

import io.cucumber.plugin.EventListener;
import io.cucumber.plugin.StrictAware;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.SnippetsSuggestedEvent;
import io.cucumber.plugin.event.TestRunFinished;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

/**
* Work around for
*/
public class UndefinedStepsPrinter implements EventListener, StrictAware {

private final PrintStream out;
private final List<String> snippets = new ArrayList<>();
private boolean strict;

public UndefinedStepsPrinter() {
this.out = System.out;
}

@Override
public void setStrict(boolean strict) {
this.strict = strict;
}

@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(SnippetsSuggestedEvent.class, this::handleSnippetSuggestedEvent);
publisher.registerHandlerFor(TestRunFinished.class, this::handleTestRunFinishedEvent);
}

private void handleSnippetSuggestedEvent(SnippetsSuggestedEvent event) {
snippets.addAll(event.getSnippets());
}

private void handleTestRunFinishedEvent(TestRunFinished event) {
if (strict) {
return;
}

if (!snippets.isEmpty()) {
out.append("\n");
out.println("There were undefined steps. You can implement missing steps with the snippets below:");
out.println();
for (String snippet : snippets) {
out.println(snippet);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.exception.CucumberException;
import io.cucumber.plugin.Plugin;
import io.cucumber.core.plugin.PluginFactory;
import io.cucumber.core.plugin.Plugins;
import io.cucumber.core.runtime.TimeServiceEventBus;
import io.cucumber.core.snippets.SnippetType;
import io.cucumber.plugin.Plugin;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;

Expand Down Expand Up @@ -50,8 +50,8 @@ void create_non_strict() {
void create_without_options() {
RuntimeOptions runtimeOptions = parser()
.parse(WithoutOptions.class)
.addDefaultSummaryPrinterIfNotPresent()
.addDefaultFormatterIfNotPresent()
.addDefaultSummaryPrinterIfAbsent()
.addDefaultFormatterIfAbsent()
.build();

assertAll("Checking RuntimeOptions",
Expand Down Expand Up @@ -80,8 +80,8 @@ void create_without_options_with_base_class_without_options() {
Class<?> subClassWithMonoChromeTrueClass = WithoutOptionsWithBaseClassWithoutOptions.class;
RuntimeOptions runtimeOptions = parser()
.parse(subClassWithMonoChromeTrueClass)
.addDefaultFormatterIfNotPresent()
.addDefaultSummaryPrinterIfNotPresent()
.addDefaultFormatterIfAbsent()
.addDefaultSummaryPrinterIfAbsent()
.build();
Plugins plugins = new Plugins(new PluginFactory(), runtimeOptions);
plugins.setEventBusOnEventListenerPlugins(new TimeServiceEventBus(Clock.systemUTC()));
Expand Down Expand Up @@ -140,7 +140,7 @@ private String getRegexpPattern(Object pattern) {
void create_default_summary_printer_when_no_summary_printer_plugin_is_defined() {
RuntimeOptions runtimeOptions = parser()
.parse(ClassWithNoSummaryPrinterPlugin.class)
.addDefaultSummaryPrinterIfNotPresent()
.addDefaultSummaryPrinterIfAbsent()
.build();
Plugins plugins = new Plugins(new PluginFactory(), runtimeOptions);
plugins.setEventBusOnEventListenerPlugins(new TimeServiceEventBus(Clock.systemUTC()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void creates_html_formatter() {
void creates_progress_formatter_as_default() {
RuntimeOptions options = new CommandlineOptionsParser()
.parse()
.addDefaultFormatterIfNotPresent()
.addDefaultFormatterIfAbsent()
.build();
Plugins plugins = new Plugins(new PluginFactory(), options);
plugins.setEventBusOnEventListenerPlugins(new TimeServiceEventBus(Clock.systemUTC()));
Expand All @@ -177,7 +177,7 @@ void creates_progress_formatter_as_default() {
void creates_default_summary_printer_when_no_summary_printer_plugin_is_specified() {
RuntimeOptions options = new CommandlineOptionsParser()
.parse("--plugin", "pretty")
.addDefaultSummaryPrinterIfNotPresent()
.addDefaultSummaryPrinterIfAbsent()
.build();
Plugins plugins = new Plugins(new PluginFactory(), options);
plugins.setEventBusOnEventListenerPlugins(new TimeServiceEventBus(Clock.systemUTC()));
Expand Down
1 change: 1 addition & 0 deletions junit/src/main/java/io/cucumber/junit/Cucumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public Cucumber(Class clazz) throws InitializationError {

RuntimeOptions runtimeOptions = new CucumberPropertiesParser()
.parse(CucumberProperties.fromSystemProperties())
.addUndefinedStepsSummaryPrinterIfAbsent()
.build(environmentOptions);

// Next parse the junit options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public TestNGCucumberRunner(Class clazz) {

runtimeOptions = new CucumberPropertiesParser()
.parse(CucumberProperties.fromSystemProperties())
.addUndefinedStepsSummaryPrinterIfAbsent()
.build(environmentOptions);

ClassLoader classLoader = clazz.getClassLoader();
Expand Down

0 comments on commit 1b5db2b

Please sign in to comment.