Skip to content

[Core] Use null safe-messages #2497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6cc61ba
WIP Use null safe-messages
mpkorstanje Mar 8, 2022
a0489a8
WIP Use null safe-messages
mpkorstanje Mar 8, 2022
a7fea9f
WIP Use null safe-messages
mpkorstanje Mar 8, 2022
22bcfc4
WIP Use null safe-messages
mpkorstanje Mar 8, 2022
a1f14f9
WIP Use null safe-messages
mpkorstanje Mar 31, 2022
2474231
WIP Use null safe-messages
mpkorstanje Apr 1, 2022
33719bb
WIP Use null safe-messages
mpkorstanje Apr 2, 2022
0ee339d
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
43d9503
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
94c6a9d
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
cff5006
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
21a8ea5
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
90c572c
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
227f0ed
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
c3eedd1
WIP Use null safe-messages
mpkorstanje Apr 3, 2022
2d05077
Merge remote-tracking branch 'origin/main' into use-null-safe-messages
mpkorstanje Apr 3, 2022
f4d9109
Merge remote-tracking branch 'origin/main' into use-null-safe-messages
mpkorstanje Apr 10, 2022
5e2b2fb
Fix version
mpkorstanje Apr 17, 2022
3344cc8
Clean up
mpkorstanje Apr 17, 2022
305dd55
Clean up
mpkorstanje Apr 17, 2022
56b1511
Clean up
mpkorstanje Apr 17, 2022
b377da2
Merge remote-tracking branch 'origin/main' into use-null-safe-messages
mpkorstanje Apr 17, 2022
c2d21a8
Some revapi
mpkorstanje Apr 17, 2022
43123b2
Fix some revapi
mpkorstanje Apr 18, 2022
13893c1
Update changelog
mpkorstanje Apr 18, 2022
20f1f9d
Tests
mpkorstanje Apr 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 31 additions & 35 deletions core/src/main/java/io/cucumber/core/runner/TestCaseState.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,14 +72,16 @@ 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
Expand All @@ -89,38 +91,32 @@ 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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
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, TestStepResult.Status> STATUS = new HashMap<Status, TestStepResult.Status>() {
private static final Map<Status, io.cucumber.messages.types.TestStepResultStatus> 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);
put(Status.FAILED, io.cucumber.messages.types.TestStepResultStatus.FAILED);
put(Status.PASSED, io.cucumber.messages.types.TestStepResultStatus.PASSED);
put(Status.UNDEFINED, io.cucumber.messages.types.TestStepResultStatus.UNDEFINED);
put(Status.PENDING, io.cucumber.messages.types.TestStepResultStatus.PENDING);
put(Status.SKIPPED, io.cucumber.messages.types.TestStepResultStatus.SKIPPED);
put(Status.AMBIGUOUS, io.cucumber.messages.types.TestStepResultStatus.AMBIGUOUS);
}
};

private TestStepResultStatus() {
}

static TestStepResult.Status from(Status status) {
return STATUS.getOrDefault(status, TestStepResult.Status.UNKNOWN);
static io.cucumber.messages.types.TestStepResultStatus from(Status status) {
return STATUS.getOrDefault(status, io.cucumber.messages.types.TestStepResultStatus.UNKNOWN);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,43 +20,22 @@ final class CucumberQuery {
private final Map<String, Scenario> gherkinScenarioById = new HashMap<>();
private final Map<String, Location> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ 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);
}
return new GherkinMessagesScenario(this, scenario);
}

private boolean hasRuleOrScenario(FeatureChild featureChild) {
return featureChild.getRule() != null || featureChild.getScenario() != null;
return featureChild.getRule().isPresent() || featureChild.getScenario().isPresent();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Feature> parse(URI path, String source, Supplier<UUID> idGenerator) {
List<Envelope> sources = singletonList(
makeSourceEnvelope(source, path.toString()));
List<Envelope> 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<Envelope> 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<String> errors = envelopes.stream()
.map(Envelope::getParseError)
.filter(Optional::isPresent)
.map(Optional::get)
.map(ParseError::getMessage)
.collect(toList());

if (gherkinDocument == null || gherkinDocument.getFeature() == null) {
List<String> 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<io.cucumber.messages.types.Pickle> pickleMessages = envelopes.stream()
.map(Envelope::getPickle)
.filter(Objects::nonNull)
.collect(toList());
List<io.cucumber.messages.types.Pickle> pickleMessages = envelopes.stream()
.map(Envelope::getPickle)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());

List<Pickle> pickles = pickleMessages.stream()
.map(pickle -> new GherkinMessagesPickle(pickle, path, dialect, cucumberQuery))
.collect(toList());
List<Pickle> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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 {
Expand Down
Loading