Skip to content

Commit d8559dc

Browse files
brasmussonmpkorstanje
authored andcommitted
[Core] Add TestRunStarted event, let Stats handle the exit code
Add the TestRunStarted event and present the duration between the TestRunStarted and TestRunFinished events in the summary print out. Move the handling of exit code and errors to the summary print out to the Stats class.
1 parent 2c9a79d commit d8559dc

File tree

6 files changed

+132
-164
lines changed

6 files changed

+132
-164
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package cucumber.api.event;
2+
3+
public final class TestRunStarted extends TimeStampedEvent {
4+
5+
public TestRunStarted(Long timeStamp) {
6+
super(timeStamp);
7+
}
8+
}

core/src/main/java/cucumber/runtime/Runtime.java

+5-99
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package cucumber.runtime;
22

3-
import cucumber.api.Pending;
4-
import cucumber.api.Result;
53
import cucumber.api.StepDefinitionReporter;
64
import cucumber.api.SummaryPrinter;
7-
import cucumber.api.event.EventHandler;
8-
import cucumber.api.event.TestCaseFinished;
95
import cucumber.api.event.TestRunFinished;
106
import cucumber.api.event.TestStepFinished;
117
import cucumber.runner.EventBus;
@@ -21,7 +17,6 @@
2117
import java.io.IOException;
2218
import java.io.PrintStream;
2319
import java.util.ArrayList;
24-
import java.util.Arrays;
2520
import java.util.Collection;
2621
import java.util.List;
2722
import java.util.Map;
@@ -32,50 +27,17 @@
3227
*/
3328
public class Runtime {
3429

35-
private static final String[] ASSUMPTION_VIOLATED_EXCEPTIONS = {
36-
"org.junit.AssumptionViolatedException",
37-
"org.junit.internal.AssumptionViolatedException"
38-
};
39-
40-
static {
41-
Arrays.sort(ASSUMPTION_VIOLATED_EXCEPTIONS);
42-
}
43-
44-
private static final byte ERRORS = 0x1;
45-
46-
private final Stats stats;
47-
UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); // package private to be avaiable for tests.
30+
final Stats stats; // package private to be avaiable for tests.
31+
private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker();
4832

4933
private final RuntimeOptions runtimeOptions;
5034

51-
private final List<Throwable> errors = new ArrayList<Throwable>();
5235
private final ResourceLoader resourceLoader;
5336
private final ClassLoader classLoader;
5437
private final Runner runner;
5538
private final List<PicklePredicate> filters;
5639
private final EventBus bus;
5740
private final Compiler compiler = new Compiler();
58-
private final EventHandler<TestStepFinished> stepFinishedHandler = new EventHandler<TestStepFinished>() {
59-
@Override
60-
public void receive(TestStepFinished event) {
61-
Result result = event.result;
62-
if (result.getError() != null) {
63-
addError(result.getError());
64-
}
65-
if (event.testStep.isHook()) {
66-
addHookToCounterAndResult(result);
67-
} else {
68-
addStepToCounterAndResult(result);
69-
}
70-
}
71-
};
72-
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
73-
@Override
74-
public void receive(TestCaseFinished event) {
75-
stats.addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation());
76-
}
77-
};
78-
7941
public Runtime(ResourceLoader resourceLoader, ClassFinder classFinder, ClassLoader classLoader, RuntimeOptions runtimeOptions) {
8042
this(resourceLoader, classLoader, loadBackends(resourceLoader, classFinder), runtimeOptions);
8143
}
@@ -115,8 +77,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio
11577
this.filters.add(new LinePredicate(lineFilters));
11678
}
11779

118-
bus.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
119-
bus.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
80+
stats.setEventPublisher(bus);
12081
undefinedStepsTracker.setEventPublisher(bus);
12182
runtimeOptions.setEventBus(bus);
12283
}
@@ -126,10 +87,6 @@ private static Collection<? extends Backend> loadBackends(ResourceLoader resourc
12687
return reflections.instantiateSubclasses(Backend.class, "cucumber.runtime", new Class[]{ResourceLoader.class}, new Object[]{resourceLoader});
12788
}
12889

129-
public void addError(Throwable error) {
130-
errors.add(error);
131-
}
132-
13390
/**
13491
* This is the main entry point. Used from CLI, but not from JUnit.
13592
*/
@@ -191,40 +148,11 @@ void printStats(PrintStream out) {
191148
}
192149

193150
public List<Throwable> getErrors() {
194-
return errors;
151+
return stats.getErrors();
195152
}
196153

197154
public byte exitStatus() {
198-
byte result = 0x0;
199-
if (hasErrors() || hasUndefinedOrPendingStepsAndIsStrict()) {
200-
result |= ERRORS;
201-
}
202-
return result;
203-
}
204-
205-
private boolean hasUndefinedOrPendingStepsAndIsStrict() {
206-
return runtimeOptions.isStrict() && hasUndefinedOrPendingSteps();
207-
}
208-
209-
private boolean hasUndefinedOrPendingSteps() {
210-
return hasUndefinedSteps() || hasPendingSteps();
211-
}
212-
213-
private boolean hasUndefinedSteps() {
214-
return undefinedStepsTracker.hasUndefinedSteps();
215-
}
216-
217-
private boolean hasPendingSteps() {
218-
return !errors.isEmpty() && !hasErrors();
219-
}
220-
221-
private boolean hasErrors() {
222-
for (Throwable error : errors) {
223-
if (!isPending(error) && !isAssumptionViolated(error)) {
224-
return true;
225-
}
226-
}
227-
return false;
155+
return stats.exitStatus(runtimeOptions.isStrict());
228156
}
229157

230158
public List<String> getSnippets() {
@@ -235,28 +163,6 @@ public Glue getGlue() {
235163
return runner.getGlue();
236164
}
237165

238-
public static boolean isPending(Throwable t) {
239-
if (t == null) {
240-
return false;
241-
}
242-
return t.getClass().isAnnotationPresent(Pending.class);
243-
}
244-
245-
public static boolean isAssumptionViolated(Throwable t) {
246-
if (t == null) {
247-
return false;
248-
}
249-
return Arrays.binarySearch(ASSUMPTION_VIOLATED_EXCEPTIONS, t.getClass().getName()) >= 0;
250-
}
251-
252-
private void addStepToCounterAndResult(Result result) {
253-
stats.addStep(result);
254-
}
255-
256-
private void addHookToCounterAndResult(Result result) {
257-
stats.addHookTime(result.getDuration());
258-
}
259-
260166
public EventBus getEventBus() {
261167
return bus;
262168
}

core/src/main/java/cucumber/runtime/RuntimeOptions.java

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import cucumber.api.SnippetType;
44
import cucumber.api.StepDefinitionReporter;
55
import cucumber.api.SummaryPrinter;
6+
import cucumber.api.event.TestRunStarted;
67
import cucumber.api.formatter.ColorAware;
78
import cucumber.api.formatter.Formatter;
89
import cucumber.api.formatter.StrictAware;
@@ -308,6 +309,7 @@ private void addKeywordRow(List<List<String>> table, String key, List<String> ke
308309
public List<CucumberFeature> cucumberFeatures(ResourceLoader resourceLoader, EventBus bus) {
309310
List<CucumberFeature> features = load(resourceLoader, featurePaths, System.out);
310311
getPlugins(); // to create the formatter objects
312+
bus.send(new TestRunStarted(bus.getTime()));
311313
for (CucumberFeature feature : features) {
312314
feature.sendTestSourceRead(bus);
313315
}

core/src/main/java/cucumber/runtime/Stats.java

+75-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package cucumber.runtime;
22

33
import cucumber.api.Result;
4+
import cucumber.api.event.EventHandler;
5+
import cucumber.api.event.EventListener;
6+
import cucumber.api.event.EventPublisher;
7+
import cucumber.api.event.TestCaseFinished;
8+
import cucumber.api.event.TestRunFinished;
9+
import cucumber.api.event.TestRunStarted;
10+
import cucumber.api.event.TestStepFinished;
411
import cucumber.runtime.formatter.AnsiFormats;
512
import cucumber.runtime.formatter.Format;
613
import cucumber.runtime.formatter.Formats;
@@ -13,18 +20,51 @@
1320
import java.util.List;
1421
import java.util.Locale;
1522

16-
class Stats {
23+
class Stats implements EventListener {
1724
public static final long ONE_SECOND = 1000000000;
1825
public static final long ONE_MINUTE = 60 * ONE_SECOND;
26+
private static final byte ERRORS = 0x1;
1927
private SubCounts scenarioSubCounts = new SubCounts();
2028
private SubCounts stepSubCounts = new SubCounts();
29+
private long startTime = 0;
2130
private long totalDuration = 0;
2231
private Formats formats;
2332
private Locale locale;
24-
private List<String> failedScenarios = new ArrayList<String>();
33+
private final List<String> failedScenarios = new ArrayList<String>();
2534
private List<String> ambiguousScenarios = new ArrayList<String>();
26-
private List<String> pendingScenarios = new ArrayList<String>();
27-
private List<String> undefinedScenarios = new ArrayList<String>();
35+
private final List<String> pendingScenarios = new ArrayList<String>();
36+
private final List<String> undefinedScenarios = new ArrayList<String>();
37+
private final List<Throwable> errors = new ArrayList<Throwable>();
38+
private final EventHandler<TestRunStarted> testRunStartedHandler = new EventHandler<TestRunStarted>() {
39+
@Override
40+
public void receive(TestRunStarted event) {
41+
setStartTime(event.getTimeStamp());
42+
}
43+
};
44+
private final EventHandler<TestStepFinished> stepFinishedHandler = new EventHandler<TestStepFinished>() {
45+
@Override
46+
public void receive(TestStepFinished event) {
47+
Result result = event.result;
48+
if (result.getError() != null) {
49+
addError(result.getError());
50+
}
51+
if (!event.testStep.isHook()) {
52+
addStep(result.getStatus());
53+
}
54+
}
55+
};
56+
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
57+
@Override
58+
public void receive(TestCaseFinished event) {
59+
addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation());
60+
}
61+
};
62+
private final EventHandler<TestRunFinished> testRunFinishedHandler = new EventHandler<TestRunFinished>() {
63+
@Override
64+
public void receive(TestRunFinished event) {
65+
setFinishTime(event.getTimeStamp());
66+
}
67+
};
2868

2969
public Stats(boolean monochrome) {
3070
this(monochrome, Locale.getDefault());
@@ -39,6 +79,27 @@ public Stats(boolean monochrome, Locale locale) {
3979
}
4080
}
4181

82+
83+
@Override
84+
public void setEventPublisher(EventPublisher publisher) {
85+
publisher.registerHandlerFor(TestRunStarted.class, testRunStartedHandler);
86+
publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
87+
publisher.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
88+
publisher.registerHandlerFor(TestRunFinished.class, testRunFinishedHandler);
89+
}
90+
91+
public List<Throwable> getErrors() {
92+
return errors;
93+
}
94+
95+
public byte exitStatus(boolean isStrict) {
96+
byte result = 0x0;
97+
if (!failedScenarios.isEmpty() || (isStrict && (!pendingScenarios.isEmpty() || !undefinedScenarios.isEmpty()))) {
98+
result |= ERRORS;
99+
}
100+
return result;
101+
}
102+
42103
public void printStats(PrintStream out, boolean isStrict) {
43104
printNonZeroResultScenarios(out, isStrict);
44105
if (stepSubCounts.getTotal() == 0) {
@@ -119,21 +180,20 @@ private void printScenarios(PrintStream out, List<String> scenarios, Result.Type
119180
}
120181
}
121182

122-
public void addStep(Result result) {
123-
addResultToSubCount(stepSubCounts, result.getStatus());
124-
addTime(result.getDuration());
183+
void addStep(Result.Type resultStatus) {
184+
addResultToSubCount(stepSubCounts, resultStatus);
125185
}
126186

127-
public void addScenario(Result.Type resultStatus) {
128-
addResultToSubCount(scenarioSubCounts, resultStatus);
187+
private void addError(Throwable error) {
188+
errors.add(error);
129189
}
130190

131-
public void addHookTime(Long duration) {
132-
addTime(duration);
191+
void setStartTime(Long startTime) {
192+
this.startTime = startTime;
133193
}
134194

135-
private void addTime(Long duration) {
136-
totalDuration += duration != null ? duration : 0;
195+
void setFinishTime(Long finishTime) {
196+
this.totalDuration = finishTime - startTime;
137197
}
138198

139199
private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus) {
@@ -158,7 +218,7 @@ private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus)
158218
}
159219
}
160220

161-
public void addScenario(Result.Type resultStatus, String scenarioDesignation) {
221+
void addScenario(Result.Type resultStatus, String scenarioDesignation) {
162222
addResultToSubCount(scenarioSubCounts, resultStatus);
163223
switch (resultStatus) {
164224
case FAILED:
@@ -178,7 +238,7 @@ public void addScenario(Result.Type resultStatus, String scenarioDesignation) {
178238
}
179239
}
180240

181-
class SubCounts {
241+
static class SubCounts {
182242
public int passed = 0;
183243
public int failed = 0;
184244
public int ambiguous = 0;

0 commit comments

Comments
 (0)