Skip to content

Commit ce6a9c9

Browse files
committed
Fix errors in the RerunFormatter, move its testing to core
Fix the rerun formatters handling of failures in background, scenario outline examples and hooks in the RerunFormatter. Move all testing of the RerunFormatter to core.
1 parent 0110e3f commit ce6a9c9

File tree

9 files changed

+139
-176
lines changed

9 files changed

+139
-176
lines changed

core/src/main/java/cucumber/runtime/formatter/RerunFormatter.java

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@
2424
* Failed means: (failed, undefined, pending) test result
2525
*/
2626
class RerunFormatter implements Formatter, Reporter {
27-
2827
private final NiceAppendable out;
29-
3028
private String featureLocation;
31-
32-
private Step step;
33-
29+
private Scenario scenario;
30+
private ScenarioState state = ScenarioState.None;
31+
private boolean isTestFailed = false;
3432
private Map<String, LinkedHashSet<Integer>> featureAndFailedLinesMapping = new HashMap<String, LinkedHashSet<Integer>>();
3533

34+
enum ScenarioState {
35+
None, In_Background_Or_Before, In_Scenario
36+
}
3637

3738
public RerunFormatter(Appendable out) {
3839
this.out = new NiceAppendable(out);
@@ -49,14 +50,28 @@ public void feature(Feature feature) {
4950

5051
@Override
5152
public void background(Background background) {
53+
recordPreviousScenarioIfFailed();
54+
state = ScenarioState.In_Background_Or_Before;
5255
}
5356

5457
@Override
5558
public void scenario(Scenario scenario) {
59+
recordPreviousScenarioIfFailed();
60+
state = ScenarioState.In_Scenario;
61+
this.scenario = scenario;
62+
}
63+
64+
private void recordPreviousScenarioIfFailed() {
65+
if (state == ScenarioState.In_Scenario && isTestFailed) {
66+
recordTestFailed();
67+
isTestFailed = false;
68+
}
5669
}
5770

5871
@Override
5972
public void scenarioOutline(ScenarioOutline scenarioOutline) {
73+
recordPreviousScenarioIfFailed();
74+
state = ScenarioState.None;
6075
}
6176

6277
@Override
@@ -65,11 +80,12 @@ public void examples(Examples examples) {
6580

6681
@Override
6782
public void step(Step step) {
68-
this.step = step;
6983
}
7084

7185
@Override
7286
public void eof() {
87+
recordPreviousScenarioIfFailed();
88+
state = ScenarioState.None;
7389
}
7490

7591
@Override
@@ -78,10 +94,10 @@ public void syntaxError(String state, String event, List<String> legalEvents, St
7894

7995
@Override
8096
public void done() {
81-
reportFailedSteps();
97+
reportFailedScenarios();
8298
}
8399

84-
private void reportFailedSteps() {
100+
private void reportFailedScenarios() {
85101
Set<Map.Entry<String, LinkedHashSet<Integer>>> entries = featureAndFailedLinesMapping.entrySet();
86102
boolean firstFeature = true;
87103
for (Map.Entry<String, LinkedHashSet<Integer>> entry : entries) {
@@ -115,13 +131,17 @@ public void endOfScenarioLifeCycle(Scenario scenario) {
115131

116132
@Override
117133
public void before(Match match, Result result) {
118-
134+
recordPreviousScenarioIfFailed();
135+
state = ScenarioState.In_Background_Or_Before;
136+
if (isTestFailed(result)) {
137+
isTestFailed = true;
138+
}
119139
}
120140

121141
@Override
122142
public void result(Result result) {
123143
if (isTestFailed(result)) {
124-
recordTestFailed();
144+
isTestFailed = true;
125145
}
126146
}
127147

@@ -131,17 +151,20 @@ private boolean isTestFailed(Result result) {
131151
}
132152

133153
private void recordTestFailed() {
134-
LinkedHashSet<Integer> failedSteps = this.featureAndFailedLinesMapping.get(featureLocation);
135-
if (failedSteps == null) {
136-
failedSteps = new LinkedHashSet<Integer>();
137-
this.featureAndFailedLinesMapping.put(featureLocation, failedSteps);
154+
LinkedHashSet<Integer> failedScenarios = this.featureAndFailedLinesMapping.get(featureLocation);
155+
if (failedScenarios == null) {
156+
failedScenarios = new LinkedHashSet<Integer>();
157+
this.featureAndFailedLinesMapping.put(featureLocation, failedScenarios);
138158
}
139159

140-
failedSteps.add(step.getLine());
160+
failedScenarios.add(scenario.getLine());
141161
}
142162

143163
@Override
144164
public void after(Match match, Result result) {
165+
if (isTestFailed(result)) {
166+
isTestFailed = true;
167+
}
145168
}
146169

147170
@Override

core/src/test/java/cucumber/runtime/TestHelper.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.UnsupportedEncodingException;
2525
import java.util.AbstractMap.SimpleEntry;
2626
import java.util.ArrayList;
27+
import java.util.Arrays;
2728
import java.util.List;
2829
import java.util.Map;
2930

@@ -68,13 +69,20 @@ public String getClassName() {
6869

6970
public static void runFeatureWithFormatter(final CucumberFeature feature, final Map<String, String> stepsToResult, final List<SimpleEntry<String, String>> hooks,
7071
final long stepHookDuration, final Formatter formatter, final Reporter reporter) throws Throwable, FileNotFoundException {
72+
runFeaturesWithFormatter(Arrays.asList(feature), stepsToResult, hooks, stepHookDuration, formatter, reporter);
73+
}
74+
75+
public static void runFeaturesWithFormatter(final List<CucumberFeature> features, final Map<String, String> stepsToResult, final List<SimpleEntry<String, String>> hooks,
76+
final long stepHookDuration, final Formatter formatter, final Reporter reporter) throws Throwable {
7177
final RuntimeOptions runtimeOptions = new RuntimeOptions(new Env());
7278
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
7379
final ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(classLoader);
7480
final RuntimeGlue glue = createMockedRuntimeGlueThatMatchesTheSteps(stepsToResult, hooks);
7581
final Runtime runtime = new Runtime(resourceLoader, classLoader, asList(mock(Backend.class)), runtimeOptions, new StopWatch.Stub(stepHookDuration), glue);
7682

77-
feature.run(formatter, reporter, runtime);
83+
for (CucumberFeature feature : features) {
84+
feature.run(formatter, reporter, runtime);
85+
}
7886
formatter.done();
7987
formatter.close();
8088
}

core/src/test/java/cucumber/runtime/formatter/RerunFormatterTest.java

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.AbstractMap.SimpleEntry;
88
import java.util.ArrayList;
9+
import java.util.Arrays;
910
import java.util.Collections;
1011
import java.util.HashMap;
1112
import java.util.List;
@@ -15,6 +16,42 @@
1516

1617
public class RerunFormatterTest {
1718

19+
@Test
20+
public void should_leave_report_empty_when_no_scenario_fails() throws Throwable {
21+
CucumberFeature feature = TestHelper.feature("path/test.feature", "" +
22+
"Feature: feature name\n" +
23+
" Scenario: scenario name\n" +
24+
" Given first step\n" +
25+
" When second step\n" +
26+
" Then third step\n");
27+
Map<String, String> stepsToResult = new HashMap<String, String>();
28+
stepsToResult.put("first step", "passed");
29+
stepsToResult.put("second step", "passed");
30+
stepsToResult.put("third step", "passed");
31+
32+
String formatterOutput = runFeatureWithRerunFormatter(feature, stepsToResult);
33+
34+
assertEquals("", formatterOutput);
35+
}
36+
37+
@Test
38+
public void should_use_scenario_location_when_scenario_step_fails() throws Throwable {
39+
CucumberFeature feature = TestHelper.feature("path/test.feature", "" +
40+
"Feature: feature name\n" +
41+
" Scenario: scenario name\n" +
42+
" Given first step\n" +
43+
" When second step\n" +
44+
" Then third step\n");
45+
Map<String, String> stepsToResult = new HashMap<String, String>();
46+
stepsToResult.put("first step", "passed");
47+
stepsToResult.put("second step", "passed");
48+
stepsToResult.put("third step", "failed");
49+
50+
String formatterOutput = runFeatureWithRerunFormatter(feature, stepsToResult);
51+
52+
assertEquals("path/test.feature:2", formatterOutput);
53+
}
54+
1855
@Test
1956
public void should_use_scenario_location_when_background_step_fails() throws Throwable {
2057
CucumberFeature feature = TestHelper.feature("path/test.feature", "" +
@@ -95,17 +132,71 @@ public void should_use_scenario_location_when_after_hook_fails() throws Throwabl
95132
assertEquals("path/test.feature:2", formatterOutput);
96133
}
97134

135+
@Test
136+
public void should_one_entry_for_feature_with_many_failing_scenarios() throws Throwable {
137+
CucumberFeature feature = TestHelper.feature("path/test.feature", "" +
138+
"Feature: feature name\n" +
139+
" Scenario: scenario 1 name\n" +
140+
" When first step\n" +
141+
" Then second step\n" +
142+
" Scenario: scenario 2 name\n" +
143+
" When third step\n" +
144+
" Then forth step\n");
145+
Map<String, String> stepsToResult = new HashMap<String, String>();
146+
stepsToResult.put("first step", "passed");
147+
stepsToResult.put("second step", "failed");
148+
stepsToResult.put("third step", "failed");
149+
stepsToResult.put("forth step", "passed");
150+
151+
String formatterOutput = runFeatureWithRerunFormatter(feature, stepsToResult);
152+
153+
assertEquals("path/test.feature:2:5", formatterOutput);
154+
}
155+
156+
@Test
157+
public void should_one_entry_for_each_failing_feature() throws Throwable {
158+
CucumberFeature feature1 = TestHelper.feature("path/first.feature", "" +
159+
"Feature: feature 1 name\n" +
160+
" Scenario: scenario 1 name\n" +
161+
" When first step\n" +
162+
" Then second step\n");
163+
CucumberFeature feature2 = TestHelper.feature("path/second.feature", "" +
164+
"Feature: feature 2 name\n" +
165+
" Scenario: scenario 2 name\n" +
166+
" When third step\n" +
167+
" Then forth step\n");
168+
Map<String, String> stepsToResult = new HashMap<String, String>();
169+
stepsToResult.put("first step", "passed");
170+
stepsToResult.put("second step", "failed");
171+
stepsToResult.put("third step", "failed");
172+
stepsToResult.put("forth step", "passed");
173+
174+
String formatterOutput = runFeaturesWithRerunFormatter(Arrays.asList(feature1, feature2), stepsToResult);
175+
176+
assertEquals("path/second.feature:2 path/first.feature:2", formatterOutput);
177+
}
178+
98179
private String runFeatureWithRerunFormatter(final CucumberFeature feature, final Map<String, String> stepsToResult)
99180
throws Throwable {
100181
return runFeatureWithRerunFormatter(feature, stepsToResult, Collections.<SimpleEntry<String, String>>emptyList());
101182
}
102183

103184
private String runFeatureWithRerunFormatter(final CucumberFeature feature, final Map<String, String> stepsToResult,
104185
final List<SimpleEntry<String, String>> hooks) throws Throwable {
186+
return runFeaturesWithRerunFormatter(Arrays.asList(feature), stepsToResult, hooks);
187+
}
188+
189+
private String runFeaturesWithRerunFormatter(final List<CucumberFeature> features, final Map<String, String> stepsToResult)
190+
throws Throwable {
191+
return runFeaturesWithRerunFormatter(features, stepsToResult, Collections.<SimpleEntry<String, String>>emptyList());
192+
}
193+
194+
private String runFeaturesWithRerunFormatter(final List<CucumberFeature> features, final Map<String, String> stepsToResult,
195+
final List<SimpleEntry<String, String>> hooks) throws Throwable {
105196
final StringBuffer buffer = new StringBuffer();
106197
final RerunFormatter rerunFormatter = new RerunFormatter(buffer);
107198
final long stepHookDuration = 0;
108-
TestHelper.runFeatureWithFormatter(feature, stepsToResult, hooks, stepHookDuration, rerunFormatter, rerunFormatter);
199+
TestHelper.runFeaturesWithFormatter(features, stepsToResult, hooks, stepHookDuration, rerunFormatter, rerunFormatter);
109200
return buffer.toString();
110201
}
111202

java/src/test/java/cucumber/runtime/java/formatter/DummyGlueCode.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

java/src/test/java/cucumber/runtime/java/formatter/RerunFormatterTest.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)