Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the PrettyFormatter work by reverting to all-steps-first execution #557

Merged
merged 5 commits into from
Jul 16, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions core/src/main/java/cucumber/runtime/Runtime.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,24 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOp
}

public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection<? extends Backend> backends, RuntimeOptions runtimeOptions) {
this.resourceLoader = resourceLoader;
this.classLoader = classLoader;
this(resourceLoader, classLoader, backends, runtimeOptions, null);
}

public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection<? extends Backend> backends,
RuntimeOptions runtimeOptions, RuntimeGlue optionalGlue) {
if (backends.isEmpty()) {
throw new CucumberException("No backends were found. Please make sure you have a backend module on your CLASSPATH.");
}
this.resourceLoader = resourceLoader;
this.classLoader = classLoader;
this.backends = backends;
glue = new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader));
this.runtimeOptions = runtimeOptions;
this.glue = optionalGlue != null ? optionalGlue : new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader));

for (Backend backend : backends) {
backend.loadGlue(glue, runtimeOptions.getGlue());
backend.setUnreportedStepExecutor(this);
}
this.runtimeOptions = runtimeOptions;
}

private static Collection<? extends Backend> loadBackends(ResourceLoader resourceLoader, ClassLoader classLoader) {
Expand Down
113 changes: 77 additions & 36 deletions core/src/main/java/cucumber/runtime/formatter/JUnitFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class JUnitFormatter implements Formatter, Reporter, StrictAware {

public JUnitFormatter(URL out) throws IOException {
this.out = new UTF8OutputStreamWriter(new URLOutputStream(out));
TestCase.treatSkippedAsFailure = false;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
rootElement = doc.createElement("testsuite");
Expand All @@ -62,13 +63,15 @@ public void feature(Feature feature) {

@Override
public void background(Background background) {
testCase = new TestCase();
root = testCase.createElement(doc);
if (!isCurrentTestCaseCreatedNameless()) {
testCase = new TestCase();
root = testCase.createElement(doc);
}
}

@Override
public void scenario(Scenario scenario) {
if (testCase != null && testCase.scenario == null) {
if (isCurrentTestCaseCreatedNameless()) {
testCase.scenario = scenario;
} else {
testCase = new TestCase(scenario);
Expand All @@ -80,6 +83,10 @@ public void scenario(Scenario scenario) {
increaseAttributeValue(rootElement, "tests");
}

private boolean isCurrentTestCaseCreatedNameless() {
return testCase != null && testCase.scenario == null;
}

@Override
public void step(Step step) {
if (testCase != null) testCase.steps.add(step);
Expand Down Expand Up @@ -110,6 +117,10 @@ public void result(Result result) {

@Override
public void before(Match match, Result result) {
if (!isCurrentTestCaseCreatedNameless()) {
testCase = new TestCase();
root = testCase.createElement(doc);
}
handleHook(result);
}

Expand All @@ -119,10 +130,8 @@ public void after(Match match, Result result) {
}

private void handleHook(Result result) {
if (result.getStatus().equals(Result.FAILED)) {
testCase.results.add(result);
}

testCase.hookResults.add(result);
testCase.updateElement(doc, root);
}

private void increaseAttributeValue(Element element, String attribute) {
Expand All @@ -135,6 +144,7 @@ private void increaseAttributeValue(Element element, String attribute) {

@Override
public void scenarioOutline(ScenarioOutline scenarioOutline) {
testCase = null;
}

@Override
Expand Down Expand Up @@ -195,6 +205,7 @@ private TestCase() {
static boolean treatSkippedAsFailure = false;
final List<Step> steps = new ArrayList<Step>();
final List<Result> results = new ArrayList<Result>();
final List<Result> hookResults = new ArrayList<Result>();

private Element createElement(Document doc) {
return doc.createElement("testcase");
Expand All @@ -206,49 +217,31 @@ private void writeElement(Document doc, Element tc) {
}

public void updateElement(Document doc, Element tc) {
long totalDurationNanos = 0;
for (Result r : results) {
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
}

double totalDurationSeconds = ((double) totalDurationNanos) / 1000000000;
String time = NUMBER_FORMAT.format(totalDurationSeconds);
tc.setAttribute("time", time);
tc.setAttribute("time", calculateTotalDurationString());

StringBuilder sb = new StringBuilder();
addStepAndResultListing(sb);
Result skipped = null, failed = null;
for (int i = 0; i < steps.size(); i++) {
int length = sb.length();
Result result = results.get(i);
for (Result result : results) {
if ("failed".equals(result.getStatus())) failed = result;
if ("undefined".equals(result.getStatus()) || "pending".equals(result.getStatus())) skipped = result;
sb.append(steps.get(i).getKeyword());
sb.append(steps.get(i).getName());
for (int j = 0; sb.length() - length + j < 140; j++) sb.append(".");
sb.append(result.getStatus());
sb.append("\n");
}
for (Result result : hookResults) {
if (failed == null && "failed".equals(result.getStatus())) failed = result;
}
Element child;
if (failed != null) {
sb.append("\nStackTrace:\n");
StringWriter sw = new StringWriter();
failed.getError().printStackTrace(new PrintWriter(sw));
sb.append(sw.toString());
child = doc.createElement("failure");
child.setAttribute("message", failed.getErrorMessage());
child.appendChild(doc.createCDATASection(sb.toString()));
addStackTrace(sb, failed);
child = createElementWithMessage(doc, sb, "failure", failed.getErrorMessage());
} else if (skipped != null) {
if (treatSkippedAsFailure) {
child = doc.createElement("failure");
child.setAttribute("message", "The scenario has pending or undefined step(s)");
child = createElementWithMessage(doc, sb, "failure", "The scenario has pending or undefined step(s)");
}
else {
child = doc.createElement("skipped");
child = createElement(doc, sb, "skipped");
}
child.appendChild(doc.createCDATASection(sb.toString()));
} else {
child = doc.createElement("system-out");
child.appendChild(doc.createCDATASection(sb.toString()));
child = createElement(doc, sb, "system-out");
}

Node existingChild = tc.getFirstChild();
Expand All @@ -259,6 +252,54 @@ public void updateElement(Document doc, Element tc) {
}
}

private String calculateTotalDurationString() {
long totalDurationNanos = 0;
for (Result r : results) {
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
}
for (Result r : hookResults) {
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
}
double totalDurationSeconds = ((double) totalDurationNanos) / 1000000000;
return NUMBER_FORMAT.format(totalDurationSeconds);
}

private void addStepAndResultListing(StringBuilder sb) {
for (int i = 0; i < steps.size(); i++) {
int length = sb.length();
String resultStatus = "not executed";
if (i < results.size()) {
resultStatus = results.get(i).getStatus();
}
sb.append(steps.get(i).getKeyword());
sb.append(steps.get(i).getName());
do {
sb.append(".");
} while (sb.length() - length < 76);
sb.append(resultStatus);
sb.append("\n");
}
}

private void addStackTrace(StringBuilder sb, Result failed) {
sb.append("\nStackTrace:\n");
StringWriter sw = new StringWriter();
failed.getError().printStackTrace(new PrintWriter(sw));
sb.append(sw.toString());
}

private Element createElementWithMessage(Document doc, StringBuilder sb, String elementType, String message) {
Element child = createElement(doc, sb, elementType);
child.setAttribute("message", message);
return child;
}

private Element createElement(Document doc, StringBuilder sb, String elementType) {
Element child = doc.createElement(elementType);
child.appendChild(doc.createCDATASection(sb.toString()));
return child;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void run(Formatter formatter, Reporter reporter, Runtime runtime) {

runBackground(formatter, reporter, runtime);
format(formatter);
runSteps(formatter, reporter, runtime);
runSteps(reporter, runtime);

runtime.runAfterHooks(reporter, tags);
runtime.disposeBackendWorlds();
Expand All @@ -46,7 +46,7 @@ public void run(Formatter formatter, Reporter reporter, Runtime runtime) {
private void runBackground(Formatter formatter, Reporter reporter, Runtime runtime) {
if (cucumberBackground != null) {
cucumberBackground.format(formatter);
cucumberBackground.runSteps(formatter, reporter, runtime);
cucumberBackground.runSteps(reporter, runtime);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public List<CucumberExamples> getCucumberExamplesList() {
@Override
public void run(Formatter formatter, Reporter reporter, Runtime runtime) {
format(formatter);
formatSteps(formatter);
for (CucumberExamples cucumberExamples : cucumberExamplesList) {
cucumberExamples.format(formatter);
List<CucumberScenario> exampleScenarios = cucumberExamples.createExampleScenarios();
Expand Down
10 changes: 3 additions & 7 deletions core/src/main/java/cucumber/runtime/model/StepContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,18 @@ public void step(Step step) {

void format(Formatter formatter) {
statement.replay(formatter);
}

void formatSteps(Formatter formatter) {
for (Step step : getSteps()) {
formatter.step(step);
}
}

void runSteps(Formatter formatter, Reporter reporter, Runtime runtime) {
void runSteps(Reporter reporter, Runtime runtime) {
for (Step step : getSteps()) {
runStep(step, formatter, reporter, runtime);
runStep(step, reporter, runtime);
}
}

void runStep(Step step, Formatter formatter, Reporter reporter, Runtime runtime) {
formatter.step(step);
void runStep(Step step, Reporter reporter, Runtime runtime) {
runtime.runStep(cucumberFeature.getUri(), step, reporter, cucumberFeature.getI18n());
}
}
14 changes: 14 additions & 0 deletions core/src/test/java/cucumber/runtime/RuntimeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import static cucumber.runtime.TestHelper.feature;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;

public class RuntimeTest {
Expand Down Expand Up @@ -163,6 +165,18 @@ public void strict_with_errors() {
assertEquals(0x1, runtime.exitStatus());
}

@Test
public void should_throw_cucumer_exception_if_no_backends_are_found() throws Exception {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
new Runtime(new ClasspathResourceLoader(classLoader), classLoader, Collections.<Backend>emptyList(),
new RuntimeOptions(new Properties()));
fail("A CucumberException should have been thrown");
} catch (CucumberException e) {
assertEquals("No backends were found. Please make sure you have a backend module on your CLASSPATH.", e.getMessage());
}
}

private Runtime createStrictRuntime() {
return createRuntime("-g", "anything", "--strict");
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/cucumber/runtime/TestHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@Ignore
public class TestHelper {
static CucumberFeature feature(final String path, final String source) throws IOException {
public static CucumberFeature feature(final String path, final String source) throws IOException {
ArrayList<CucumberFeature> cucumberFeatures = new ArrayList<CucumberFeature>();
FeatureBuilder featureBuilder = new FeatureBuilder(cucumberFeatures);
featureBuilder.parse(new Resource() {
Expand Down
Loading