From cace210df2e51d7dd64bfbb4be7556cd8fc987d3 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 19 Apr 2022 12:16:24 +0200 Subject: [PATCH] [Core] Use null safe-messages (#2497) With https://github.com/cucumber/common/pull/1879 `messages` now uses `Optional` for optional types avoiding some unexpected null references. This resulted in some updating of `gherkin` and `html-formatter`. Additionally with this change the dependency on Jackson has been removed from `messages`. However we still have to serialize the message objects into json. So for now Jackson is shaded into `core` instead. And eventually we'll be able to spin this out to it's own module. --- .revapi/api-changes.json | 57 ++++++++++ CHANGELOG.md | 9 +- bom/pom.xml | 3 +- core/pom.xml | 106 +++++++++--------- .../options/CommandlineOptionsParser.java | 13 ++- .../cucumber/core/plugin/HtmlFormatter.java | 7 +- .../java/io/cucumber/core/plugin/Jackson.java | 27 +++++ .../cucumber/core/plugin/JsonFormatter.java | 3 +- .../core/plugin/MessageFormatter.java | 5 +- .../core/plugin/TestSourcesModel.java | 73 ++++++------ .../core/plugin/TimelineFormatter.java | 8 +- .../cucumber/core/plugin/UsageFormatter.java | 3 +- .../io/cucumber/core/runner/CachingGlue.java | 84 +++++++------- .../io/cucumber/core/runner/TestCase.java | 52 ++++----- .../cucumber/core/runner/TestCaseState.java | 63 +++++------ .../io/cucumber/core/runner/TestStep.java | 18 ++- .../core/runner/TestStepResultStatus.java | 29 ----- .../runner/TestStepResultStatusMapper.java | 40 +++++++ .../runtime/CucumberExecutionContext.java | 12 +- .../stepexpression/StepExpressionFactory.java | 6 +- .../options/CommandlineOptionsParserTest.java | 13 ++- .../CucumberOptionsAnnotationParserTest.java | 1 + .../core/plugin/HtmlFormatterTest.java | 80 ++++++------- .../core/plugin/MessageFormatterTest.java | 18 +-- .../core/plugin/PluginFactoryTest.java | 1 + .../core/plugin/TimelineFormatterTest.java | 10 +- .../core/runner/TestCaseStateTest.java | 28 ++--- .../io/cucumber/core/runtime/RuntimeTest.java | 5 +- ...r.properties => junit-platform.properties} | 0 gherkin-messages/pom.xml | 48 -------- .../core/gherkin/messages/CucumberQuery.java | 47 ++------ .../GherkinMessagesDocStringArgument.java | 2 +- .../messages/GherkinMessagesFeature.java | 8 +- .../GherkinMessagesFeatureParser.java | 96 ++++++++-------- .../messages/GherkinMessagesLocation.java | 2 +- .../gherkin/messages/GherkinMessagesRule.java | 8 +- .../gherkin/messages/GherkinMessagesStep.java | 28 +++-- ...r.properties => junit-platform.properties} | 0 ...r.properties => junit-platform.properties} | 0 ...r.properties => junit-platform.properties} | 0 ...r.properties => junit-platform.properties} | 0 pom.xml | 4 +- .../test/resources/junit-platform.properties | 1 + 43 files changed, 511 insertions(+), 507 deletions(-) create mode 100644 core/src/main/java/io/cucumber/core/plugin/Jackson.java delete mode 100644 core/src/main/java/io/cucumber/core/runner/TestStepResultStatus.java create mode 100644 core/src/main/java/io/cucumber/core/runner/TestStepResultStatusMapper.java rename deltaspike/src/test/resources/{cucumber.properties => junit-platform.properties} (100%) rename java/src/test/resources/{cucumber.properties => junit-platform.properties} (100%) rename java8/src/test/resources/{cucumber.properties => junit-platform.properties} (100%) rename kotlin-java8/src/test/resources/{cucumber.properties => junit-platform.properties} (100%) rename openejb/src/test/resources/{cucumber.properties => junit-platform.properties} (100%) create mode 100644 spring/src/test/resources/junit-platform.properties diff --git a/.revapi/api-changes.json b/.revapi/api-changes.json index f3ea0594b8..7e926483c9 100644 --- a/.revapi/api-changes.json +++ b/.revapi/api-changes.json @@ -106,6 +106,63 @@ "old": "class io.cucumber.gherkin.internal.com.eclipsesource.json.JsonWriter", "new": "class io.cucumber.gherkin.internal.com.eclipsesource.json.JsonWriter", "justification": "Internal API" + }, + { + "regex": true, + "code": "java.method.returnTypeChanged", + "old": ".* io\\.cucumber\\.messages\\..*", + "new": ".* io\\.cucumber\\.messages\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.method.removed", + "old": ".* io\\.cucumber\\.messages\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.nowFinal", + "old": ".* io\\.cucumber\\.messages\\..*", + "new": ".* io\\.cucumber\\.messages\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.method.numberOfParametersChanged", + "old": ".* io\\.cucumber\\.messages\\..*", + "new": ".* io\\.cucumber\\.messages\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.removed", + "old": ".* io\\.cucumber\\.messages\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.removed", + "old": ".* io\\.cucumber\\.core\\.gherkin\\.messages\\.internal\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.removed", + "old": ".* io\\.cucumber\\.gherkin\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.removed", + "old": ".* io\\.cucumber\\.gherkin\\.internal\\..*", + "justification": "Internal API" + }, + { + "regex": true, + "code": "java.class.nonPublicPartOfAPI", + "new": ".* io\\.cucumber\\.core\\.internal\\..*", + "justification": "Internal API" } ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index a2169426b0..7230dfe687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * [JUnit Platform] Support `cucumber.features` property ([#2498](https://github.com/cucumber/cucumber-jvm/pull/2498) M.P. Korstanje) ### Changed +* [Core] Use null-safe messages ([#2497](https://github.com/cucumber/cucumber-jvm/pull/2497) M.P. Korstanje) + * Update dependency io.cucumber:html-formatter to v19.1 + - Removed work around for 'Uncaught TypeError: e.git is undefined' + * Update dependency io.cucumber:messages to v18 + * Update dependency io.cucumber:gherkin to v23 + * Moved shaded jackson from `messages` to `core`. + * Update dependency io.cucumber:ci-environment to v9 ([#2475](https://github.com/cucumber/cucumber-jvm/pull/2475) M.P. Korstanje) -* Update dependency io.cucumber:html-formatter to v18 ([#2476](https://github.com/cucumber/cucumber-jvm/pull/2476) M.P. Korstanje) - - Removed work around for 'Uncaught TypeError: e.git is undefined' * Update dependency com.google.inject:guice to v5.1.0 ([#2473](https://github.com/cucumber/cucumber-jvm/pull/2473) M.P. Korstanje) * Update dependency org.testng:testng to v7.5 ([#2457](https://github.com/cucumber/cucumber-jvm/pull/2457) M.P. Korstanje) diff --git a/bom/pom.xml b/bom/pom.xml index 03b0d20656..697c1a4566 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -14,8 +14,7 @@ 9.0.4 15.0.2 - 4.1.0 - 18.0.0 + 19.1.0 4.1.0 diff --git a/core/pom.xml b/core/pom.xml index 4441f35f52..9873194836 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,7 +15,7 @@ io.cucumber.core 1.1.2 - 2.13.2.2 + 2.13.2.20220328 1.14.3 5.8.2 2.9.0 @@ -42,14 +42,17 @@ pom import + + com.fasterxml.jackson + jackson-bom + ${jackson-databind.version} + pom + import + - - io.cucumber - gherkin - io.cucumber cucumber-gherkin @@ -95,6 +98,14 @@ apiguardian-api ${apiguardian-api.version} + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + org.xmlunit @@ -136,42 +147,12 @@ vertx-web ${vertx.version} test - - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - io.vertx vertx-junit5 ${vertx.version} test - - - - org.junit.jupiter - junit-jupiter-params - - - org.reactivestreams - reactive-streams - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - @@ -204,13 +185,6 @@ - - com.fasterxml.jackson.core - jackson-databind - ${jackson-databind.version} - test - - @@ -267,21 +241,51 @@ - io.cucumber:gherkin + com.fasterxml.jackson.core:jackson-databind + com.fasterxml.jackson.core:jackson-core + com.fasterxml.jackson.core:jackson-annotations + com.fasterxml.jackson.datatype:jackson-datatype-jdk8 - - - - - - - + + + com.fasterxml + io.cucumber.core.internal.com.fasterxml + + - io.cucumber:gherkin + com.fasterxml.jackson.core:jackson-databind + + **/module-info.class + META-INF/MANIFEST.MF + META-INF/LICENSE + META-INF/NOTICE + + + + com.fasterxml.jackson.core:jackson-core + + **/module-info.class + META-INF/MANIFEST.MF + META-INF/LICENSE + META-INF/NOTICE + + + + com.fasterxml.jackson.core:jackson-annotations + + **/module-info.class + META-INF/MANIFEST.MF + META-INF/LICENSE + + + + com.fasterxml.jackson.datatype:jackson-datatype-jdk8 + **/module-info.class META-INF/MANIFEST.MF + META-INF/LICENSE diff --git a/core/src/main/java/io/cucumber/core/options/CommandlineOptionsParser.java b/core/src/main/java/io/cucumber/core/options/CommandlineOptionsParser.java index 8cb7fb150a..80e628e3f9 100644 --- a/core/src/main/java/io/cucumber/core/options/CommandlineOptionsParser.java +++ b/core/src/main/java/io/cucumber/core/options/CommandlineOptionsParser.java @@ -6,9 +6,9 @@ import io.cucumber.core.logging.Logger; import io.cucumber.core.logging.LoggerFactory; import io.cucumber.datatable.DataTable; +import io.cucumber.datatable.DataTableFormatter; import io.cucumber.gherkin.GherkinDialect; import io.cucumber.gherkin.GherkinDialectProvider; -import io.cucumber.gherkin.IGherkinDialectProvider; import io.cucumber.tagexpressions.TagExpressionParser; import java.io.BufferedReader; @@ -198,7 +198,7 @@ private String removeArgFor(String arg, List args) { } private byte printI18n(String language) { - IGherkinDialectProvider dialectProvider = new GherkinDialectProvider(); + GherkinDialectProvider dialectProvider = new GherkinDialectProvider(); List languages = dialectProvider.getLanguages(); if (language.equalsIgnoreCase("help")) { @@ -233,7 +233,7 @@ private String loadUsageText() { BufferedReader br = new BufferedReader(new InputStreamReader(usageResourceStream, UTF_8))) { return br.lines().collect(joining(System.lineSeparator())); } catch (Exception e) { - return "Could not load usage text: " + e.toString(); + return "Could not load usage text: " + e; } } @@ -271,8 +271,11 @@ private byte printKeywordsFor(GherkinDialect dialect) { addCodeKeywordRow(table, "then", dialect.getThenKeywords()); addCodeKeywordRow(table, "and", dialect.getAndKeywords()); addCodeKeywordRow(table, "but", dialect.getButKeywords()); - DataTable.create(table).print(builder); - out.println(builder.toString()); + DataTableFormatter.builder() + .prefixRow(" ") + .build() + .formatTo(DataTable.create(table), builder); + out.println(builder); return 0x0; } diff --git a/core/src/main/java/io/cucumber/core/plugin/HtmlFormatter.java b/core/src/main/java/io/cucumber/core/plugin/HtmlFormatter.java index edc1e6cc21..d6feb5c6f1 100644 --- a/core/src/main/java/io/cucumber/core/plugin/HtmlFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/HtmlFormatter.java @@ -14,7 +14,7 @@ public final class HtmlFormatter implements ConcurrentEventListener { @SuppressWarnings("WeakerAccess") // Used by PluginFactory public HtmlFormatter(OutputStream out) throws IOException { - this.writer = new MessagesToHtmlWriter(new UTF8OutputStreamWriter(out)); + this.writer = new MessagesToHtmlWriter(out, Jackson.OBJECT_MAPPER::writeValue); } @Override @@ -25,7 +25,8 @@ public void setEventPublisher(EventPublisher publisher) { private void write(Envelope event) { // Workaround to reduce the size of the report // See: https://github.com/cucumber/cucumber/issues/1232 - if (event.getStepDefinition() != null || event.getHook() != null || event.getParameterType() != null) { + if (event.getStepDefinition().isPresent() || event.getHook().isPresent() + || event.getParameterType().isPresent()) { return; } @@ -37,7 +38,7 @@ private void write(Envelope event) { // TODO: Plugins should implement the closable interface // and be closed by Cucumber - if (event.getTestRunFinished() != null) { + if (event.getTestRunFinished().isPresent()) { try { writer.close(); } catch (IOException e) { diff --git a/core/src/main/java/io/cucumber/core/plugin/Jackson.java b/core/src/main/java/io/cucumber/core/plugin/Jackson.java new file mode 100644 index 0000000000..9ed84dbcf1 --- /dev/null +++ b/core/src/main/java/io/cucumber/core/plugin/Jackson.java @@ -0,0 +1,27 @@ +package io.cucumber.core.plugin; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.cfg.ConstructorDetector; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; + +final class Jackson { + public static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .serializationInclusion(Include.NON_ABSENT) + .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED) + .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING) + .enable(DeserializationFeature.USE_LONG_FOR_INTS) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET) + .build(); + + private Jackson() { + } + +} diff --git a/core/src/main/java/io/cucumber/core/plugin/JsonFormatter.java b/core/src/main/java/io/cucumber/core/plugin/JsonFormatter.java index 6b89480884..f36526e4ea 100644 --- a/core/src/main/java/io/cucumber/core/plugin/JsonFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/JsonFormatter.java @@ -1,6 +1,5 @@ package io.cucumber.core.plugin; -import io.cucumber.messages.JSON; import io.cucumber.messages.types.Background; import io.cucumber.messages.types.Feature; import io.cucumber.messages.types.Scenario; @@ -145,7 +144,7 @@ private void finishReport(TestRunFinished event) { } try { - JSON.writeValue(writer, featureMaps); + Jackson.OBJECT_MAPPER.writeValue(writer, featureMaps); writer.close(); } catch (IOException e) { throw new RuntimeException(e); diff --git a/core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java b/core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java index ff06db919e..865add861e 100644 --- a/core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java @@ -1,6 +1,5 @@ package io.cucumber.core.plugin; -import io.cucumber.messages.JSON; import io.cucumber.messages.types.Envelope; import io.cucumber.plugin.ConcurrentEventListener; import io.cucumber.plugin.event.EventPublisher; @@ -24,10 +23,10 @@ public void setEventPublisher(EventPublisher publisher) { private void writeMessage(Envelope envelope) { try { - JSON.writeValue(writer, envelope); + Jackson.OBJECT_MAPPER.writeValue(writer, envelope); writer.write("\n"); writer.flush(); - if (envelope.getTestRunFinished() != null) { + if (envelope.getTestRunFinished().isPresent()) { writer.close(); } } catch (IOException e) { diff --git a/core/src/main/java/io/cucumber/core/plugin/TestSourcesModel.java b/core/src/main/java/io/cucumber/core/plugin/TestSourcesModel.java index 9329c7dc2f..4eadb552d3 100644 --- a/core/src/main/java/io/cucumber/core/plugin/TestSourcesModel.java +++ b/core/src/main/java/io/cucumber/core/plugin/TestSourcesModel.java @@ -1,6 +1,6 @@ package io.cucumber.core.plugin; -import io.cucumber.gherkin.Gherkin; +import io.cucumber.gherkin.GherkinParser; import io.cucumber.messages.types.Background; import io.cucumber.messages.types.Envelope; import io.cucumber.messages.types.Examples; @@ -9,6 +9,8 @@ import io.cucumber.messages.types.GherkinDocument; import io.cucumber.messages.types.RuleChild; import io.cucumber.messages.types.Scenario; +import io.cucumber.messages.types.Source; +import io.cucumber.messages.types.SourceMediaType; import io.cucumber.messages.types.Step; import io.cucumber.messages.types.TableRow; import io.cucumber.plugin.event.TestSourceRead; @@ -17,15 +19,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.UUID; - -import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope; -import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; +import java.util.stream.Stream; final class TestSourcesModel { @@ -96,7 +92,7 @@ Feature getFeature(URI path) { parseGherkinSource(path); } if (pathToAstMap.containsKey(path)) { - return pathToAstMap.get(path).getFeature(); + return pathToAstMap.get(path).getFeature().orElse(null); } return null; } @@ -107,26 +103,26 @@ private void parseGherkinSource(URI path) { } String source = pathToReadEventMap.get(path).getSource(); - List sources = singletonList( - makeSourceEnvelope(source, path.toString())); + GherkinParser parser = GherkinParser.builder() + .build(); - List envelopes = Gherkin.fromSources( - sources, - true, - true, - true, - () -> String.valueOf(UUID.randomUUID())).collect(toList()); + Stream envelopes = parser.parse( + Envelope.of(new Source(path.toString(), source, SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN))); - GherkinDocument gherkinDocument = envelopes.stream() + // TODO: What about empty gherkin docs? + GherkinDocument gherkinDocument = envelopes .map(Envelope::getGherkinDocument) - .filter(Objects::nonNull) + .filter(Optional::isPresent) + .map(Optional::get) .findFirst() .orElse(null); pathToAstMap.put(path, gherkinDocument); Map nodeMap = new HashMap<>(); - AstNode currentParent = new AstNode(gherkinDocument.getFeature(), null); - for (FeatureChild child : gherkinDocument.getFeature().getChildren()) { + // TODO: What about gherkin docs with no features? + Feature feature = gherkinDocument.getFeature().get(); + AstNode currentParent = new AstNode(feature, null); + for (FeatureChild child : feature.getChildren()) { processFeatureDefinition(nodeMap, child, currentParent); } pathToNodeMap.put(path, nodeMap); @@ -134,17 +130,13 @@ private void parseGherkinSource(URI path) { } private void processFeatureDefinition(Map nodeMap, FeatureChild child, AstNode currentParent) { - if (child.getBackground() != null) { - processBackgroundDefinition(nodeMap, child.getBackground(), currentParent); - } else if (child.getScenario() != null) { - processScenarioDefinition(nodeMap, child.getScenario(), currentParent); - } else if (child.getRule() != null) { - AstNode childNode = new AstNode(child.getRule(), currentParent); - nodeMap.put(child.getRule().getLocation().getLine(), childNode); - for (RuleChild ruleChild : child.getRule().getChildren()) { - processRuleDefinition(nodeMap, ruleChild, childNode); - } - } + child.getBackground().ifPresent(background -> processBackgroundDefinition(nodeMap, background, currentParent)); + child.getScenario().ifPresent(scenario -> processScenarioDefinition(nodeMap, scenario, currentParent)); + child.getRule().ifPresent(rule -> { + AstNode childNode = new AstNode(rule, currentParent); + nodeMap.put(rule.getLocation().getLine(), childNode); + rule.getChildren().forEach(ruleChild -> processRuleDefinition(nodeMap, ruleChild, childNode)); + }); } private void processBackgroundDefinition( @@ -169,11 +161,8 @@ private void processScenarioDefinition(Map nodeMap, Scenario chil } private void processRuleDefinition(Map nodeMap, RuleChild child, AstNode currentParent) { - if (child.getBackground() != null) { - processBackgroundDefinition(nodeMap, child.getBackground(), currentParent); - } else if (child.getScenario() != null) { - processScenarioDefinition(nodeMap, child.getScenario(), currentParent); - } + child.getBackground().ifPresent(background -> processBackgroundDefinition(nodeMap, background, currentParent)); + child.getScenario().ifPresent(scenario -> processScenarioDefinition(nodeMap, scenario, currentParent)); } private void processScenarioOutlineExamples( @@ -181,7 +170,8 @@ private void processScenarioOutlineExamples( ) { for (Examples examples : scenarioOutline.getExamples()) { AstNode examplesNode = new AstNode(examples, parent); - TableRow headerRow = examples.getTableHeader(); + // TODO: Can tables without headers even exist? + TableRow headerRow = examples.getTableHeader().get(); AstNode headerNode = new AstNode(headerRow, examplesNode); nodeMap.put(headerRow.getLocation().getLine(), headerNode); for (int i = 0; i < examples.getTableBody().size(); ++i) { @@ -198,7 +188,7 @@ AstNode getAstNode(URI path, int line) { parseGherkinSource(path); } if (pathToNodeMap.containsKey(path)) { - return pathToNodeMap.get(path).get(Long.valueOf(line)); + return pathToNodeMap.get(path).get((long) line); } return null; } @@ -208,7 +198,7 @@ boolean hasBackground(URI path, int line) { parseGherkinSource(path); } if (pathToNodeMap.containsKey(path)) { - AstNode astNode = pathToNodeMap.get(path).get(Long.valueOf(line)); + AstNode astNode = pathToNodeMap.get(path).get((long) line); return getBackgroundForTestCase(astNode).isPresent(); } return false; @@ -219,7 +209,8 @@ static Optional getBackgroundForTestCase(AstNode astNode) { return feature.getChildren() .stream() .map(FeatureChild::getBackground) - .filter(Objects::nonNull) + .filter(Optional::isPresent) + .map(Optional::get) .findFirst(); } diff --git a/core/src/main/java/io/cucumber/core/plugin/TimelineFormatter.java b/core/src/main/java/io/cucumber/core/plugin/TimelineFormatter.java index cec5964853..5fa0943aff 100644 --- a/core/src/main/java/io/cucumber/core/plugin/TimelineFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/TimelineFormatter.java @@ -1,10 +1,10 @@ package io.cucumber.core.plugin; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonGenerator.Feature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import io.cucumber.core.exception.CucumberException; -import io.cucumber.messages.internal.com.fasterxml.jackson.annotation.JsonInclude.Include; -import io.cucumber.messages.internal.com.fasterxml.jackson.core.JsonGenerator.Feature; -import io.cucumber.messages.internal.com.fasterxml.jackson.databind.ObjectMapper; -import io.cucumber.messages.internal.com.fasterxml.jackson.databind.SerializationFeature; import io.cucumber.plugin.ConcurrentEventListener; import io.cucumber.plugin.event.EventPublisher; import io.cucumber.plugin.event.Location; diff --git a/core/src/main/java/io/cucumber/core/plugin/UsageFormatter.java b/core/src/main/java/io/cucumber/core/plugin/UsageFormatter.java index 5b2e7257ad..877e31b368 100644 --- a/core/src/main/java/io/cucumber/core/plugin/UsageFormatter.java +++ b/core/src/main/java/io/cucumber/core/plugin/UsageFormatter.java @@ -1,6 +1,5 @@ package io.cucumber.core.plugin; -import io.cucumber.messages.JSON; import io.cucumber.plugin.ConcurrentEventListener; import io.cucumber.plugin.Plugin; import io.cucumber.plugin.event.EventPublisher; @@ -63,7 +62,7 @@ void finishReport() { } try { - JSON.writeValue(out, stepDefContainers); + Jackson.OBJECT_MAPPER.writeValue(out, stepDefContainers); out.close(); } catch (IOException e) { throw new RuntimeException(e); diff --git a/core/src/main/java/io/cucumber/core/runner/CachingGlue.java b/core/src/main/java/io/cucumber/core/runner/CachingGlue.java index 3406425ebd..27c158d1fd 100644 --- a/core/src/main/java/io/cucumber/core/runner/CachingGlue.java +++ b/core/src/main/java/io/cucumber/core/runner/CachingGlue.java @@ -33,6 +33,7 @@ import io.cucumber.messages.types.Location; import io.cucumber.messages.types.SourceReference; import io.cucumber.messages.types.StepDefinitionPattern; +import io.cucumber.messages.types.StepDefinitionPatternType; import io.cucumber.plugin.event.StepDefinedEvent; import java.net.URI; @@ -285,28 +286,24 @@ void prepareGlue(StepTypeRegistry stepTypeRegistry) throws DuplicateStepDefiniti } private void emitParameterTypeDefined(ParameterType parameterType) { - io.cucumber.messages.types.ParameterType messagesParameterType = new io.cucumber.messages.types.ParameterType(); - messagesParameterType.setId(bus.generateId().toString()); - messagesParameterType.setName(parameterType.getName()); - messagesParameterType.setRegularExpressions(parameterType.getRegexps()); - messagesParameterType.setPreferForRegularExpressionMatch(parameterType.preferForRegexpMatch()); - messagesParameterType.setUseForSnippets(parameterType.useForSnippets()); - - Envelope envelope = new Envelope(); - envelope.setParameterType(messagesParameterType); - bus.send(envelope); + io.cucumber.messages.types.ParameterType messagesParameterType = new io.cucumber.messages.types.ParameterType( + parameterType.getName(), + parameterType.getRegexps(), + parameterType.preferForRegexpMatch(), + parameterType.useForSnippets(), + bus.generateId().toString()); + bus.send(Envelope.of(messagesParameterType)); } private void emitHook(CoreHookDefinition coreHook) { - Hook messagesHook = new Hook(); - messagesHook.setId(coreHook.getId().toString()); - messagesHook.setTagExpression(coreHook.getTagExpression()); - coreHook.getDefinitionLocation() - .ifPresent(reference -> messagesHook.setSourceReference(createSourceReference(reference))); - - Envelope envelope = new Envelope(); - envelope.setHook(messagesHook); - bus.send(envelope); + Hook messagesHook = new Hook( + coreHook.getId().toString(), + null, + coreHook.getDefinitionLocation() + .map(this::createSourceReference) + .orElseGet(this::emptySourceReference), + coreHook.getTagExpression()); + bus.send(Envelope.of(messagesHook)); } private void emitStepDefined(CoreStepDefinition coreStepDefinition) { @@ -316,24 +313,21 @@ private void emitStepDefined(CoreStepDefinition coreStepDefinition) { coreStepDefinition.getStepDefinition().getLocation(), coreStepDefinition.getExpression().getSource()))); - io.cucumber.messages.types.StepDefinition messagesStepDefinition = new io.cucumber.messages.types.StepDefinition(); - messagesStepDefinition.setId(coreStepDefinition.getId().toString()); - messagesStepDefinition.setPattern(new StepDefinitionPattern( - coreStepDefinition.getExpression().getSource(), - getExpressionType(coreStepDefinition))); - coreStepDefinition.getDefinitionLocation() - .ifPresent(reference -> messagesStepDefinition.setSourceReference(createSourceReference(reference))); - - Envelope envelope = new Envelope(); - envelope.setStepDefinition(messagesStepDefinition); - bus.send(envelope); + io.cucumber.messages.types.StepDefinition messagesStepDefinition = new io.cucumber.messages.types.StepDefinition( + coreStepDefinition.getId().toString(), + new StepDefinitionPattern( + coreStepDefinition.getExpression().getSource(), + getExpressionType(coreStepDefinition)), + coreStepDefinition.getDefinitionLocation() + .map(this::createSourceReference) + .orElseGet(this::emptySourceReference)); + bus.send(Envelope.of(messagesStepDefinition)); } private SourceReference createSourceReference(io.cucumber.core.backend.SourceReference reference) { - SourceReference sourceReference = new SourceReference(); if (reference instanceof JavaMethodReference) { JavaMethodReference methodReference = (JavaMethodReference) reference; - sourceReference.setJavaMethod(new JavaMethod( + return SourceReference.of(new JavaMethod( methodReference.className(), methodReference.methodName(), methodReference.methodParameterTypes())); @@ -341,22 +335,28 @@ private SourceReference createSourceReference(io.cucumber.core.backend.SourceRef if (reference instanceof StackTraceElementReference) { StackTraceElementReference stackReference = (StackTraceElementReference) reference; - JavaStackTraceElement stackTraceElementBuilder = new JavaStackTraceElement(); - stackTraceElementBuilder.setClassName(stackReference.className()); - stackTraceElementBuilder.setMethodName(stackReference.methodName()); - stackReference.fileName().ifPresent(stackTraceElementBuilder::setFileName); - sourceReference.setJavaStackTraceElement(stackTraceElementBuilder); - sourceReference.setLocation(new Location(Long.valueOf(stackReference.lineNumber()), null)); + JavaStackTraceElement stackTraceElement = new JavaStackTraceElement( + stackReference.className(), + // TODO: Fix json schema. Stacktrace elements need not have a + // source file + stackReference.fileName().orElse("Unknown"), + stackReference.methodName()); + Location location = new Location((long) stackReference.lineNumber(), null); + return new SourceReference(null, null, stackTraceElement, location); } - return sourceReference; + return emptySourceReference(); + } + + private SourceReference emptySourceReference() { + return new SourceReference(null, null, null, null); } - private StepDefinitionPattern.Type getExpressionType(CoreStepDefinition stepDefinition) { + private StepDefinitionPatternType getExpressionType(CoreStepDefinition stepDefinition) { Class expressionType = stepDefinition.getExpression().getExpressionType(); if (expressionType.isAssignableFrom(RegularExpression.class)) { - return StepDefinitionPattern.Type.REGULAR_EXPRESSION; + return StepDefinitionPatternType.REGULAR_EXPRESSION; } else if (expressionType.isAssignableFrom(CucumberExpression.class)) { - return StepDefinitionPattern.Type.CUCUMBER_EXPRESSION; + return StepDefinitionPatternType.CUCUMBER_EXPRESSION; } else { throw new IllegalArgumentException(expressionType.getName()); } diff --git a/core/src/main/java/io/cucumber/core/runner/TestCase.java b/core/src/main/java/io/cucumber/core/runner/TestCase.java index 8e6f9fd61b..1604b17178 100644 --- a/core/src/main/java/io/cucumber/core/runner/TestCase.java +++ b/core/src/main/java/io/cucumber/core/runner/TestCase.java @@ -6,7 +6,6 @@ import io.cucumber.messages.types.Envelope; import io.cucumber.messages.types.StepMatchArgument; import io.cucumber.messages.types.StepMatchArgumentsList; -import io.cucumber.messages.types.TestStepResult; import io.cucumber.plugin.event.Group; import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.Result; @@ -15,8 +14,6 @@ import io.cucumber.plugin.event.TestCaseStarted; import io.cucumber.plugin.event.TestStep; -import java.io.PrintWriter; -import java.io.StringWriter; import java.net.URI; import java.time.Duration; import java.time.Instant; @@ -27,8 +24,6 @@ import static io.cucumber.core.runner.ExecutionMode.DRY_RUN; import static io.cucumber.core.runner.ExecutionMode.RUN; -import static io.cucumber.core.runner.TestStepResultStatus.from; -import static io.cucumber.messages.TimeConversion.javaDurationToDuration; import static io.cucumber.messages.TimeConversion.javaInstantToTimestamp; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; @@ -68,12 +63,6 @@ private static io.cucumber.messages.types.Group makeMessageGroup( group.getValue()); } - private static String toString(Throwable error) { - StringWriter stringWriter = new StringWriter(); - error.printStackTrace(new PrintWriter(stringWriter)); - return stringWriter.toString(); - } - void run(EventBus bus) { ExecutionMode nextExecutionMode = this.executionMode; emitTestCaseMessage(bus); @@ -106,7 +95,7 @@ void run(EventBus bus) { Duration duration = Duration.between(start, stop); Status status = Status.valueOf(state.getStatus().name()); Result result = new Result(status, duration, state.getError()); - emitTestCaseFinished(bus, executionId, stop, duration, status, result); + emitTestCaseFinished(bus, executionId, stop, result); } @Override @@ -166,8 +155,7 @@ public UUID getId() { } private void emitTestCaseMessage(EventBus bus) { - Envelope envelope = new Envelope(); - envelope.setTestCase(new io.cucumber.messages.types.TestCase( + Envelope envelope = Envelope.of(new io.cucumber.messages.types.TestCase( id.toString(), pickle.getId(), getTestSteps() @@ -178,26 +166,33 @@ private void emitTestCaseMessage(EventBus bus) { } private io.cucumber.messages.types.TestStep createTestStep(TestStep pluginTestStep) { - io.cucumber.messages.types.TestStep messagesTestStep = new io.cucumber.messages.types.TestStep(); - messagesTestStep.setId(pluginTestStep.getId().toString()); + // public TestStep(String hookId, String id, String pickleStepId, + // List stepDefinitionIds, List + // stepMatchArgumentsLists) { + String id = pluginTestStep.getId().toString(); + String hookId = null; + String pickleStepId = null; + List stepMatchArgumentsLists = null; + List stepDefinitionIds = null; if (pluginTestStep instanceof HookTestStep) { HookTestStep hookTestStep = (HookTestStep) pluginTestStep; HookDefinitionMatch definitionMatch = hookTestStep.getDefinitionMatch(); CoreHookDefinition hookDefinition = definitionMatch.getHookDefinition(); - messagesTestStep.setHookId(hookDefinition.getId().toString()); + hookId = hookDefinition.getId().toString(); } else if (pluginTestStep instanceof PickleStepTestStep) { PickleStepTestStep pickleStep = (PickleStepTestStep) pluginTestStep; - messagesTestStep.setPickleStepId(pickleStep.getStep().getId()); - messagesTestStep.setStepMatchArgumentsLists(singletonList(getStepMatchArguments(pickleStep))); + pickleStepId = pickleStep.getStep().getId(); + stepMatchArgumentsLists = singletonList(getStepMatchArguments(pickleStep)); StepDefinition stepDefinition = pickleStep.getDefinitionMatch().getStepDefinition(); if (stepDefinition instanceof CoreStepDefinition) { CoreStepDefinition coreStepDefinition = (CoreStepDefinition) stepDefinition; - messagesTestStep.setStepDefinitionIds(singletonList(coreStepDefinition.getId().toString())); + stepDefinitionIds = singletonList(coreStepDefinition.getId().toString()); } } - return messagesTestStep; + return new io.cucumber.messages.types.TestStep(hookId, id, pickleStepId, stepDefinitionIds, + stepMatchArgumentsLists); } public StepMatchArgumentsList getStepMatchArguments(PickleStepTestStep pickleStep) { @@ -209,8 +204,7 @@ public StepMatchArgumentsList getStepMatchArguments(PickleStepTestStep pickleSte private void emitTestCaseStarted(EventBus bus, Instant start, UUID executionId) { bus.send(new TestCaseStarted(start, this)); - Envelope envelope = new Envelope(); - envelope.setTestCaseStarted(new io.cucumber.messages.types.TestCaseStarted( + Envelope envelope = Envelope.of(new io.cucumber.messages.types.TestCaseStarted( 0L, executionId.toString(), id.toString(), @@ -219,18 +213,10 @@ private void emitTestCaseStarted(EventBus bus, Instant start, UUID executionId) } private void emitTestCaseFinished( - EventBus bus, UUID executionId, Instant stop, Duration duration, Status status, Result result + EventBus bus, UUID executionId, Instant stop, Result result ) { bus.send(new TestCaseFinished(stop, this, result)); - TestStepResult testStepResult = new TestStepResult(); - testStepResult.setStatus(from(status)); - testStepResult.setDuration(javaDurationToDuration(duration)); - if (result.getError() != null) { - testStepResult.setMessage(toString(result.getError())); - } - - Envelope envelope = new Envelope(); - envelope.setTestCaseFinished(new io.cucumber.messages.types.TestCaseFinished(executionId.toString(), + Envelope envelope = Envelope.of(new io.cucumber.messages.types.TestCaseFinished(executionId.toString(), javaInstantToTimestamp(stop), false)); bus.send(envelope); } diff --git a/core/src/main/java/io/cucumber/core/runner/TestCaseState.java b/core/src/main/java/io/cucumber/core/runner/TestCaseState.java index 7154848b71..06d94266fd 100644 --- a/core/src/main/java/io/cucumber/core/runner/TestCaseState.java +++ b/core/src/main/java/io/cucumber/core/runner/TestCaseState.java @@ -3,7 +3,7 @@ import io.cucumber.core.backend.Status; import io.cucumber.core.eventbus.EventBus; import io.cucumber.messages.types.Attachment; -import io.cucumber.messages.types.Attachment.ContentEncoding; +import io.cucumber.messages.types.AttachmentContentEncoding; import io.cucumber.messages.types.Envelope; import io.cucumber.plugin.event.EmbedEvent; import io.cucumber.plugin.event.Result; @@ -72,14 +72,15 @@ public void attach(byte[] data, String mediaType, String name) { requireActiveTestStep(); bus.send(new EmbedEvent(bus.getInstant(), testCase, data, mediaType, name)); - Attachment attachment = createAttachment(); - attachment.setBody(Base64.getEncoder().encodeToString(data)); - attachment.setContentEncoding(ContentEncoding.BASE_64); - attachment.setMediaType(mediaType); - if (name != null) { - attachment.setFileName(name); - } - bus.send(createEnvelope(attachment)); + bus.send(Envelope.of(new Attachment( + Base64.getEncoder().encodeToString(data), + AttachmentContentEncoding.BASE64, + name, + mediaType, + null, + testExecutionId.toString(), + currentTestStepId.toString(), + null))); } @Override @@ -89,38 +90,30 @@ public void attach(String data, String mediaType, String name) { requireActiveTestStep(); bus.send(new EmbedEvent(bus.getInstant(), testCase, data.getBytes(UTF_8), mediaType, name)); - Attachment attachment = createAttachment(); - attachment.setBody(data); - attachment.setContentEncoding(ContentEncoding.IDENTITY); - attachment.setMediaType(mediaType); - if (name != null) { - attachment.setFileName(name); - } - bus.send(createEnvelope(attachment)); + bus.send(Envelope.of(new Attachment( + data, + AttachmentContentEncoding.IDENTITY, + name, + mediaType, + null, + testExecutionId.toString(), + currentTestStepId.toString(), + null))); } @Override public void log(String text) { requireActiveTestStep(); bus.send(new WriteEvent(bus.getInstant(), testCase, text)); - Attachment attachment = createAttachment(); - attachment.setBody(text); - attachment.setContentEncoding(ContentEncoding.IDENTITY); - attachment.setMediaType("text/x.cucumber.log+plain"); - bus.send(createEnvelope(attachment)); - } - - private Envelope createEnvelope(Attachment attachment) { - Envelope envelope = new Envelope(); - envelope.setAttachment(attachment); - return envelope; - } - - private Attachment createAttachment() { - Attachment attachment = new Attachment(); - attachment.setTestCaseStartedId(testExecutionId.toString()); - attachment.setTestStepId(currentTestStepId.toString()); - return attachment; + bus.send(Envelope.of(new Attachment( + text, + AttachmentContentEncoding.IDENTITY, + null, + "text/x.cucumber.log+plain", + null, + testExecutionId.toString(), + currentTestStepId.toString(), + null))); } @Override diff --git a/core/src/main/java/io/cucumber/core/runner/TestStep.java b/core/src/main/java/io/cucumber/core/runner/TestStep.java index bfe0b53609..023d82e103 100644 --- a/core/src/main/java/io/cucumber/core/runner/TestStep.java +++ b/core/src/main/java/io/cucumber/core/runner/TestStep.java @@ -21,7 +21,7 @@ import static io.cucumber.core.exception.UnrecoverableExceptions.rethrowIfUnrecoverable; import static io.cucumber.core.runner.ExecutionMode.SKIP; import static io.cucumber.core.runner.TestAbortedExceptions.createIsTestAbortedExceptionPredicate; -import static io.cucumber.core.runner.TestStepResultStatus.from; +import static io.cucumber.core.runner.TestStepResultStatusMapper.from; import static io.cucumber.messages.TimeConversion.javaDurationToDuration; import static io.cucumber.messages.TimeConversion.javaInstantToTimestamp; import static java.time.Duration.ZERO; @@ -72,8 +72,7 @@ ExecutionMode run(TestCase testCase, EventBus bus, TestCaseState state, Executio private void emitTestStepStarted(TestCase testCase, EventBus bus, UUID textExecutionId, Instant startTime) { bus.send(new TestStepStarted(startTime, testCase, this)); - Envelope envelope = new Envelope(); - envelope.setTestStepStarted(new io.cucumber.messages.types.TestStepStarted( + Envelope envelope = Envelope.of(new io.cucumber.messages.types.TestStepStarted( textExecutionId.toString(), id.toString(), javaInstantToTimestamp(startTime))); @@ -117,15 +116,12 @@ private void emitTestStepFinished( ) { bus.send(new TestStepFinished(stopTime, testCase, this, result)); - TestStepResult testStepResult = new TestStepResult(); - if (result.getError() != null) { - testStepResult.setMessage(extractStackTrace(result.getError())); - } - testStepResult.setStatus(from(result.getStatus())); - testStepResult.setDuration(javaDurationToDuration(duration)); + TestStepResult testStepResult = new TestStepResult( + javaDurationToDuration(duration), + result.getError() != null ? extractStackTrace(result.getError()) : null, + from(result.getStatus())); - Envelope envelope = new Envelope(); - envelope.setTestStepFinished(new io.cucumber.messages.types.TestStepFinished( + Envelope envelope = Envelope.of(new io.cucumber.messages.types.TestStepFinished( textExecutionId.toString(), id.toString(), testStepResult, diff --git a/core/src/main/java/io/cucumber/core/runner/TestStepResultStatus.java b/core/src/main/java/io/cucumber/core/runner/TestStepResultStatus.java deleted file mode 100644 index e21b11dbc0..0000000000 --- a/core/src/main/java/io/cucumber/core/runner/TestStepResultStatus.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.cucumber.core.runner; - -import io.cucumber.messages.types.TestStepResult; -import io.cucumber.plugin.event.Status; - -import java.util.HashMap; -import java.util.Map; - -class TestStepResultStatus { - - private static final Map STATUS = new HashMap() { - { - put(Status.FAILED, TestStepResult.Status.FAILED); - put(Status.PASSED, TestStepResult.Status.PASSED); - put(Status.UNDEFINED, TestStepResult.Status.UNDEFINED); - put(Status.PENDING, TestStepResult.Status.PENDING); - put(Status.SKIPPED, TestStepResult.Status.SKIPPED); - put(Status.AMBIGUOUS, TestStepResult.Status.AMBIGUOUS); - } - }; - - private TestStepResultStatus() { - } - - static TestStepResult.Status from(Status status) { - return STATUS.getOrDefault(status, TestStepResult.Status.UNKNOWN); - } - -} diff --git a/core/src/main/java/io/cucumber/core/runner/TestStepResultStatusMapper.java b/core/src/main/java/io/cucumber/core/runner/TestStepResultStatusMapper.java new file mode 100644 index 0000000000..223541431a --- /dev/null +++ b/core/src/main/java/io/cucumber/core/runner/TestStepResultStatusMapper.java @@ -0,0 +1,40 @@ +package io.cucumber.core.runner; + +import io.cucumber.messages.types.TestStepResultStatus; +import io.cucumber.plugin.event.Status; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +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 io.cucumber.messages.types.TestStepResultStatus.UNKNOWN; + +class TestStepResultStatusMapper { + + private static final Map STATUS; + + static { + Map status = new HashMap<>(); + status.put(Status.FAILED, FAILED); + status.put(Status.PASSED, PASSED); + status.put(Status.UNDEFINED, UNDEFINED); + status.put(Status.PENDING, PENDING); + status.put(Status.SKIPPED, SKIPPED); + status.put(Status.AMBIGUOUS, AMBIGUOUS); + STATUS = Collections.unmodifiableMap(status); + }; + + private TestStepResultStatusMapper() { + } + + static TestStepResultStatus from(Status status) { + return STATUS.getOrDefault(status, UNKNOWN); + } + +} diff --git a/core/src/main/java/io/cucumber/core/runtime/CucumberExecutionContext.java b/core/src/main/java/io/cucumber/core/runtime/CucumberExecutionContext.java index b47cf3b60b..bd03a25982 100644 --- a/core/src/main/java/io/cucumber/core/runtime/CucumberExecutionContext.java +++ b/core/src/main/java/io/cucumber/core/runtime/CucumberExecutionContext.java @@ -52,9 +52,7 @@ public void startTestRun() { } private void emitMeta() { - Envelope envelope = new Envelope(); - envelope.setMeta(createMeta()); - bus.send(envelope); + bus.send(Envelope.of(createMeta())); } private Meta createMeta() { @@ -81,9 +79,7 @@ private void emitTestRunStarted() { log.debug(() -> "Sending run test started event"); start = bus.getInstant(); bus.send(new TestRunStarted(start)); - Envelope envelope = new Envelope(); - envelope.setTestRunStarted(new io.cucumber.messages.types.TestRunStarted(javaInstantToTimestamp(start))); - bus.send(envelope); + bus.send(Envelope.of(new io.cucumber.messages.types.TestRunStarted(javaInstantToTimestamp(start)))); } public void runBeforeAllHooks() { @@ -118,9 +114,7 @@ private void emitTestRunFinished(Throwable exception) { exception != null ? printStackTrace(exception) : null, exception == null && exitStatus.isSuccess(), javaInstantToTimestamp(instant)); - Envelope envelope = new Envelope(); - envelope.setTestRunFinished(testRunFinished); - bus.send(envelope); + bus.send(Envelope.of(testRunFinished)); } public void beforeFeature(Feature feature) { diff --git a/core/src/main/java/io/cucumber/core/stepexpression/StepExpressionFactory.java b/core/src/main/java/io/cucumber/core/stepexpression/StepExpressionFactory.java index 56ff95b42f..a79cbcc4b4 100644 --- a/core/src/main/java/io/cucumber/core/stepexpression/StepExpressionFactory.java +++ b/core/src/main/java/io/cucumber/core/stepexpression/StepExpressionFactory.java @@ -87,11 +87,9 @@ private Expression crateExpression(String expressionString) { try { expression = expressionFactory.createExpression(expressionString); } catch (UndefinedParameterTypeException e) { - Envelope envelope = new Envelope(); - envelope.setUndefinedParameterType(new UndefinedParameterType( + bus.send(Envelope.of(new UndefinedParameterType( expressionString, - e.getUndefinedParameterTypeName())); - bus.send(envelope); + e.getUndefinedParameterTypeName()))); throw registerTypeInConfiguration(expressionString, e); } return expression; diff --git a/core/src/test/java/io/cucumber/core/options/CommandlineOptionsParserTest.java b/core/src/test/java/io/cucumber/core/options/CommandlineOptionsParserTest.java index c6391f5f47..3a919a35ad 100644 --- a/core/src/test/java/io/cucumber/core/options/CommandlineOptionsParserTest.java +++ b/core/src/test/java/io/cucumber/core/options/CommandlineOptionsParserTest.java @@ -21,6 +21,7 @@ import org.hamcrest.core.Is; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -111,9 +112,19 @@ void prints_usage_for_unknown_options() { @Test void prints_usage_for_help() { parser.parse("--help"); - assertThat(output(), startsWith("Usage")); } + @Test + void prints_supported_languages() { + parser.parse("--i18n", "help"); + assertThat(output(), startsWith("af Afrikaans Afrikaans")); + } + + @Test + void prints_supported_keywords() { + parser.parse("--i18n", "en"); + assertThat(output(), startsWith(" | feature | \"Feature\", \"Business Need\", \"Ability\" |")); + } @Test void assigns_feature_paths() { diff --git a/core/src/test/java/io/cucumber/core/options/CucumberOptionsAnnotationParserTest.java b/core/src/test/java/io/cucumber/core/options/CucumberOptionsAnnotationParserTest.java index 60240b69ff..189d3b278f 100644 --- a/core/src/test/java/io/cucumber/core/options/CucumberOptionsAnnotationParserTest.java +++ b/core/src/test/java/io/cucumber/core/options/CucumberOptionsAnnotationParserTest.java @@ -13,6 +13,7 @@ import io.cucumber.core.snippets.SnippetType; import io.cucumber.plugin.Plugin; import io.cucumber.tagexpressions.TagExpressionException; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; diff --git a/core/src/test/java/io/cucumber/core/plugin/HtmlFormatterTest.java b/core/src/test/java/io/cucumber/core/plugin/HtmlFormatterTest.java index c82ff2057d..55466c387e 100644 --- a/core/src/test/java/io/cucumber/core/plugin/HtmlFormatterTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/HtmlFormatterTest.java @@ -5,14 +5,19 @@ import io.cucumber.messages.types.Envelope; import io.cucumber.messages.types.Hook; import io.cucumber.messages.types.ParameterType; +import io.cucumber.messages.types.SourceReference; import io.cucumber.messages.types.StepDefinition; +import io.cucumber.messages.types.StepDefinitionPattern; +import io.cucumber.messages.types.StepDefinitionPatternType; import io.cucumber.messages.types.TestRunFinished; import io.cucumber.messages.types.TestRunStarted; import io.cucumber.messages.types.Timestamp; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.time.Clock; +import java.util.Collections; import java.util.UUID; import static java.nio.charset.StandardCharsets.UTF_8; @@ -28,23 +33,17 @@ void writes_index_html() throws Throwable { EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); formatter.setEventPublisher(bus); - TestRunStarted testRunStarted = new TestRunStarted(); - testRunStarted.setTimestamp(new Timestamp(10L, 0L)); - Envelope testRunStartedEnvelope = new Envelope(); - testRunStartedEnvelope.setTestRunStarted(testRunStarted); - bus.send(testRunStartedEnvelope); + TestRunStarted testRunStarted = new TestRunStarted(new Timestamp(10L, 0L)); + bus.send(Envelope.of(testRunStarted)); - TestRunFinished testRunFinished = new TestRunFinished(); - testRunFinished.setTimestamp(new Timestamp(15L, 0L)); - Envelope testRunFinishedEnvelope = new Envelope(); - testRunFinishedEnvelope.setTestRunFinished(testRunFinished); - bus.send(testRunFinishedEnvelope); + TestRunFinished testRunFinished = new TestRunFinished(null, true, new Timestamp(15L, 0L)); + bus.send(Envelope.of(testRunFinished)); String html = new String(bytes.toByteArray(), UTF_8); assertThat(html, containsString("" + "window.CUCUMBER_MESSAGES = [" + "{\"testRunStarted\":{\"timestamp\":{\"seconds\":10,\"nanos\":0}}}," + - "{\"testRunFinished\":{\"timestamp\":{\"seconds\":15,\"nanos\":0}}}" + + "{\"testRunFinished\":{\"success\":true,\"timestamp\":{\"seconds\":15,\"nanos\":0}}}" + "];\n")); } @@ -55,38 +54,43 @@ void ignores_step_definitions() throws Throwable { EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); formatter.setEventPublisher(bus); - TestRunStarted testRunStarted = new TestRunStarted(); - testRunStarted.setTimestamp(new Timestamp(10L, 0L)); - Envelope testRunStartedEnvelope = new Envelope(); - testRunStartedEnvelope.setTestRunStarted(testRunStarted); - bus.send(testRunStartedEnvelope); - - StepDefinition stepDefinition = new StepDefinition(); - Envelope stepDefinitionEnvelope = new Envelope(); - stepDefinitionEnvelope.setStepDefinition(stepDefinition); - bus.send(stepDefinitionEnvelope); - - Hook hook = new Hook(); - Envelope hookEnvelope = new Envelope(); - hookEnvelope.setHook(hook); - bus.send(hookEnvelope); - - ParameterType parameterType = new ParameterType(); - Envelope parameterTypeEnvelope = new Envelope(); - parameterTypeEnvelope.setParameterType(parameterType); - bus.send(parameterTypeEnvelope); - - TestRunFinished testRunFinished = new TestRunFinished(); - testRunFinished.setTimestamp(new Timestamp(15L, 0L)); - Envelope testRunFinishedEnvelope = new Envelope(); - testRunFinishedEnvelope.setTestRunFinished(testRunFinished); - bus.send(testRunFinishedEnvelope); + TestRunStarted testRunStarted = new TestRunStarted(new Timestamp(10L, 0L)); + bus.send(Envelope.of(testRunStarted)); + + StepDefinition stepDefinition = new StepDefinition( + "", + new StepDefinitionPattern("", StepDefinitionPatternType.CUCUMBER_EXPRESSION), + SourceReference.of("https://example.com")); + bus.send(Envelope.of(stepDefinition)); + + Hook hook = new Hook("", + null, + SourceReference.of("https://example.com"), + null); + bus.send(Envelope.of(hook)); + + // public ParameterType(String name, List regularExpressions, + // Boolean preferForRegularExpressionMatch, Boolean useForSnippets, + // String id) { + ParameterType parameterType = new ParameterType( + "", + Collections.emptyList(), + true, + false, + ""); + bus.send(Envelope.of(parameterType)); + + TestRunFinished testRunFinished = new TestRunFinished( + null, + true, + new Timestamp(15L, 0L)); + bus.send(Envelope.of(testRunFinished)); String html = new String(bytes.toByteArray(), UTF_8); assertThat(html, containsString("" + "window.CUCUMBER_MESSAGES = [" + "{\"testRunStarted\":{\"timestamp\":{\"seconds\":10,\"nanos\":0}}}," + - "{\"testRunFinished\":{\"timestamp\":{\"seconds\":15,\"nanos\":0}}}" + + "{\"testRunFinished\":{\"success\":true,\"timestamp\":{\"seconds\":15,\"nanos\":0}}}" + "];\n")); } diff --git a/core/src/test/java/io/cucumber/core/plugin/MessageFormatterTest.java b/core/src/test/java/io/cucumber/core/plugin/MessageFormatterTest.java index f283005fbd..bed0963757 100644 --- a/core/src/test/java/io/cucumber/core/plugin/MessageFormatterTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/MessageFormatterTest.java @@ -25,22 +25,16 @@ void test() { EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); formatter.setEventPublisher(bus); - TestRunStarted testRunStarted = new TestRunStarted(); - testRunStarted.setTimestamp(new Timestamp(10L, 0L)); - Envelope testRunStartedEnvelope = new Envelope(); - testRunStartedEnvelope.setTestRunStarted(testRunStarted); - bus.send(testRunStartedEnvelope); - - TestRunFinished testRunFinished = new TestRunFinished(); - testRunFinished.setTimestamp(new Timestamp(15L, 0L)); - Envelope testRunFinishedEnvelope = new Envelope(); - testRunFinishedEnvelope.setTestRunFinished(testRunFinished); - bus.send(testRunFinishedEnvelope); + TestRunStarted testRunStarted = new TestRunStarted(new Timestamp(10L, 0L)); + bus.send(Envelope.of(testRunStarted)); + + TestRunFinished testRunFinished = new TestRunFinished(null, true, new Timestamp(15L, 0L)); + bus.send(Envelope.of(testRunFinished)); String ndjson = new String(bytes.toByteArray(), UTF_8); assertThat(ndjson, containsString("" + "{\"testRunStarted\":{\"timestamp\":{\"seconds\":10,\"nanos\":0}}}\n" + - "{\"testRunFinished\":{\"timestamp\":{\"seconds\":15,\"nanos\":0}}}\n")); + "{\"testRunFinished\":{\"success\":true,\"timestamp\":{\"seconds\":15,\"nanos\":0}}}\n")); } } 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 41f336bbdf..82c6e40395 100644 --- a/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java @@ -17,6 +17,7 @@ import io.cucumber.plugin.event.TestRunStarted; import io.cucumber.plugin.event.TestStepFinished; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.api.io.TempDir; diff --git a/core/src/test/java/io/cucumber/core/plugin/TimelineFormatterTest.java b/core/src/test/java/io/cucumber/core/plugin/TimelineFormatterTest.java index 92b823cb2c..15120c4943 100644 --- a/core/src/test/java/io/cucumber/core/plugin/TimelineFormatterTest.java +++ b/core/src/test/java/io/cucumber/core/plugin/TimelineFormatterTest.java @@ -1,5 +1,10 @@ package io.cucumber.core.plugin; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import io.cucumber.core.backend.StubStepDefinition; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; @@ -11,11 +16,6 @@ import io.cucumber.core.runtime.StubBackendSupplier; import io.cucumber.core.runtime.StubFeatureSupplier; import io.cucumber.core.runtime.TimeServiceEventBus; -import io.cucumber.messages.internal.com.fasterxml.jackson.annotation.JsonInclude.Include; -import io.cucumber.messages.internal.com.fasterxml.jackson.core.JsonGenerator; -import io.cucumber.messages.internal.com.fasterxml.jackson.core.JsonProcessingException; -import io.cucumber.messages.internal.com.fasterxml.jackson.databind.ObjectMapper; -import io.cucumber.messages.internal.com.fasterxml.jackson.databind.SerializationFeature; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; diff --git a/core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java b/core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java index b23528ce53..dc13053d72 100644 --- a/core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java +++ b/core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java @@ -4,7 +4,7 @@ import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.runtime.TimeServiceEventBus; -import io.cucumber.messages.types.Attachment.ContentEncoding; +import io.cucumber.messages.types.AttachmentContentEncoding; import io.cucumber.messages.types.Envelope; import io.cucumber.plugin.event.EmbedEvent; import org.junit.jupiter.api.Test; @@ -122,13 +122,14 @@ void attach_bytes_emits_event_on_bus() { assertThat(embedEvent.getName(), is("hello.txt")); Envelope envelope = envelopes.get(0); - assertThat(envelope.getAttachment().getBody(), + assertThat(envelope.getAttachment().get().getBody(), is(Base64.getEncoder().encodeToString("Hello World".getBytes(UTF_8)))); - assertThat(envelope.getAttachment().getContentEncoding(), is(ContentEncoding.BASE_64)); - assertThat(envelope.getAttachment().getMediaType(), is("text/plain")); - assertThat(envelope.getAttachment().getFileName(), is("hello.txt")); - assertThat(envelope.getAttachment().getTestStepId(), is(activeTestStep.toString())); - assertThat(envelope.getAttachment().getTestCaseStartedId(), is(state.getTestExecutionId().toString())); + assertThat(envelope.getAttachment().get().getContentEncoding(), is(AttachmentContentEncoding.BASE64)); + assertThat(envelope.getAttachment().get().getMediaType(), is("text/plain")); + assertThat(envelope.getAttachment().get().getFileName().get(), is("hello.txt")); + assertThat(envelope.getAttachment().get().getTestStepId().get(), is(activeTestStep.toString())); + assertThat(envelope.getAttachment().get().getTestCaseStartedId().get(), + is(state.getTestExecutionId().toString())); } @Test @@ -154,12 +155,13 @@ void attach_string_emits_event_on_bus() { assertThat(embedEvent.getName(), is("hello.txt")); Envelope envelope = envelopes.get(0); - assertThat(envelope.getAttachment().getBody(), is("Hello World")); - assertThat(envelope.getAttachment().getContentEncoding(), is(ContentEncoding.IDENTITY)); - assertThat(envelope.getAttachment().getMediaType(), is("text/plain")); - assertThat(envelope.getAttachment().getFileName(), is("hello.txt")); - assertThat(envelope.getAttachment().getTestStepId(), is(activeTestStep.toString())); - assertThat(envelope.getAttachment().getTestCaseStartedId(), is(state.getTestExecutionId().toString())); + assertThat(envelope.getAttachment().get().getBody(), is("Hello World")); + assertThat(envelope.getAttachment().get().getContentEncoding(), is(AttachmentContentEncoding.IDENTITY)); + assertThat(envelope.getAttachment().get().getMediaType(), is("text/plain")); + assertThat(envelope.getAttachment().get().getFileName().get(), is("hello.txt")); + assertThat(envelope.getAttachment().get().getTestStepId().get(), is(activeTestStep.toString())); + assertThat(envelope.getAttachment().get().getTestCaseStartedId().get(), + is(state.getTestExecutionId().toString())); } @Test diff --git a/core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java b/core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java index a507eb86a3..f552209889 100644 --- a/core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java +++ b/core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java @@ -459,10 +459,11 @@ void emits_a_meta_message() { .build() .run(); - Meta meta = messages.get(0).getMeta(); + Meta meta = messages.get(0).getMeta().get(); assertThat(meta.getProtocolVersion(), matchesPattern("\\d+\\.\\d+\\.\\d+(-RC\\d+)?(-SNAPSHOT)?")); assertThat(meta.getImplementation().getName(), is("cucumber-jvm")); - assertThat(meta.getImplementation().getVersion(), matchesPattern("\\d+\\.\\d+\\.\\d+(-RC\\d+)?(-SNAPSHOT)?")); + assertThat(meta.getImplementation().getVersion().get(), + matchesPattern("\\d+\\.\\d+\\.\\d+(-RC\\d+)?(-SNAPSHOT)?")); assertThat(meta.getOs().getName(), matchesPattern(".+")); assertThat(meta.getCpu().getName(), matchesPattern(".+")); } diff --git a/deltaspike/src/test/resources/cucumber.properties b/deltaspike/src/test/resources/junit-platform.properties similarity index 100% rename from deltaspike/src/test/resources/cucumber.properties rename to deltaspike/src/test/resources/junit-platform.properties diff --git a/gherkin-messages/pom.xml b/gherkin-messages/pom.xml index 0c4dddf6d8..25c3da9275 100644 --- a/gherkin-messages/pom.xml +++ b/gherkin-messages/pom.xml @@ -54,52 +54,4 @@ - - - - - - org.revapi - revapi-maven-plugin - - true - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - - - io.cucumber:gherkin - - - - - io.cucumber:gherkin - - META-INF/MANIFEST.MF - - - - - - io.cucumber.gherkin - io.cucumber.core.gherkin.messages.internal.gherkin - - - - - - - - - diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/CucumberQuery.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/CucumberQuery.java index 10eeee9cbb..fcea9c4952 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/CucumberQuery.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/CucumberQuery.java @@ -2,10 +2,8 @@ import io.cucumber.messages.types.Background; import io.cucumber.messages.types.Examples; -import io.cucumber.messages.types.FeatureChild; -import io.cucumber.messages.types.GherkinDocument; +import io.cucumber.messages.types.Feature; import io.cucumber.messages.types.Location; -import io.cucumber.messages.types.RuleChild; import io.cucumber.messages.types.Scenario; import io.cucumber.messages.types.Step; import io.cucumber.messages.types.TableRow; @@ -22,43 +20,22 @@ final class CucumberQuery { private final Map gherkinScenarioById = new HashMap<>(); private final Map locationBySourceId = new HashMap<>(); - void update(GherkinDocument gherkinDocument) { - for (FeatureChild featureChild : gherkinDocument.getFeature().getChildren()) { - if (featureChild.getBackground() != null) { - this.updateBackground( - featureChild.getBackground(), - gherkinDocument.getUri()); - } - - if (featureChild.getScenario() != null) { - this.updateScenario( - featureChild.getScenario(), - gherkinDocument.getUri()); - } - - if (featureChild.getRule() != null) { - for (RuleChild ruleChild : featureChild.getRule().getChildren()) { - if (ruleChild.getBackground() != null) { - this.updateBackground( - ruleChild.getBackground(), - gherkinDocument.getUri()); - } - - if (ruleChild.getScenario() != null) { - this.updateScenario( - ruleChild.getScenario(), - gherkinDocument.getUri()); - } - } - } - } + void update(Feature feature) { + feature.getChildren().forEach(featureChild -> { + featureChild.getBackground().ifPresent(this::updateBackground); + featureChild.getScenario().ifPresent(this::updateScenario); + featureChild.getRule().ifPresent(rule -> rule.getChildren().forEach(ruleChild -> { + ruleChild.getBackground().ifPresent(this::updateBackground); + ruleChild.getScenario().ifPresent(this::updateScenario); + })); + }); } - private void updateBackground(Background background, String uri) { + private void updateBackground(Background background) { updateStep(background.getSteps()); } - private void updateScenario(Scenario scenario, String uri) { + private void updateScenario(Scenario scenario) { gherkinScenarioById.put(requireNonNull(scenario.getId()), scenario); locationBySourceId.put(requireNonNull(scenario.getId()), scenario.getLocation()); updateStep(scenario.getSteps()); diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesDocStringArgument.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesDocStringArgument.java index a6a174f33c..0de6bd54ac 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesDocStringArgument.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesDocStringArgument.java @@ -25,7 +25,7 @@ public String getContentType() { @Override public String getMediaType() { - String mediaType = docString.getMediaType(); + String mediaType = docString.getMediaType().orElse(null); if ("".equals(mediaType)) { return null; } diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeature.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeature.java index 6c43bacb22..dce72f94ae 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeature.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeature.java @@ -45,11 +45,11 @@ final class GherkinMessagesFeature implements Feature { } private Node mapRuleOrScenario(FeatureChild featureChild) { - if (featureChild.getRule() != null) { - return new GherkinMessagesRule(this, featureChild.getRule()); + if (featureChild.getRule().isPresent()) { + return new GherkinMessagesRule(this, featureChild.getRule().get()); } - io.cucumber.messages.types.Scenario scenario = featureChild.getScenario(); + io.cucumber.messages.types.Scenario scenario = featureChild.getScenario().get(); if (!scenario.getExamples().isEmpty()) { return new GherkinMessagesScenarioOutline(this, scenario); } @@ -57,7 +57,7 @@ private Node mapRuleOrScenario(FeatureChild featureChild) { } private boolean hasRuleOrScenario(FeatureChild featureChild) { - return featureChild.getRule() != null || featureChild.getScenario() != null; + return featureChild.getRule().isPresent() || featureChild.getScenario().isPresent(); } @Override diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeatureParser.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeatureParser.java index 174736673b..99d1d1e21e 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeatureParser.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeatureParser.java @@ -4,80 +4,78 @@ import io.cucumber.core.gherkin.FeatureParser; import io.cucumber.core.gherkin.FeatureParserException; import io.cucumber.core.gherkin.Pickle; -import io.cucumber.gherkin.Gherkin; import io.cucumber.gherkin.GherkinDialect; import io.cucumber.gherkin.GherkinDialectProvider; +import io.cucumber.gherkin.GherkinParser; import io.cucumber.messages.types.Envelope; import io.cucumber.messages.types.GherkinDocument; import io.cucumber.messages.types.ParseError; +import io.cucumber.messages.types.Source; import java.net.URI; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; +import java.util.stream.Collectors; -import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope; -import static java.util.Collections.singletonList; +import static io.cucumber.messages.types.SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN; import static java.util.stream.Collectors.toList; public final class GherkinMessagesFeatureParser implements FeatureParser { @Override public Optional parse(URI path, String source, Supplier idGenerator) { - List sources = singletonList( - makeSourceEnvelope(source, path.toString())); + List envelopes = GherkinParser.builder() + .idGenerator(() -> idGenerator.get().toString()) + .build() + .parse(Envelope.of(new Source(path.toString(), source, TEXT_X_CUCUMBER_GHERKIN_PLAIN))) + .collect(Collectors.toUnmodifiableList()); - List envelopes = Gherkin.fromSources( - sources, - true, - true, - true, - () -> idGenerator.get().toString()).collect(toList()); - - GherkinDocument gherkinDocument = envelopes.stream() - .map(Envelope::getGherkinDocument) - .filter(Objects::nonNull) - .findFirst() - .orElse(null); + List errors = envelopes.stream() + .map(Envelope::getParseError) + .filter(Optional::isPresent) + .map(Optional::get) + .map(ParseError::getMessage) + .collect(toList()); - if (gherkinDocument == null || gherkinDocument.getFeature() == null) { - List errors = envelopes.stream() - .map(Envelope::getParseError) - .filter(Objects::nonNull) - .map(ParseError::getMessage) - .collect(toList()); - if (!errors.isEmpty()) { - throw new FeatureParserException( - "Failed to parse resource at: " + path + "\n" + String.join("\n", errors)); - } - return Optional.empty(); + if (!errors.isEmpty()) { + throw new FeatureParserException( + "Failed to parse resource at: " + path + "\n" + String.join("\n", errors)); } - CucumberQuery cucumberQuery = new CucumberQuery(); - cucumberQuery.update(gherkinDocument); - GherkinDialectProvider dialectProvider = new GherkinDialectProvider(); - io.cucumber.messages.types.Feature feature = gherkinDocument.getFeature(); - String language = feature.getLanguage(); - GherkinDialect dialect = dialectProvider.getDialect(language, null); + return envelopes.stream() + .map(Envelope::getGherkinDocument) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .map(GherkinDocument::getFeature) + .filter(Optional::isPresent) + .map(Optional::get) + .map(feature -> { + CucumberQuery cucumberQuery = new CucumberQuery(); + cucumberQuery.update(feature); + GherkinDialectProvider dialectProvider = new GherkinDialectProvider(); + String language = feature.getLanguage(); + GherkinDialect dialect = dialectProvider.getDialect(language, null); - List pickleMessages = envelopes.stream() - .map(Envelope::getPickle) - .filter(Objects::nonNull) - .collect(toList()); + List pickleMessages = envelopes.stream() + .map(Envelope::getPickle) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); - List pickles = pickleMessages.stream() - .map(pickle -> new GherkinMessagesPickle(pickle, path, dialect, cucumberQuery)) - .collect(toList()); + List pickles = pickleMessages.stream() + .map(pickle -> new GherkinMessagesPickle(pickle, path, dialect, cucumberQuery)) + .collect(toList()); - GherkinMessagesFeature messagesFeature = new GherkinMessagesFeature( - feature, - path, - source, - pickles, - envelopes); - return Optional.of(messagesFeature); + return new GherkinMessagesFeature( + feature, + path, + source, + pickles, + envelopes); + }); } @Override diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesLocation.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesLocation.java index d49c4c5e0e..a0353dbbae 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesLocation.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesLocation.java @@ -5,7 +5,7 @@ final class GherkinMessagesLocation { static Location from(io.cucumber.messages.types.Location location) { - return new Location(Math.toIntExact(location.getLine()), Math.toIntExact(location.getColumn())); + return new Location(Math.toIntExact(location.getLine()), Math.toIntExact(location.getColumn().orElse(0L))); } } diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesRule.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesRule.java index d091a3437b..c42c378317 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesRule.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesRule.java @@ -1,5 +1,6 @@ package io.cucumber.core.gherkin.messages; +import io.cucumber.messages.types.RuleChild; import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.Node; @@ -18,9 +19,10 @@ final class GherkinMessagesRule implements Node.Rule { this.parent = parent; this.rule = rule; this.children = rule.getChildren().stream() - .filter(ruleChild -> ruleChild.getScenario() != null) - .map(ruleChild -> { - io.cucumber.messages.types.Scenario scenario = ruleChild.getScenario(); + .map(RuleChild::getScenario) + .filter(Optional::isPresent) + .map(Optional::get) + .map(scenario -> { if (!scenario.getExamples().isEmpty()) { return new GherkinMessagesScenarioOutline(this, scenario); } else { diff --git a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesStep.java b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesStep.java index f4fca860d8..9616d403f4 100644 --- a/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesStep.java +++ b/gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesStep.java @@ -6,7 +6,6 @@ import io.cucumber.gherkin.GherkinDialect; import io.cucumber.messages.types.PickleDocString; import io.cucumber.messages.types.PickleStep; -import io.cucumber.messages.types.PickleStepArgument; import io.cucumber.messages.types.PickleTable; import io.cucumber.plugin.event.Location; @@ -35,20 +34,19 @@ final class GherkinMessagesStep implements Step { } private static Argument extractArgument(PickleStep pickleStep, Location location) { - PickleStepArgument argument = pickleStep.getArgument(); - if (pickleStep.getArgument() == null) { - return null; - } - if (argument.getDocString() != null) { - PickleDocString docString = argument.getDocString(); - // TODO: Fix this work around - return new GherkinMessagesDocStringArgument(docString, location.getLine() + 1); - } - if (argument.getDataTable() != null) { - PickleTable table = argument.getDataTable(); - return new GherkinMessagesDataTableArgument(table, location.getLine() + 1); - } - return null; + return pickleStep.getArgument() + .map(argument -> { + if (argument.getDocString().isPresent()) { + PickleDocString docString = argument.getDocString().get(); + // TODO: Fix this work around + return new GherkinMessagesDocStringArgument(docString, location.getLine() + 1); + } + if (argument.getDataTable().isPresent()) { + PickleTable table = argument.getDataTable().get(); + return new GherkinMessagesDataTableArgument(table, location.getLine() + 1); + } + return null; + }).orElse(null); } private static StepType extractKeyWordType(String keyWord, GherkinDialect dialect) { diff --git a/java/src/test/resources/cucumber.properties b/java/src/test/resources/junit-platform.properties similarity index 100% rename from java/src/test/resources/cucumber.properties rename to java/src/test/resources/junit-platform.properties diff --git a/java8/src/test/resources/cucumber.properties b/java8/src/test/resources/junit-platform.properties similarity index 100% rename from java8/src/test/resources/cucumber.properties rename to java8/src/test/resources/junit-platform.properties diff --git a/kotlin-java8/src/test/resources/cucumber.properties b/kotlin-java8/src/test/resources/junit-platform.properties similarity index 100% rename from kotlin-java8/src/test/resources/cucumber.properties rename to kotlin-java8/src/test/resources/junit-platform.properties diff --git a/openejb/src/test/resources/cucumber.properties b/openejb/src/test/resources/junit-platform.properties similarity index 100% rename from openejb/src/test/resources/cucumber.properties rename to openejb/src/test/resources/junit-platform.properties diff --git a/pom.xml b/pom.xml index c3f2cccc60..870b7e0f4c 100644 --- a/pom.xml +++ b/pom.xml @@ -21,8 +21,8 @@ - 17.1.1 - 22.0.0 + 18.0.0 + 23.0.0 2.5.15 diff --git a/spring/src/test/resources/junit-platform.properties b/spring/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000..b48dd63bf1 --- /dev/null +++ b/spring/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +cucumber.publish.quiet=true