Skip to content

Commit 39e5483

Browse files
aslakhellesoympkorstanje
authored andcommitted
[Core] Support Gherkin Rule keyword
Introduces the Gherkin Messages module which will add support for the Gherkin `Rule` keyword. Because the rule keyword is not supported by the `json` or `html` formatter it will be an opt-in module.
1 parent cee8eb2 commit 39e5483

21 files changed

+905
-32
lines changed

gherkin-messages/pom.xml

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>io.cucumber</groupId>
8+
<artifactId>cucumber-jvm</artifactId>
9+
<version>5.0.0-RC3-SNAPSHOT</version>
10+
</parent>
11+
12+
<properties>
13+
<project.Automatic-Module-Name>io.cucumber.core.gherkin.messages</project.Automatic-Module-Name>
14+
</properties>
15+
16+
<artifactId>cucumber-gherkin-messages</artifactId>
17+
<packaging>jar</packaging>
18+
<name>Cucumber-JVM: Gherkin Messages</name>
19+
20+
<dependencies>
21+
<dependency>
22+
<groupId>io.cucumber</groupId>
23+
<artifactId>gherkin</artifactId>
24+
<version>${gherkin-messages.version}</version>
25+
</dependency>
26+
27+
<dependency>
28+
<groupId>io.cucumber</groupId>
29+
<artifactId>cucumber-gherkin</artifactId>
30+
</dependency>
31+
32+
<dependency>
33+
<groupId>io.cucumber</groupId>
34+
<artifactId>messages</artifactId>
35+
</dependency>
36+
37+
</dependencies>
38+
39+
<build>
40+
<plugins>
41+
<plugin>
42+
<groupId>org.apache.maven.plugins</groupId>
43+
<artifactId>maven-shade-plugin</artifactId>
44+
<version>3.1.0</version>
45+
<executions>
46+
<execution>
47+
<phase>package</phase>
48+
<goals>
49+
<goal>shade</goal>
50+
</goals>
51+
<configuration>
52+
<artifactSet>
53+
<includes>
54+
<include>io.cucumber:gherkin</include>
55+
</includes>
56+
</artifactSet>
57+
<relocations>
58+
<relocation>
59+
<pattern>io.cucumber.gherkin</pattern>
60+
<shadedPattern>io.cucumber.core.gherkin.messages.internal.gherkin</shadedPattern>
61+
</relocation>
62+
</relocations>
63+
</configuration>
64+
</execution>
65+
</executions>
66+
</plugin>
67+
</plugins>
68+
</build>
69+
70+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package io.cucumber.core.gherkin.messages;
2+
3+
import io.cucumber.messages.Messages.GherkinDocument;
4+
import io.cucumber.messages.Messages.GherkinDocument.Feature.FeatureChild;
5+
import io.cucumber.messages.Messages.GherkinDocument.Feature.FeatureChild.RuleChild;
6+
import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario;
7+
import io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario.Examples;
8+
import io.cucumber.messages.Messages.GherkinDocument.Feature.Step;
9+
import io.cucumber.messages.Messages.GherkinDocument.Feature.TableRow;
10+
import io.cucumber.messages.Messages.Location;
11+
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
import static java.util.Objects.requireNonNull;
17+
18+
final class CucumberQuery {
19+
private final Map<String, Step> gherkinStepById = new HashMap<>();
20+
private final Map<String, Scenario> gherkinScenarioById = new HashMap<>();
21+
private final Map<String, Location> locationBySourceId = new HashMap<>();
22+
23+
void update(GherkinDocument gherkinDocument) {
24+
for (FeatureChild featureChild : gherkinDocument.getFeature().getChildrenList()) {
25+
if (featureChild.hasBackground()) {
26+
this.updateBackground(
27+
featureChild.getBackground(),
28+
gherkinDocument.getUri()
29+
);
30+
}
31+
32+
if (featureChild.hasScenario()) {
33+
this.updateScenario(
34+
featureChild.getScenario(),
35+
gherkinDocument.getUri()
36+
);
37+
}
38+
39+
if (featureChild.hasRule()) {
40+
for (RuleChild ruleChild : featureChild.getRule().getChildrenList()) {
41+
if (ruleChild.hasBackground()) {
42+
this.updateBackground(
43+
ruleChild.getBackground(),
44+
gherkinDocument.getUri()
45+
);
46+
}
47+
48+
if (ruleChild.hasScenario()) {
49+
this.updateScenario(
50+
ruleChild.getScenario(),
51+
gherkinDocument.getUri()
52+
);
53+
}
54+
}
55+
}
56+
}
57+
}
58+
59+
private void updateScenario(Scenario scenario, String uri) {
60+
gherkinScenarioById.put(requireNonNull(scenario.getId()), scenario);
61+
locationBySourceId.put(requireNonNull(scenario.getId()), scenario.getLocation());
62+
updateStep(scenario.getStepsList());
63+
64+
for (Examples examples: scenario.getExamplesList()) {
65+
for (TableRow tableRow: examples.getTableBodyList()) {
66+
this.locationBySourceId.put(requireNonNull(tableRow.getId()), tableRow.getLocation());
67+
}
68+
}
69+
}
70+
71+
private void updateBackground(GherkinDocument.Feature.Background background, String uri) {
72+
updateStep(background.getStepsList());
73+
}
74+
75+
private void updateStep(List<Step> stepsList) {
76+
for (Step step : stepsList) {
77+
locationBySourceId.put(requireNonNull(step.getId()), step.getLocation());
78+
gherkinStepById.put(requireNonNull(step.getId()), step);
79+
}
80+
}
81+
82+
Step getGherkinStep(String sourceId) {
83+
return requireNonNull(gherkinStepById.get(requireNonNull(sourceId)));
84+
}
85+
86+
Scenario getGherkinScenario(String sourceId) {
87+
return requireNonNull(gherkinScenarioById.get(requireNonNull(sourceId)));
88+
}
89+
90+
Location getLocation(String sourceId) {
91+
Location location = locationBySourceId.get(requireNonNull(sourceId));
92+
return requireNonNull(location);
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.cucumber.core.gherkin.messages;
2+
3+
import io.cucumber.core.gherkin.DataTableArgument;
4+
import io.cucumber.messages.Messages.PickleStepArgument.PickleTable;
5+
6+
import java.util.AbstractList;
7+
import java.util.List;
8+
9+
final class GherkinMessagesDataTableArgument implements DataTableArgument {
10+
11+
private final CellView cells;
12+
private final int line;
13+
14+
GherkinMessagesDataTableArgument(PickleTable table, int line) {
15+
this.cells = new CellView(table);
16+
this.line = line;
17+
}
18+
19+
@Override
20+
public List<List<String>> cells() {
21+
return cells;
22+
}
23+
24+
@Override
25+
public int getLine() {
26+
return line;
27+
}
28+
29+
private static class CellView extends AbstractList<List<String>> {
30+
private final PickleTable table;
31+
32+
CellView(PickleTable table) {
33+
this.table = table;
34+
}
35+
36+
@Override
37+
public List<String> get(int row) {
38+
return new AbstractList<String>() {
39+
@Override
40+
public String get(int column) {
41+
return table.getRows(row).getCells(column).getValue();
42+
}
43+
44+
@Override
45+
public int size() {
46+
return table.getRows(row).getCellsCount();
47+
}
48+
};
49+
}
50+
51+
@Override
52+
public int size() {
53+
return table.getRowsCount();
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.cucumber.core.gherkin.messages;
2+
3+
import io.cucumber.core.gherkin.DocStringArgument;
4+
import io.cucumber.messages.Messages.PickleStepArgument.PickleDocString;
5+
6+
final class GherkinMessagesDocStringArgument implements DocStringArgument {
7+
8+
private final PickleDocString docString;
9+
private final int line;
10+
11+
GherkinMessagesDocStringArgument(PickleDocString docString, int line) {
12+
this.docString = docString;
13+
this.line = line;
14+
}
15+
16+
@Override
17+
public String getContent() {
18+
return docString.getContent();
19+
}
20+
21+
@Override
22+
public String getContentType() {
23+
return docString.getContentType();
24+
}
25+
26+
@Override
27+
public int getLine() {
28+
return line;
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.cucumber.core.gherkin.messages;
2+
3+
import io.cucumber.core.gherkin.Example;
4+
import io.cucumber.core.gherkin.Location;
5+
import io.cucumber.messages.Messages.GherkinDocument.Feature.TableRow;
6+
7+
final class GherkinMessagesExample implements Example {
8+
9+
private final TableRow tableRow;
10+
private final int rowIndex;
11+
12+
GherkinMessagesExample(TableRow tableRow, int rowIndex) {
13+
this.tableRow = tableRow;
14+
this.rowIndex = rowIndex;
15+
}
16+
17+
@Override
18+
public String getKeyWord() {
19+
return null;
20+
}
21+
22+
@Override
23+
public String getName() {
24+
return "Example #" + rowIndex;
25+
}
26+
27+
@Override
28+
public Location getLocation() {
29+
return GherkinMessagesLocation.from(tableRow.getLocation());
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.cucumber.core.gherkin.messages;
2+
3+
import io.cucumber.core.gherkin.Example;
4+
import io.cucumber.core.gherkin.Examples;
5+
import io.cucumber.core.gherkin.Location;
6+
7+
import java.util.concurrent.atomic.AtomicInteger;
8+
import java.util.stream.Stream;
9+
10+
final class GherkinMessagesExamples implements Examples {
11+
12+
private final io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario.Examples examples;
13+
14+
GherkinMessagesExamples(io.cucumber.messages.Messages.GherkinDocument.Feature.Scenario.Examples examples) {
15+
this.examples = examples;
16+
}
17+
18+
@Override
19+
public Stream<Example> children() {
20+
AtomicInteger row = new AtomicInteger(1);
21+
return examples.getTableBodyList().stream()
22+
.map(tableRow -> new GherkinMessagesExample(tableRow, row.getAndIncrement()));
23+
}
24+
25+
@Override
26+
public String getKeyWord() {
27+
return examples.getKeyword();
28+
}
29+
30+
@Override
31+
public String getName() {
32+
return examples.getName();
33+
}
34+
35+
@Override
36+
public Location getLocation() {
37+
return GherkinMessagesLocation.from(examples.getLocation());
38+
}
39+
}

0 commit comments

Comments
 (0)