Skip to content

Commit cf3dc37

Browse files
committed
Simplify with better messages
1 parent 15cfe0f commit cf3dc37

File tree

3 files changed

+91
-20
lines changed

3 files changed

+91
-20
lines changed

cucumber-bom/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
<properties>
1616
<ci-environment.version>10.0.1</ci-environment.version>
1717
<cucumber-expressions.version>18.0.1</cucumber-expressions.version>
18-
<gherkin.version>33.0.0</gherkin.version>
18+
<gherkin.version>33.0.1-SNAPSHOT</gherkin.version>
1919
<html-formatter.version>21.13.0</html-formatter.version>
2020
<junit-xml-formatter.version>0.8.0</junit-xml-formatter.version>
21-
<messages.version>28.0.0</messages.version>
21+
<messages.version>28.0.1-SNAPSHOT</messages.version>
2222
<pretty-formatter.version>0.3.0</pretty-formatter.version>
2323
<query.version>13.5.1-SNAPSHOT</query.version>
2424
<tag-expressions.version>6.1.2</tag-expressions.version>

cucumber-core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import io.cucumber.core.feature.FeatureWithLines;
44
import io.cucumber.messages.types.Envelope;
5+
import io.cucumber.messages.types.Pickle;
6+
import io.cucumber.messages.types.TestCase;
57
import io.cucumber.messages.types.TestCaseFinished;
6-
import io.cucumber.messages.types.TestStepResult;
8+
import io.cucumber.messages.types.TestCaseStarted;
9+
import io.cucumber.messages.types.TestRunFinished;
10+
import io.cucumber.messages.types.TestStepFinished;
711
import io.cucumber.messages.types.TestStepResultStatus;
812
import io.cucumber.plugin.ConcurrentEventListener;
913
import io.cucumber.plugin.event.EventPublisher;
10-
import io.cucumber.query.Query;
1114

1215
import java.io.File;
1316
import java.io.OutputStream;
@@ -16,12 +19,21 @@
1619
import java.net.URI;
1720
import java.net.URISyntaxException;
1821
import java.nio.charset.StandardCharsets;
22+
import java.util.ArrayList;
23+
import java.util.Collections;
24+
import java.util.Comparator;
25+
import java.util.HashMap;
1926
import java.util.HashSet;
20-
import java.util.LinkedHashMap;
27+
import java.util.List;
2128
import java.util.Map;
29+
import java.util.Optional;
2230
import java.util.Set;
2331

2432
import static io.cucumber.core.feature.FeatureWithLines.create;
33+
import static io.cucumber.messages.types.TestStepResultStatus.PASSED;
34+
import static io.cucumber.messages.types.TestStepResultStatus.SKIPPED;
35+
import static java.util.Collections.emptyList;
36+
import static java.util.Comparator.comparing;
2537
import static java.util.Objects.requireNonNull;
2638

2739
/**
@@ -30,9 +42,9 @@
3042
*/
3143
public final class RerunFormatter implements ConcurrentEventListener {
3244

33-
private final PrintWriter writer;
34-
private final Map<String, Set<Integer>> featureAndFailedLinesMapping = new LinkedHashMap<>();
3545
private final Query query = new Query();
46+
private final Map<String, Set<Integer>> featureAndFailedLinesMapping = new HashMap<>();
47+
private final PrintWriter writer;
3648

3749
public RerunFormatter(OutputStream out) {
3850
this.writer = createPrintWriter(out);
@@ -68,32 +80,30 @@ public void setEventPublisher(EventPublisher publisher) {
6880
publisher.registerHandlerFor(Envelope.class, event -> {
6981
query.update(event);
7082
event.getTestCaseFinished().ifPresent(this::handleTestCaseFinished);
71-
event.getTestRunFinished().ifPresent(testRunFinished -> finishReport());
83+
event.getTestRunFinished().ifPresent(this::handleTestRunFinished);
7284
});
7385
}
7486

87+
7588
private void handleTestCaseFinished(TestCaseFinished event) {
76-
TestStepResultStatus testStepResultStatus = query.findMostSevereTestStepResultBy(event)
77-
.map(TestStepResult::getStatus)
89+
TestStepResultStatus status = query.findMostSevereTestStepResultBy(event)
7890
// By definition
79-
.orElse(TestStepResultStatus.PASSED);
80-
81-
if (testStepResultStatus == TestStepResultStatus.PASSED
82-
|| testStepResultStatus == TestStepResultStatus.SKIPPED) {
91+
.orElse(PASSED);
92+
if (status == PASSED || status == SKIPPED) {
8393
return;
8494
}
85-
8695
query.findPickleBy(event).ifPresent(pickle -> {
87-
Set<Integer> lines = featureAndFailedLinesMapping
88-
.computeIfAbsent(pickle.getUri(), s -> new HashSet<>());
89-
query.findLocationOf(pickle).ifPresent(location -> {
96+
// Adds the entire feature for rerunning
97+
Set<Integer> lines = featureAndFailedLinesMapping.computeIfAbsent(pickle.getUri(), s -> new HashSet<>());
98+
pickle.getLocation().ifPresent(location -> {
99+
// Adds the specific scenarios
90100
// TODO: Messages are silly
91101
lines.add((int) (long) location.getLine());
92102
});
93103
});
94104
}
95105

96-
private void finishReport() {
106+
private void handleTestRunFinished(TestRunFinished testRunFinished) {
97107
for (Map.Entry<String, Set<Integer>> entry : featureAndFailedLinesMapping.entrySet()) {
98108
String key = entry.getKey();
99109
// TODO: Should these be relative?
@@ -104,4 +114,65 @@ private void finishReport() {
104114
writer.close();
105115
}
106116

117+
/**
118+
* Miniaturized version of Cucumber Query.
119+
* <p>
120+
* The rerun plugin only needs a few things.
121+
*/
122+
private static class Query {
123+
124+
private final Map<String, TestCase> testCaseById = new HashMap<>();
125+
private final Map<String, List<TestStepResultStatus>> testStepsResultStatusByTestCaseStartedId = new HashMap<>();
126+
private final Map<String, TestCaseStarted> testCaseStartedById = new HashMap<>();
127+
private final Map<String, Pickle> pickleById = new HashMap<>();
128+
129+
void update(Envelope envelope) {
130+
envelope.getPickle().ifPresent(this::updatePickle);
131+
envelope.getTestCase().ifPresent(this::updateTestCase);
132+
envelope.getTestCaseStarted().ifPresent(this::updateTestCaseStarted);
133+
envelope.getTestStepFinished().ifPresent(this::updateTestStepFinished);
134+
}
135+
136+
private void updatePickle(Pickle event) {
137+
pickleById.put(event.getId(), event);
138+
}
139+
140+
private void updateTestCase(TestCase event) {
141+
testCaseById.put(event.getId(), event);
142+
}
143+
144+
private void updateTestCaseStarted(TestCaseStarted testCaseStarted) {
145+
testCaseStartedById.put(testCaseStarted.getId(), testCaseStarted);
146+
}
147+
148+
private void updateTestStepFinished(TestStepFinished event) {
149+
String testCaseStartedId = event.getTestCaseStartedId();
150+
testStepsResultStatusByTestCaseStartedId.computeIfAbsent(testCaseStartedId, s -> new ArrayList<>())
151+
.add(event.getTestStepResult().getStatus());
152+
}
153+
154+
public Optional<TestStepResultStatus> findMostSevereTestStepResultBy(TestCaseFinished testCaseFinished) {
155+
List<TestStepResultStatus> statuses = testStepsResultStatusByTestCaseStartedId
156+
.getOrDefault(testCaseFinished.getTestCaseStartedId(), emptyList());
157+
if (statuses.isEmpty()) {
158+
return Optional.empty();
159+
}
160+
return Optional.of(Collections.max(statuses, comparing(Enum::ordinal)));
161+
}
162+
163+
public Optional<Pickle> findPickleBy(TestCaseFinished testCaseFinished) {
164+
String testCaseStartedId = testCaseFinished.getTestCaseStartedId();
165+
TestCaseStarted testCaseStarted = testCaseStartedById.get(testCaseStartedId);
166+
if (testCaseStarted == null) {
167+
return Optional.empty();
168+
}
169+
TestCase testCase = testCaseById.get(testCaseStarted.getTestCaseId());
170+
if (testCase == null) {
171+
return Optional.empty();
172+
}
173+
return Optional.ofNullable(pickleById.get(testCase.getPickleId()));
174+
}
175+
176+
}
177+
107178
}

cucumber-core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ private static String getHookName(Hook hook) {
379379
}
380380

381381
private Optional<String> findSnippets(Pickle pickle) {
382-
return query.findLocationOf(pickle)
382+
return pickle.getLocation()
383383
.map(location -> {
384384
URI uri = URI.create(pickle.getUri());
385385
List<Suggestion> suggestionForTestCase = suggestions.stream()

0 commit comments

Comments
 (0)