Skip to content

Commit ac38546

Browse files
committed
[Junit Engine] Map pickle tree to TestDescriptors
Because the pickle tree and and the test descriptor tree have a one to one correspondence is is possible to map one data structure to the other. This significantly cleans up a mixing of concerns.
1 parent d6ddd26 commit ac38546

File tree

6 files changed

+114
-88
lines changed

6 files changed

+114
-88
lines changed

gherkin-messages/src/main/java/io/cucumber/core/gherkin/messages/GherkinMessagesFeature.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import java.net.URI;
1313
import java.util.Collection;
1414
import java.util.List;
15+
import java.util.NoSuchElementException;
1516
import java.util.Objects;
16-
import java.util.Optional;
1717
import java.util.stream.Collectors;
1818

1919
final class GherkinMessagesFeature implements Feature {
@@ -62,11 +62,12 @@ public Location getLocation() {
6262
}
6363

6464
@Override
65-
public Optional<Pickle> getPickleAt(Located located) {
65+
public Pickle getPickleAt(Located located) {
6666
Location location = located.getLocation();
6767
return pickles.stream()
68-
.filter(cucumberPickle -> cucumberPickle.getLocation().equals(location))
69-
.findFirst();
68+
.filter(pickle -> pickle.getLocation().equals(location))
69+
.findFirst()
70+
.orElseThrow(() -> new NoSuchElementException("No pickle at " + location));
7071
}
7172

7273
@Override

gherkin-vintage/src/main/java/io/cucumber/core/gherkin/vintage/GherkinVintageFeature.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
import java.net.URI;
1212
import java.util.Collection;
1313
import java.util.List;
14+
import java.util.NoSuchElementException;
1415
import java.util.Objects;
15-
import java.util.Optional;
1616
import java.util.stream.Collectors;
1717

1818
final class GherkinVintageFeature implements Feature {
@@ -49,11 +49,12 @@ public String getKeyword() {
4949
}
5050

5151
@Override
52-
public Optional<Pickle> getPickleAt(Located located) {
52+
public Pickle getPickleAt(Located located) {
5353
Location location = located.getLocation();
5454
return pickles.stream()
55-
.filter(cucumberPickle -> cucumberPickle.getLocation().equals(location))
56-
.findFirst();
55+
.filter(pickle -> pickle.getLocation().equals(location))
56+
.findFirst()
57+
.orElseThrow(() -> new NoSuchElementException("No pickle at " + location));
5758
}
5859

5960
@Override

gherkin/src/main/java/io/cucumber/core/gherkin/Feature.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import java.net.URI;
44
import java.util.List;
5-
import java.util.Optional;
65

76
public interface Feature extends Node, Container<Node> {
87

98
String getKeyword();
109

11-
Optional<Pickle> getPickleAt(Located located);
10+
Pickle getPickleAt(Located located);
1211

1312
List<Pickle> getPickles();
1413

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
11
package io.cucumber.core.gherkin;
22

3+
import java.util.function.BiFunction;
4+
35
public interface Node extends Located, Named {
6+
7+
default <T> T map(
8+
T parent,
9+
BiFunction<Feature, T, T> mapFeature,
10+
BiFunction<Scenario, T, T> mapScenario,
11+
BiFunction<Rule, T, T> mapRule,
12+
BiFunction<ScenarioOutline, T, T> mapScenarioOutline,
13+
BiFunction<Examples, T, T> mapExamples,
14+
BiFunction<Example, T, T> mapExample
15+
) {
16+
if (this instanceof Scenario) {
17+
return mapScenario.apply((Scenario) this, parent);
18+
} else if (this instanceof Example) {
19+
return mapExample.apply((Example) this, parent);
20+
} else if (this instanceof Container){
21+
final T mapped;
22+
if (this instanceof Feature) {
23+
mapped = mapFeature.apply((Feature) this, parent);
24+
} else if(this instanceof Rule){
25+
mapped = mapRule.apply((Rule) this, parent);
26+
} else if (this instanceof ScenarioOutline){
27+
mapped = mapScenarioOutline.apply((ScenarioOutline) this, parent);
28+
} else if (this instanceof Examples){
29+
mapped = mapExamples.apply((Examples) this, parent);
30+
} else {
31+
throw new IllegalArgumentException(this.getClass().getName());
32+
}
33+
Container<?> container = (Container<?>) this;
34+
container.children().forEach(node -> node.map(mapped, mapFeature, mapScenario, mapRule, mapScenarioOutline, mapExamples, mapExample));
35+
return mapped;
36+
} else {
37+
throw new IllegalArgumentException(this.getClass().getName());
38+
}
39+
}
440
}

junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/FeatureResolver.java

+65-76
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import io.cucumber.core.gherkin.Example;
66
import io.cucumber.core.gherkin.Examples;
77
import io.cucumber.core.gherkin.Feature;
8-
import io.cucumber.core.gherkin.Located;
98
import io.cucumber.core.gherkin.Named;
9+
import io.cucumber.core.gherkin.Pickle;
1010
import io.cucumber.core.gherkin.Rule;
1111
import io.cucumber.core.gherkin.Scenario;
1212
import io.cucumber.core.gherkin.ScenarioOutline;
@@ -96,7 +96,7 @@ private void resolvePath(Path path) {
9696
.scanForResourcesPath(path)
9797
.stream()
9898
.sorted(comparing(Feature::getUri))
99-
.map(this::resolveFeature)
99+
.map(this::createFeatureDescriptor)
100100
.forEach(engineDescriptor::mergeFeature);
101101
}
102102

@@ -117,7 +117,7 @@ private void resolvePackageResource(String packageName) {
117117
.scanForResourcesInPackage(packageName, packageFilter)
118118
.stream()
119119
.sorted(comparing(Feature::getUri))
120-
.map(this::resolveFeature)
120+
.map(this::createFeatureDescriptor)
121121
.forEach(engineDescriptor::mergeFeature);
122122
}
123123

@@ -127,7 +127,7 @@ void resolveClasspathResource(ClasspathResourceSelector selector) {
127127
.scanForClasspathResource(classpathResourceName, packageFilter)
128128
.stream()
129129
.sorted(comparing(Feature::getUri))
130-
.map(this::resolveFeature)
130+
.map(this::createFeatureDescriptor)
131131
.forEach(engineDescriptor::mergeFeature);
132132
}
133133

@@ -136,7 +136,7 @@ void resolveClasspathRoot(ClasspathRootSelector selector) {
136136
.scanForResourcesInClasspathRoot(selector.getClasspathRoot(), packageFilter)
137137
.stream()
138138
.sorted(comparing(Feature::getUri))
139-
.map(this::resolveFeature)
139+
.map(this::createFeatureDescriptor)
140140
.forEach(engineDescriptor::mergeFeature);
141141
}
142142

@@ -182,81 +182,70 @@ private Stream<FeatureDescriptor> resolveUri(URI uri) {
182182
.scanForResourcesUri(uri)
183183
.stream()
184184
.sorted(comparing(Feature::getUri))
185-
.map(this::resolveFeature);
185+
.map(this::createFeatureDescriptor);
186186
}
187187

188-
private FeatureDescriptor resolveFeature(Feature feature) {
188+
private FeatureDescriptor createFeatureDescriptor(Feature feature) {
189189
FeatureOrigin source = FeatureOrigin.fromUri(feature.getUri());
190-
FeatureDescriptor descriptor = new FeatureDescriptor(
191-
source.featureSegment(engineDescriptor.getUniqueId(), feature),
192-
getNameOrKeyWord(feature),
193-
source.featureSource(),
194-
feature
195-
);
196-
feature.children().forEach(scenarioDefinition -> visit(feature, descriptor, source, scenarioDefinition));
197-
return descriptor;
198-
}
199-
200-
private <T extends Located & Named> void visit(Feature feature, TestDescriptor parent, FeatureOrigin source, T node) {
201-
if (node instanceof Scenario) {
202-
feature.getPickleAt(node)
203-
.ifPresent(pickle -> {
204-
PickleDescriptor descriptor = new PickleDescriptor(
205-
source.scenarioSegment(parent.getUniqueId(), node),
206-
getNameOrKeyWord(node),
207-
source.nodeSource(node),
208-
pickle
209-
);
210-
parent.addChild(descriptor);
211-
});
212-
}
213-
214-
if (node instanceof Rule) {
215-
NodeDescriptor descriptor = new NodeDescriptor(
216-
source.ruleSegment(parent.getUniqueId(), node),
217-
getNameOrKeyWord(node),
218-
source.nodeSource(node)
219-
);
220-
parent.addChild(descriptor);
221-
Rule rule = (Rule) node;
222-
rule.children().forEach(section -> visit(feature, descriptor, source, section));
223-
}
224-
225-
if (node instanceof ScenarioOutline) {
226-
NodeDescriptor descriptor = new NodeDescriptor(
227-
source.scenarioSegment(parent.getUniqueId(), node),
228-
getNameOrKeyWord(node),
229-
source.nodeSource(node)
230-
);
231-
parent.addChild(descriptor);
232-
ScenarioOutline scenarioOutline = (ScenarioOutline) node;
233-
scenarioOutline.children().forEach(section -> visit(feature, descriptor, source, section));
234-
}
235-
236-
if (node instanceof Examples) {
237-
NodeDescriptor descriptor = new NodeDescriptor(
238-
source.examplesSegment(parent.getUniqueId(), node),
239-
getNameOrKeyWord(node),
240-
source.nodeSource(node)
241-
);
242-
parent.addChild(descriptor);
243-
Examples examples = (Examples) node;
244-
examples.children().forEach(example -> visit(feature, descriptor, source, example));
245-
}
246-
247-
if (node instanceof Example) {
248-
feature.getPickleAt(node)
249-
.ifPresent(pickle -> {
250-
PickleDescriptor descriptor = new PickleDescriptor(
251-
source.exampleSegment(parent.getUniqueId(), node),
252-
getNameOrKeyWord(node),
253-
source.nodeSource(node),
254-
pickle
255-
);
256-
parent.addChild(descriptor);
257-
});
258-
}
259190

191+
return (FeatureDescriptor) feature.map(
192+
engineDescriptor,
193+
(Feature self, TestDescriptor parent) -> new FeatureDescriptor(
194+
source.featureSegment(parent.getUniqueId(), self),
195+
getNameOrKeyWord(self),
196+
source.featureSource(),
197+
self
198+
),
199+
(Scenario node, TestDescriptor parent) -> {
200+
Pickle pickle = feature.getPickleAt(node);
201+
TestDescriptor descriptor = new PickleDescriptor(
202+
source.scenarioSegment(parent.getUniqueId(), node),
203+
getNameOrKeyWord(node),
204+
source.nodeSource(node),
205+
pickle
206+
);
207+
parent.addChild(descriptor);
208+
return descriptor;
209+
},
210+
(Rule node, TestDescriptor parent) -> {
211+
TestDescriptor descriptor = new NodeDescriptor(
212+
source.ruleSegment(parent.getUniqueId(), node),
213+
getNameOrKeyWord(node),
214+
source.nodeSource(node)
215+
);
216+
parent.addChild(descriptor);
217+
return descriptor;
218+
},
219+
(ScenarioOutline node, TestDescriptor parent) -> {
220+
TestDescriptor descriptor = new NodeDescriptor(
221+
source.scenarioSegment(parent.getUniqueId(), node),
222+
getNameOrKeyWord(node),
223+
source.nodeSource(node)
224+
);
225+
parent.addChild(descriptor);
226+
return descriptor;
227+
},
228+
(Examples node, TestDescriptor parent) -> {
229+
NodeDescriptor descriptor = new NodeDescriptor(
230+
source.examplesSegment(parent.getUniqueId(), node),
231+
getNameOrKeyWord(node),
232+
source.nodeSource(node)
233+
);
234+
parent.addChild(descriptor);
235+
return descriptor;
236+
},
237+
(Example node, TestDescriptor parent) -> {
238+
Pickle pickle = feature.getPickleAt(node);
239+
PickleDescriptor descriptor = new PickleDescriptor(
240+
source.exampleSegment(parent.getUniqueId(), node),
241+
getNameOrKeyWord(node),
242+
source.nodeSource(node),
243+
pickle
244+
);
245+
parent.addChild(descriptor);
246+
return descriptor;
247+
}
248+
);
260249
}
261250

262251
private <T extends Named> String getNameOrKeyWord(T node) {

pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858

5959
<!--Test Dependencies-->
6060
<junit.version>4.13</junit.version>
61-
<junit-jupiter.version>5.6.1</junit-jupiter.version>
62-
<junit-platform.version>1.6.1</junit-platform.version>
61+
<junit-jupiter.version>5.6.2</junit-jupiter.version>
62+
<junit-platform.version>1.6.2</junit-platform.version>
6363
<hamcrest.version>2.2</hamcrest.version>
6464
<mockito.version>3.3.3</mockito.version>
6565
<!--Maven plugins-->

0 commit comments

Comments
 (0)