diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d215f332..691e43bed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [Core] Emit Suggestion message ([#3073](https://github.com/cucumber/cucumber-jvm/pull/3073) M.P. Korstanje) + ### Fixed - [Core] Emit StepMatchArgumentsList for ambiguous steps ([#3066](https://github.com/cucumber/cucumber-jvm/pull/3066) M.P. Korstanje) diff --git a/cucumber-core/src/main/java/io/cucumber/core/backend/Snippet.java b/cucumber-core/src/main/java/io/cucumber/core/backend/Snippet.java index ae0c00ab4e..88392e4245 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/backend/Snippet.java +++ b/cucumber-core/src/main/java/io/cucumber/core/backend/Snippet.java @@ -5,10 +5,21 @@ import java.lang.reflect.Type; import java.text.MessageFormat; import java.util.Map; +import java.util.Optional; @API(status = API.Status.STABLE) public interface Snippet { + /** + * The language of the generated snippet. + * + * @see io.cucumber.messages.types.Snippet#getLanguage() + * @return the language of the generated snippet. + */ + default Optional language() { + return Optional.empty(); + } + /** * @return a {@link java.text.MessageFormat} template used to generate a * snippet. The template can access the following variables: diff --git a/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java b/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java index 80468d2703..30ffe98c36 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java +++ b/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java @@ -13,8 +13,9 @@ import io.cucumber.core.logging.LoggerFactory; import io.cucumber.core.snippets.SnippetGenerator; import io.cucumber.core.stepexpression.StepTypeRegistry; +import io.cucumber.messages.types.Envelope; +import io.cucumber.messages.types.Snippet; import io.cucumber.plugin.event.HookType; -import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.SnippetsSuggestedEvent; import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; @@ -26,11 +27,11 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; import static io.cucumber.core.exception.ExceptionUtils.throwAsUncheckedException; import static io.cucumber.core.runner.StackManipulation.removeFrameworkFrames; import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; public final class Runner { @@ -128,7 +129,7 @@ private List createSnippetGeneratorsForPickle(StepTypeRegistry .map(Backend::getSnippet) .filter(Objects::nonNull) .map(s -> new SnippetGenerator(s, stepTypeRegistry.parameterTypeRegistry())) - .collect(Collectors.toList()); + .collect(toList()); } private void buildBackendWorlds() { @@ -193,16 +194,28 @@ private PickleStepDefinitionMatch matchStepToStepDefinition(Pickle pickle, Step } private void emitSnippetSuggestedEvent(Pickle pickle, Step step) { - List snippets = generateSnippetsForStep(step); + List snippets = generateSnippetsForStep(step); if (snippets.isEmpty()) { return; } - Suggestion suggestion = new Suggestion(step.getText(), snippets); - Location scenarioLocation = pickle.getLocation(); - Location stepLocation = step.getLocation(); - SnippetsSuggestedEvent event = new SnippetsSuggestedEvent(bus.getInstant(), pickle.getUri(), scenarioLocation, - stepLocation, suggestion); - bus.send(event); + + bus.send(new SnippetsSuggestedEvent( + bus.getInstant(), + pickle.getUri(), + pickle.getLocation(), + step.getLocation(), + new Suggestion( + step.getText(), + snippets.stream() + .map(Snippet::getCode) + .collect(toList())))); + + bus.send( + Envelope.of( + new io.cucumber.messages.types.Suggestion( + bus.generateId().toString(), + step.getId(), + snippets))); } private List createAfterStepHooks(List tags) { @@ -219,16 +232,18 @@ private List createTestStepsForHooks( return hooks.stream() .filter(hook -> hook.matches(tags)) .map(hook -> new HookTestStep(bus.generateId(), hookType, new HookDefinitionMatch(hook))) - .collect(Collectors.toList()); - } - - private List generateSnippetsForStep(Step step) { - List snippets = new ArrayList<>(); - for (SnippetGenerator snippetGenerator : snippetGenerators) { - List snippet = snippetGenerator.getSnippet(step, runnerOptions.getSnippetType()); - snippets.addAll(snippet); - } - return snippets; + .collect(toList()); + } + + private List generateSnippetsForStep(Step step) { + return snippetGenerators.stream() + .flatMap(generator -> { + String language = generator.getLanguage().orElse("unknown"); + return generator.getSnippet(step, runnerOptions.getSnippetType()) + .stream() + .map(code -> new Snippet(language, code)); + }) + .collect(toList()); } } diff --git a/cucumber-core/src/main/java/io/cucumber/core/snippets/SnippetGenerator.java b/cucumber-core/src/main/java/io/cucumber/core/snippets/SnippetGenerator.java index 7e49f6373c..ec2a1fc51f 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/snippets/SnippetGenerator.java +++ b/cucumber-core/src/main/java/io/cucumber/core/snippets/SnippetGenerator.java @@ -15,6 +15,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -37,6 +38,10 @@ public SnippetGenerator(Snippet snippet, ParameterTypeRegistry parameterTypeRegi this.generator = new CucumberExpressionGenerator(parameterTypeRegistry); } + public Optional getLanguage() { + return snippet.language(); + } + public List getSnippet(Step step, SnippetType snippetType) { List generatedExpressions = generator.generateExpressions(step.getText()); IdentifierGenerator functionNameGenerator = new IdentifierGenerator(snippetType.joiner()); diff --git a/cucumber-core/src/test/java/io/cucumber/core/snippets/TestSnippet.java b/cucumber-core/src/test/java/io/cucumber/core/snippets/TestSnippet.java index e224a735ce..b1e34193a2 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/snippets/TestSnippet.java +++ b/cucumber-core/src/test/java/io/cucumber/core/snippets/TestSnippet.java @@ -5,9 +5,15 @@ import java.lang.reflect.Type; import java.text.MessageFormat; import java.util.Map; +import java.util.Optional; public class TestSnippet implements Snippet { + @Override + public Optional language() { + return Optional.of("test"); + } + private int i; @Override diff --git a/cucumber-java/src/main/java/io/cucumber/java/AbstractJavaSnippet.java b/cucumber-java/src/main/java/io/cucumber/java/AbstractJavaSnippet.java index e330f501cf..0fbc2b1bea 100644 --- a/cucumber-java/src/main/java/io/cucumber/java/AbstractJavaSnippet.java +++ b/cucumber-java/src/main/java/io/cucumber/java/AbstractJavaSnippet.java @@ -5,11 +5,17 @@ import java.lang.reflect.Type; import java.util.Map; +import java.util.Optional; import static java.util.stream.Collectors.joining; abstract class AbstractJavaSnippet implements Snippet { + @Override + public Optional language() { + return Optional.of("java"); + } + @Override public final String tableHint() { return "" +