From 5fb1b76126f03746dddc62505ece4f0fe001943a Mon Sep 17 00:00:00 2001 From: brasmusson Date: Sat, 1 Jun 2013 21:09:09 +0200 Subject: [PATCH 1/6] Print summary at the end of the run Print the same kind of summary at the end of the run as Cucumber-Ruby: x Scenarios (x1 failed, x2 skipped, x3 pending, x4 undefined, x5 passed) y Steps (y1 failed, y2 skipped, y3 pending, y4 undefined, y5 passed) XmY.YYYs The new class SummaryCounter is used by the Runtime class to collect the data for the summary. The SummaryPrinter then let the SummaryCounter print the summary before the errors and the snippets. The printout from the SummaryPrinter is moved to after the printout from the formatters to make the summary printed after the progress or pretty printout. --- .../main/java/cucumber/runtime/Runtime.java | 51 ++++- .../java/cucumber/runtime/ScenarioImpl.java | 2 +- .../java/cucumber/runtime/SummaryCounter.java | 135 +++++++++++ .../runtime/snippets/SummaryPrinter.java | 6 + .../java/cucumber/runtime/RuntimeTest.java | 216 ++++++++++++++++++ .../cucumber/runtime/ScenarioResultTest.java | 19 +- .../cucumber/runtime/SummaryCounterTest.java | 172 ++++++++++++++ .../java/cucumber/api/junit/Cucumber.java | 2 +- 8 files changed, 587 insertions(+), 16 deletions(-) create mode 100755 core/src/main/java/cucumber/runtime/SummaryCounter.java create mode 100755 core/src/test/java/cucumber/runtime/SummaryCounterTest.java diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 56cc9f7164..24e31e139a 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -42,7 +42,8 @@ public class Runtime implements UnreportedStepExecutor { private static final Object DUMMY_ARG = new Object(); private static final byte ERRORS = 0x1; - final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + private final SummaryCounter summaryCounter; + final UndefinedStepsTracker undefinedStepsTracker; private final Glue glue; private final RuntimeOptions runtimeOptions; @@ -62,19 +63,29 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOp } public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions) { + this(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker()); + } + + public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, + RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker) { + this(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, + new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + } + + public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, + RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker, RuntimeGlue glue) { this.resourceLoader = resourceLoader; this.classLoader = classLoader; - if (backends.isEmpty()) { - throw new CucumberException("No backends were found. Please make sure you have a backend module on your CLASSPATH."); - } this.backends = backends; - glue = new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader)); + this.runtimeOptions = runtimeOptions; + this.undefinedStepsTracker = undefinedStepsTracker; + this.glue = glue; + this.summaryCounter = new SummaryCounter(runtimeOptions.monochrome); for (Backend backend : backends) { backend.loadGlue(glue, runtimeOptions.glue); backend.setUnreportedStepExecutor(this); } - this.runtimeOptions = runtimeOptions; } private static Collection loadBackends(ResourceLoader resourceLoader, ClassLoader classLoader) { @@ -95,8 +106,8 @@ public void run() { Formatter formatter = runtimeOptions.formatter(classLoader); formatter.done(); - printSummary(); formatter.close(); + printSummary(); } private void run(CucumberFeature cucumberFeature) { @@ -121,6 +132,7 @@ public void buildBackendWorlds(Reporter reporter, Set tags) { } public void disposeBackendWorlds() { + summaryCounter.addScenario(scenarioResult.getStatus()); for (Backend backend : backends) { backend.disposeWorld(); } @@ -203,7 +215,7 @@ private void runHookIfTagsMatch(HookDefinition hook, Reporter reporter, Set } finally { long duration = System.nanoTime() - start; Result result = new Result(status, duration, error, DUMMY_ARG); - scenarioResult.add(result); + addHookToCounterAndResult(result); if (isBefore) { reporter.before(match, result); } else { @@ -240,7 +252,9 @@ public void runStep(String uri, Step step, Reporter reporter, I18n i18n) { match = glue.stepDefinitionMatch(uri, step, i18n); } catch (AmbiguousStepDefinitionsException e) { reporter.match(e.getMatches().get(0)); - reporter.result(new Result(Result.FAILED, 0L, e, DUMMY_ARG)); + Result result = new Result(Result.FAILED, 0L, e, DUMMY_ARG); + reporter.result(result); + addStepToCounterAndResult(result); addError(e); skipNextStep = true; return; @@ -251,6 +265,7 @@ public void runStep(String uri, Step step, Reporter reporter, I18n i18n) { } else { reporter.match(Match.UNDEFINED); reporter.result(Result.UNDEFINED); + addStepToCounterAndResult(Result.UNDEFINED); skipNextStep = true; return; } @@ -260,7 +275,7 @@ public void runStep(String uri, Step step, Reporter reporter, I18n i18n) { } if (skipNextStep) { - scenarioResult.add(Result.SKIPPED); + addStepToCounterAndResult(Result.SKIPPED); reporter.result(Result.SKIPPED); } else { String status = Result.PASSED; @@ -276,7 +291,7 @@ public void runStep(String uri, Step step, Reporter reporter, I18n i18n) { } finally { long duration = System.nanoTime() - start; Result result = new Result(status, duration, error, DUMMY_ARG); - scenarioResult.add(result); + addStepToCounterAndResult(result); reporter.result(result); } } @@ -292,4 +307,18 @@ public static boolean isPending(Throwable t) { public void writeStepdefsJson() throws IOException { glue.writeStepdefsJson(runtimeOptions.featurePaths, runtimeOptions.dotCucumber); } + + public SummaryCounter getSummaryCounter() { + return summaryCounter; + } + + private void addStepToCounterAndResult(Result result) { + scenarioResult.add(result); + summaryCounter.addStep(result); + } + + private void addHookToCounterAndResult(Result result) { + scenarioResult.add(result); + summaryCounter.addHookTime(result.getDuration()); + } } diff --git a/core/src/main/java/cucumber/runtime/ScenarioImpl.java b/core/src/main/java/cucumber/runtime/ScenarioImpl.java index 6939cc4dd1..513cbd95df 100644 --- a/core/src/main/java/cucumber/runtime/ScenarioImpl.java +++ b/core/src/main/java/cucumber/runtime/ScenarioImpl.java @@ -14,7 +14,7 @@ import static java.util.Arrays.asList; public class ScenarioImpl implements Scenario { - private static final List SEVERITY = asList("passed", "undefined", "pending", "skipped", "failed"); + private static final List SEVERITY = asList("passed", "skipped", "undefined", "pending", "failed"); private final List stepResults = new ArrayList(); private final Reporter reporter; private final Set tags; diff --git a/core/src/main/java/cucumber/runtime/SummaryCounter.java b/core/src/main/java/cucumber/runtime/SummaryCounter.java new file mode 100755 index 0000000000..4b1b758854 --- /dev/null +++ b/core/src/main/java/cucumber/runtime/SummaryCounter.java @@ -0,0 +1,135 @@ +package cucumber.runtime; + +import gherkin.formatter.AnsiFormats; +import gherkin.formatter.Format; +import gherkin.formatter.Formats; +import gherkin.formatter.MonochromeFormats; +import gherkin.formatter.model.Result; + +import java.io.PrintStream; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class SummaryCounter { + public static final long ONE_SECOND = 1000000000; + public static final long ONE_MINUTE = 60 * ONE_SECOND; + public static final String PENDING = "pending"; + private SubCounts scenarioSubCounts = new SubCounts(); + private SubCounts stepSubCounts = new SubCounts(); + private long totalDuration = 0; + private Formats formats; + private Locale locale; + + public SummaryCounter(boolean monochrome) { + this(monochrome, Locale.getDefault()); + } + + public SummaryCounter(boolean monochrome, Locale locale) { + this.locale = locale; + if (monochrome) { + formats = new MonochromeFormats(); + } else { + formats = new AnsiFormats(); + } + } + + public void printSummary(PrintStream out) { + if (stepSubCounts.getTotal() == 0) { + out.println("0 Scenarios"); + out.println("0 Steps"); + } else { + printScenarioCounts(out); + printStepCounts(out); + } + printDuration(out); + } + + private void printStepCounts(PrintStream out) { + out.print(stepSubCounts.getTotal()); + out.print(" Steps ("); + printSubCounts(out, stepSubCounts); + out.println(")"); + } + + private void printScenarioCounts(PrintStream out) { + out.print(scenarioSubCounts.getTotal()); + out.print(" Scenarios ("); + printSubCounts(out, scenarioSubCounts); + out.println(")"); + } + + private void printSubCounts(PrintStream out, SubCounts subCounts) { + boolean addComma = false; + addComma = printSubCount(out, subCounts.failed, Result.FAILED, addComma); + addComma = printSubCount(out, subCounts.skipped, Result.SKIPPED.getStatus(), addComma); + addComma = printSubCount(out, subCounts.pending, PENDING, addComma); + addComma = printSubCount(out, subCounts.undefined, Result.UNDEFINED.getStatus(), addComma); + addComma = printSubCount(out, subCounts.passed, Result.PASSED, addComma); + } + + private boolean printSubCount(PrintStream out, int count, String type, boolean addComma) { + if (count != 0) { + if (addComma) { + out.print(", "); + } + Format format = formats.get(type); + out.print(format.text(count + " " + type)); + addComma = true; + } + return addComma; + } + + private void printDuration(PrintStream out) { + out.print(String.format("%dm", (totalDuration/ONE_MINUTE))); + DecimalFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(locale)); + out.println(format.format(((double)(totalDuration%ONE_MINUTE))/ONE_SECOND) + "s"); + } + + public void addStep(Result result) { + addResultToSubCount(stepSubCounts, result.getStatus()); + // the following constant defined in the Gherkin libaray have duration == null, so calls to getDuration() + // will result in a NullPointerException + if (!result.equals(Result.SKIPPED) && !result.equals(Result.UNDEFINED)) { + addTime(result.getDuration()); + } + } + + public void addScenario(String resultStatus) { + addResultToSubCount(scenarioSubCounts, resultStatus); + } + + public void addHookTime(long duration) { + addTime(duration); + } + + private void addTime(long duration) { + totalDuration += duration; + } + + private void addResultToSubCount(SubCounts subCounts, String resultStatus) { + if (resultStatus.equals(Result.FAILED)) { + subCounts.failed++; + } else if (resultStatus.equals(PENDING)) { + subCounts.pending++; + } else if (resultStatus.equals(Result.UNDEFINED.getStatus())) { + subCounts.undefined++; + } else if (resultStatus.equals(Result.SKIPPED.getStatus())) { + subCounts.skipped++; + } else if (resultStatus.equals(Result.PASSED)) { + subCounts.passed++; + } + } +} + +class SubCounts { + public int passed = 0; + public int failed = 0; + public int skipped = 0; + public int pending = 0; + public int undefined = 0; + + public int getTotal() { + return passed + failed + skipped + pending + undefined; + } +} diff --git a/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java b/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java index 823b117a96..4037610852 100644 --- a/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java +++ b/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java @@ -11,11 +11,17 @@ public SummaryPrinter(PrintStream out) { } public void print(cucumber.runtime.Runtime runtime) { + out.println(); + printSummary(runtime); out.println(); printErrors(runtime); printSnippets(runtime); } + private void printSummary(cucumber.runtime.Runtime runtime) { + runtime.getSummaryCounter().printSummary(out); + } + private void printErrors(cucumber.runtime.Runtime runtime) { for (Throwable error : runtime.getErrors()) { error.printStackTrace(out); diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index bc092ceb3b..82858d05a6 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -1,25 +1,39 @@ package cucumber.runtime; import cucumber.api.PendingException; +import cucumber.api.Scenario; import cucumber.runtime.io.ClasspathResourceLoader; import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.model.CucumberFeature; import gherkin.I18n; import gherkin.formatter.JSONFormatter; +import gherkin.formatter.Reporter; import gherkin.formatter.model.Step; +import gherkin.formatter.model.Tag; + import org.junit.Ignore; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; 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.hamcrest.CoreMatchers.startsWith; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyCollectionOf; +import static org.mockito.Matchers.anyString; public class RuntimeTest { @@ -163,6 +177,164 @@ public void strict_with_errors() { assertEquals(0x1, runtime.exitStatus()); } + @Test + public void should_add_passed_result_to_the_summary_counter() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = mock(StepDefinitionMatch.class); + + Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 passed)" + System.lineSeparator() + + "1 Steps (1 passed)" + System.lineSeparator())); + } + + @Test + public void should_add_pending_result_to_the_summary_counter() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = createExceptionThrowingMatch(new PendingException()); + + Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 pending)" + System.lineSeparator() + + "1 Steps (1 pending)" + System.lineSeparator())); + } + + @Test + public void should_add_failed_result_to_the_summary_counter() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = createExceptionThrowingMatch(new Exception()); + + Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 failed)" + System.lineSeparator() + + "1 Steps (1 failed)" + System.lineSeparator())); + } + + @Test + public void should_add_ambiguous_match_as_failed_result_to_the_summary_counter() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + + Runtime runtime = createRuntimeWithMockedGlueWithAmbiguousMatch("--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 failed)" + System.lineSeparator() + + "1 Steps (1 failed)" + System.lineSeparator())); + } + + @Test + public void should_add_skipped_result_to_the_summary_counter() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = createExceptionThrowingMatch(new Exception()); + + Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 failed)" + System.lineSeparator() + + "2 Steps (1 failed, 1 skipped)" + System.lineSeparator())); + } + + @Test + public void should_add_undefined_result_to_the_summary_counter() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + + Runtime runtime = createRuntimeWithMockedGlue(null, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 undefined)" + System.lineSeparator() + + "1 Steps (1 undefined)" + System.lineSeparator())); + } + + @Test + public void should_fail_the_scenario_if_before_fails() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = mock(StepDefinitionMatch.class); + HookDefinition hook = createExceptionThrowingHook(); + + Runtime runtime = createRuntimeWithMockedGlue(match, hook, true, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runtime.runBeforeHooks(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 failed)" + System.lineSeparator() + + "1 Steps (1 skipped)" + System.lineSeparator())); + } + + @Test + public void should_fail_the_scenario_if_after_fails() throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Reporter reporter = mock(Reporter.class); + StepDefinitionMatch match = mock(StepDefinitionMatch.class); + HookDefinition hook = createExceptionThrowingHook(); + + Runtime runtime = createRuntimeWithMockedGlue(match, hook, false, "--monochrome"); + runtime.buildBackendWorlds(reporter, Collections.emptySet()); + runStep(reporter, runtime); + runtime.runAfterHooks(reporter, Collections.emptySet()); + runtime.disposeBackendWorlds(); + runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 failed)" + System.lineSeparator() + + "1 Steps (1 passed)" + System.lineSeparator())); + } + + private StepDefinitionMatch createExceptionThrowingMatch(Exception exception) throws Throwable { + StepDefinitionMatch match = mock(StepDefinitionMatch.class); + doThrow(exception).when(match).runStep((I18n)any()); + return match; + } + + private HookDefinition createExceptionThrowingHook() throws Throwable { + HookDefinition hook = mock(HookDefinition.class); + when(hook.matches(anyCollectionOf(Tag.class))).thenReturn(true); + doThrow(new Exception()).when(hook).execute((Scenario)any()); + return hook; + } + + public void runStep(Reporter reporter, Runtime runtime) { + Step step = mock(Step.class); + I18n i18n = mock(I18n.class); + runtime.runStep("", step, reporter, i18n); + } + private Runtime createStrictRuntime() { return createRuntime("-g", "anything", "--strict"); } @@ -180,4 +352,48 @@ private Runtime createRuntime(String... runtimeArgs) { return new Runtime(resourceLoader, classLoader, backends, runtimeOptions); } + + private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, String... runtimeArgs) { + return createRuntimeWithMockedGlue(match, false, null, false, runtimeArgs); + } + + private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, HookDefinition hook, boolean isBefore, + String... runtimeArgs){ + return createRuntimeWithMockedGlue(match, false, hook, isBefore, runtimeArgs); + } + + private Runtime createRuntimeWithMockedGlueWithAmbiguousMatch(String... runtimeArgs) { + return createRuntimeWithMockedGlue(mock(StepDefinitionMatch.class), true, null, false, runtimeArgs); + } + + private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, boolean isAmbiguous, HookDefinition hook, + boolean isBefore, String... runtimeArgs) { + ResourceLoader resourceLoader = mock(ResourceLoader.class); + ClassLoader classLoader = mock(ClassLoader.class); + RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties(), runtimeArgs); + Backend backend = mock(Backend.class); + RuntimeGlue glue = mock(RuntimeGlue.class); + mockMatch(glue, match, isAmbiguous); + mockHook(glue, hook, isBefore); + Collection backends = Arrays.asList(backend); + + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker(), glue); + } + + private void mockMatch(RuntimeGlue glue, StepDefinitionMatch match, boolean isAmbiguous) { + if (isAmbiguous) { + Exception exception = new AmbiguousStepDefinitionsException(Arrays.asList(match, match)); + doThrow(exception).when(glue).stepDefinitionMatch(anyString(), (Step)any(), (I18n)any()); + } else { + when(glue.stepDefinitionMatch(anyString(), (Step)any(), (I18n)any())).thenReturn(match); + } + } + + private void mockHook(RuntimeGlue glue, HookDefinition hook, boolean isBefore) { + if (isBefore) { + when(glue.getBeforeHooks()).thenReturn(Arrays.asList(hook)); + } else { + when(glue.getAfterHooks()).thenReturn(Arrays.asList(hook)); + } + } } diff --git a/core/src/test/java/cucumber/runtime/ScenarioResultTest.java b/core/src/test/java/cucumber/runtime/ScenarioResultTest.java index f53317dd8b..f2515c53dd 100644 --- a/core/src/test/java/cucumber/runtime/ScenarioResultTest.java +++ b/core/src/test/java/cucumber/runtime/ScenarioResultTest.java @@ -22,9 +22,12 @@ public void no_steps_is_passed() throws Exception { } @Test - public void passed_and_failed_is_passed() throws Exception { + public void passed_failed_pending_undefined_skipped_is_failed() throws Exception { s.add(new Result("passed", 0L, null, null)); s.add(new Result("failed", 0L, null, null)); + s.add(new Result("pending", 0L, null, null)); + s.add(new Result("undefined", 0L, null, null)); + s.add(new Result("skipped", 0L, null, null)); assertEquals("failed", s.getStatus()); } @@ -36,12 +39,22 @@ public void passed_and_skipped_is_skipped_although_we_cant_have_skipped_without_ } @Test - public void undefined_and_pending_is_pending() throws Exception { - s.add(new Result("undefined", 0L, null, null)); + public void passed_pending_undefined_skipped_is_pending() throws Exception { + s.add(new Result("passed", 0L, null, null)); s.add(new Result("pending", 0L, null, null)); + s.add(new Result("undefined", 0L, null, null)); + s.add(new Result("skipped", 0L, null, null)); assertEquals("pending", s.getStatus()); } + @Test + public void passed_undefined_skipped_is_undefined() throws Exception { + s.add(new Result("passed", 0L, null, null)); + s.add(new Result("undefined", 0L, null, null)); + s.add(new Result("skipped", 0L, null, null)); + assertEquals("undefined", s.getStatus()); + } + @Test public void embeds_data() { byte[] data = new byte[]{1, 2, 3}; diff --git a/core/src/test/java/cucumber/runtime/SummaryCounterTest.java b/core/src/test/java/cucumber/runtime/SummaryCounterTest.java new file mode 100755 index 0000000000..0d7c29d925 --- /dev/null +++ b/core/src/test/java/cucumber/runtime/SummaryCounterTest.java @@ -0,0 +1,172 @@ +package cucumber.runtime; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.startsWith; + +import gherkin.formatter.ansi.AnsiEscapes; +import gherkin.formatter.model.Result; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Locale; + +import org.junit.Test; + +public class SummaryCounterTest { + public static final long ONE_MILLI_SECOND = 1000000; + private static final long ONE_HOUR = 60 * SummaryCounter.ONE_MINUTE; + + @Test + public void should_print_zero_scenarios_zero_steps_if_nothing_has_executed() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "0 Scenarios" + System.lineSeparator() + + "0 Steps" + System.lineSeparator())); + } + + @Test + public void should_only_print_sub_counts_if_not_zero() { + SummaryCounter counter = createMonochromeSummaryCounter(); + Result passedResult = createResultWithStatus(Result.PASSED); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.addStep(passedResult); + counter.addStep(passedResult); + counter.addStep(passedResult); + counter.addScenario(Result.PASSED); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "1 Scenarios (1 passed)" + System.lineSeparator() + + "3 Steps (3 passed)" + System.lineSeparator())); + } + + @Test + public void should_print_sub_counts_in_order_failed_skipped_pending_undefined_passed() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + addOneStepScenario(counter, Result.PASSED); + addOneStepScenario(counter, Result.FAILED); + addOneStepScenario(counter, SummaryCounter.PENDING); + addOneStepScenario(counter, Result.UNDEFINED.getStatus()); + addOneStepScenario(counter, Result.SKIPPED.getStatus()); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), startsWith( + "5 Scenarios (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)" + System.lineSeparator() + + "5 Steps (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)" + System.lineSeparator())); + } + + @Test + public void should_print_sub_counts_in_order_failed_skipped_undefined_passed_in_color() { + SummaryCounter counter = createColorSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + addOneStepScenario(counter, Result.PASSED); + addOneStepScenario(counter, Result.FAILED); + addOneStepScenario(counter, SummaryCounter.PENDING); + addOneStepScenario(counter, Result.UNDEFINED.getStatus()); + addOneStepScenario(counter, Result.SKIPPED.getStatus()); + counter.printSummary(new PrintStream(baos)); + + String colorSubCounts = + AnsiEscapes.RED + "1 failed" + AnsiEscapes.RESET + ", " + + AnsiEscapes.CYAN + "1 skipped" + AnsiEscapes.RESET + ", " + + AnsiEscapes.YELLOW + "1 pending" + AnsiEscapes.RESET + ", " + + AnsiEscapes.YELLOW + "1 undefined" + AnsiEscapes.RESET + ", " + + AnsiEscapes.GREEN + "1 passed" + AnsiEscapes.RESET; + assertThat(baos.toString(), startsWith( + "5 Scenarios (" + colorSubCounts + ")" + System.lineSeparator() + + "5 Steps (" + colorSubCounts + ")" + System.lineSeparator())); + } + + @Test + public void should_print_zero_m_zero_s_if_nothing_has_executed() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), endsWith( + "0m0.000s" + System.lineSeparator())); + } + + @Test + public void should_include_hook_time_and_step_time_has_executed() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.addHookTime(ONE_MILLI_SECOND); + counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); + counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); + counter.addHookTime(ONE_MILLI_SECOND); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), endsWith( + "0m0.004s" + System.lineSeparator())); + } + + @Test + public void should_print_minutes_seconds_and_milliseconds() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_MINUTE, null)); + counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_SECOND, null)); + counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), endsWith( + "1m1.001s" + System.lineSeparator())); + } + + @Test + public void should_print_minutes_instead_of_hours() { + SummaryCounter counter = createMonochromeSummaryCounter(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.addStep(new Result(Result.PASSED, ONE_HOUR, null)); + counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_MINUTE, null)); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), endsWith( + "61m0.000s" + System.lineSeparator())); + } + + @Test + public void should_use_locale_for_decimal_separator() { + SummaryCounter counter = new SummaryCounter(true, Locale.GERMANY); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_MINUTE, null)); + counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_SECOND, null)); + counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); + counter.printSummary(new PrintStream(baos)); + + assertThat(baos.toString(), endsWith( + "1m1,001s" + System.lineSeparator())); + } + + private void addOneStepScenario(SummaryCounter counter, String status) { + counter.addStep(createResultWithStatus(status)); + counter.addScenario(status); + } + + private Result createResultWithStatus(String status) { + return new Result(status, 0l, null); + } + + private SummaryCounter createMonochromeSummaryCounter() { + return new SummaryCounter(true, Locale.US); + } + + private SummaryCounter createColorSummaryCounter() { + return new SummaryCounter(false, Locale.US); + } +} diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index 5787161b24..cdbbf82692 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -81,8 +81,8 @@ protected void runChild(FeatureRunner child, RunNotifier notifier) { public void run(RunNotifier notifier) { super.run(notifier); jUnitReporter.done(); - new SummaryPrinter(System.out).print(runtime); jUnitReporter.close(); + new SummaryPrinter(System.out).print(runtime); } private void addChildren(List cucumberFeatures) throws InitializationError { From 3b0f7bdb07efa1677ea40ca99f8067cb6a775db6 Mon Sep 17 00:00:00 2001 From: brasmusson Date: Wed, 5 Jun 2013 09:44:33 +0200 Subject: [PATCH 2/6] Use only jdk1.6 compliant constructs in the tests --- .../java/cucumber/runtime/RuntimeTest.java | 48 +++++++++---------- .../cucumber/runtime/SummaryCounterTest.java | 44 ++++++++--------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index 82858d05a6..b151da4762 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -189,9 +189,9 @@ public void should_add_passed_result_to_the_summary_counter() throws Exception { runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 passed)" + System.lineSeparator() + - "1 Steps (1 passed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 passed)%n" + + "1 Steps (1 passed)%n"))); } @Test @@ -206,9 +206,9 @@ public void should_add_pending_result_to_the_summary_counter() throws Throwable runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 pending)" + System.lineSeparator() + - "1 Steps (1 pending)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 pending)%n" + + "1 Steps (1 pending)%n"))); } @Test @@ -223,9 +223,9 @@ public void should_add_failed_result_to_the_summary_counter() throws Throwable { runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 failed)" + System.lineSeparator() + - "1 Steps (1 failed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 failed)%n" + + "1 Steps (1 failed)%n"))); } @Test @@ -239,9 +239,9 @@ public void should_add_ambiguous_match_as_failed_result_to_the_summary_counter() runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 failed)" + System.lineSeparator() + - "1 Steps (1 failed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 failed)%n" + + "1 Steps (1 failed)%n"))); } @Test @@ -257,9 +257,9 @@ public void should_add_skipped_result_to_the_summary_counter() throws Throwable runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 failed)" + System.lineSeparator() + - "2 Steps (1 failed, 1 skipped)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 failed)%n" + + "2 Steps (1 failed, 1 skipped)%n"))); } @Test @@ -273,9 +273,9 @@ public void should_add_undefined_result_to_the_summary_counter() throws Throwabl runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 undefined)" + System.lineSeparator() + - "1 Steps (1 undefined)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 undefined)%n" + + "1 Steps (1 undefined)%n"))); } @Test @@ -292,9 +292,9 @@ public void should_fail_the_scenario_if_before_fails() throws Throwable { runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 failed)" + System.lineSeparator() + - "1 Steps (1 skipped)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 failed)%n" + + "1 Steps (1 skipped)%n"))); } @Test @@ -311,9 +311,9 @@ public void should_fail_the_scenario_if_after_fails() throws Throwable { runtime.disposeBackendWorlds(); runtime.getSummaryCounter().printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 failed)" + System.lineSeparator() + - "1 Steps (1 passed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 failed)%n" + + "1 Steps (1 passed)%n"))); } private StepDefinitionMatch createExceptionThrowingMatch(Exception exception) throws Throwable { diff --git a/core/src/test/java/cucumber/runtime/SummaryCounterTest.java b/core/src/test/java/cucumber/runtime/SummaryCounterTest.java index 0d7c29d925..d611e5b457 100755 --- a/core/src/test/java/cucumber/runtime/SummaryCounterTest.java +++ b/core/src/test/java/cucumber/runtime/SummaryCounterTest.java @@ -24,9 +24,9 @@ public void should_print_zero_scenarios_zero_steps_if_nothing_has_executed() { counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "0 Scenarios" + System.lineSeparator() + - "0 Steps" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "0 Scenarios%n" + + "0 Steps%n"))); } @Test @@ -41,9 +41,9 @@ public void should_only_print_sub_counts_if_not_zero() { counter.addScenario(Result.PASSED); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "1 Scenarios (1 passed)" + System.lineSeparator() + - "3 Steps (3 passed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "1 Scenarios (1 passed)%n" + + "3 Steps (3 passed)%n"))); } @Test @@ -58,9 +58,9 @@ public void should_print_sub_counts_in_order_failed_skipped_pending_undefined_pa addOneStepScenario(counter, Result.SKIPPED.getStatus()); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), startsWith( - "5 Scenarios (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)" + System.lineSeparator() + - "5 Steps (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "5 Scenarios (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)%n" + + "5 Steps (1 failed, 1 skipped, 1 pending, 1 undefined, 1 passed)%n"))); } @Test @@ -81,9 +81,9 @@ public void should_print_sub_counts_in_order_failed_skipped_undefined_passed_in_ AnsiEscapes.YELLOW + "1 pending" + AnsiEscapes.RESET + ", " + AnsiEscapes.YELLOW + "1 undefined" + AnsiEscapes.RESET + ", " + AnsiEscapes.GREEN + "1 passed" + AnsiEscapes.RESET; - assertThat(baos.toString(), startsWith( - "5 Scenarios (" + colorSubCounts + ")" + System.lineSeparator() + - "5 Steps (" + colorSubCounts + ")" + System.lineSeparator())); + assertThat(baos.toString(), startsWith(String.format( + "5 Scenarios (" + colorSubCounts + ")%n" + + "5 Steps (" + colorSubCounts + ")%n"))); } @Test @@ -93,8 +93,8 @@ public void should_print_zero_m_zero_s_if_nothing_has_executed() { counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), endsWith( - "0m0.000s" + System.lineSeparator())); + assertThat(baos.toString(), endsWith(String.format( + "0m0.000s%n"))); } @Test @@ -108,8 +108,8 @@ public void should_include_hook_time_and_step_time_has_executed() { counter.addHookTime(ONE_MILLI_SECOND); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), endsWith( - "0m0.004s" + System.lineSeparator())); + assertThat(baos.toString(), endsWith(String.format( + "0m0.004s%n"))); } @Test @@ -122,8 +122,8 @@ public void should_print_minutes_seconds_and_milliseconds() { counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), endsWith( - "1m1.001s" + System.lineSeparator())); + assertThat(baos.toString(), endsWith(String.format( + "1m1.001s%n"))); } @Test @@ -135,8 +135,8 @@ public void should_print_minutes_instead_of_hours() { counter.addStep(new Result(Result.PASSED, SummaryCounter.ONE_MINUTE, null)); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), endsWith( - "61m0.000s" + System.lineSeparator())); + assertThat(baos.toString(), endsWith(String.format( + "61m0.000s%n"))); } @Test @@ -149,8 +149,8 @@ public void should_use_locale_for_decimal_separator() { counter.addStep(new Result(Result.PASSED, ONE_MILLI_SECOND, null)); counter.printSummary(new PrintStream(baos)); - assertThat(baos.toString(), endsWith( - "1m1,001s" + System.lineSeparator())); + assertThat(baos.toString(), endsWith(String.format( + "1m1,001s%n"))); } private void addOneStepScenario(SummaryCounter counter, String status) { From 07902e12e838898d456a56e5a920ff7fc127d779 Mon Sep 17 00:00:00 2001 From: brasmusson Date: Tue, 11 Jun 2013 09:11:20 +0200 Subject: [PATCH 3/6] Tell don't ask when printing summary at the end of the run Let the SummaryPrinter tell the Runtime to print the summary instead of asking for the SummaryCounter. Put back the check for an emtpy list of backends in the Runtime ctor, which was removed by mistake. Add test to check that a CucumberException is thrown when the list of backends is emtpy. Use Long for duration arguments in SummaryCounter, to conform to the return type of Result.getDuration(). --- .../main/java/cucumber/runtime/Runtime.java | 12 +++++--- .../java/cucumber/runtime/SummaryCounter.java | 12 +++----- .../runtime/snippets/SummaryPrinter.java | 2 +- .../java/cucumber/runtime/RuntimeTest.java | 29 ++++++++++++++----- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 24e31e139a..cf9489d875 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -19,6 +19,7 @@ import gherkin.formatter.model.Tag; import java.io.IOException; +import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -66,14 +67,17 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker()); } - public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, + private Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker) { this(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); } - public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, + Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker, RuntimeGlue glue) { + 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; @@ -308,8 +312,8 @@ public void writeStepdefsJson() throws IOException { glue.writeStepdefsJson(runtimeOptions.featurePaths, runtimeOptions.dotCucumber); } - public SummaryCounter getSummaryCounter() { - return summaryCounter; + public void printSummary(PrintStream out) { + summaryCounter.printSummary(out); } private void addStepToCounterAndResult(Result result) { diff --git a/core/src/main/java/cucumber/runtime/SummaryCounter.java b/core/src/main/java/cucumber/runtime/SummaryCounter.java index 4b1b758854..d8bc7cdfcb 100755 --- a/core/src/main/java/cucumber/runtime/SummaryCounter.java +++ b/core/src/main/java/cucumber/runtime/SummaryCounter.java @@ -88,23 +88,19 @@ private void printDuration(PrintStream out) { public void addStep(Result result) { addResultToSubCount(stepSubCounts, result.getStatus()); - // the following constant defined in the Gherkin libaray have duration == null, so calls to getDuration() - // will result in a NullPointerException - if (!result.equals(Result.SKIPPED) && !result.equals(Result.UNDEFINED)) { - addTime(result.getDuration()); - } + addTime(result.getDuration()); } public void addScenario(String resultStatus) { addResultToSubCount(scenarioSubCounts, resultStatus); } - public void addHookTime(long duration) { + public void addHookTime(Long duration) { addTime(duration); } - private void addTime(long duration) { - totalDuration += duration; + private void addTime(Long duration) { + totalDuration += duration != null ? duration : 0; } private void addResultToSubCount(SubCounts subCounts, String resultStatus) { diff --git a/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java b/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java index 4037610852..43e89745f6 100644 --- a/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java +++ b/core/src/main/java/cucumber/runtime/snippets/SummaryPrinter.java @@ -19,7 +19,7 @@ public void print(cucumber.runtime.Runtime runtime) { } private void printSummary(cucumber.runtime.Runtime runtime) { - runtime.getSummaryCounter().printSummary(out); + runtime.printSummary(out); } private void printErrors(cucumber.runtime.Runtime runtime) { diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index b151da4762..cdb563d387 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -28,6 +28,7 @@ import static org.hamcrest.CoreMatchers.startsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -177,6 +178,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.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()); + } + } + @Test public void should_add_passed_result_to_the_summary_counter() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -187,7 +200,7 @@ public void should_add_passed_result_to_the_summary_counter() throws Exception { runtime.buildBackendWorlds(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 passed)%n" + @@ -204,7 +217,7 @@ public void should_add_pending_result_to_the_summary_counter() throws Throwable runtime.buildBackendWorlds(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 pending)%n" + @@ -221,7 +234,7 @@ public void should_add_failed_result_to_the_summary_counter() throws Throwable { runtime.buildBackendWorlds(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 failed)%n" + @@ -237,7 +250,7 @@ public void should_add_ambiguous_match_as_failed_result_to_the_summary_counter() runtime.buildBackendWorlds(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 failed)%n" + @@ -255,7 +268,7 @@ public void should_add_skipped_result_to_the_summary_counter() throws Throwable runStep(reporter, runtime); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 failed)%n" + @@ -271,7 +284,7 @@ public void should_add_undefined_result_to_the_summary_counter() throws Throwabl runtime.buildBackendWorlds(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 undefined)%n" + @@ -290,7 +303,7 @@ public void should_fail_the_scenario_if_before_fails() throws Throwable { runtime.runBeforeHooks(reporter, Collections.emptySet()); runStep(reporter, runtime); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 failed)%n" + @@ -309,7 +322,7 @@ public void should_fail_the_scenario_if_after_fails() throws Throwable { runStep(reporter, runtime); runtime.runAfterHooks(reporter, Collections.emptySet()); runtime.disposeBackendWorlds(); - runtime.getSummaryCounter().printSummary(new PrintStream(baos)); + runtime.printSummary(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 failed)%n" + From c8feb10d8e6c86c3a22532a3ed594cb87fed6594 Mon Sep 17 00:00:00 2001 From: brasmusson Date: Tue, 11 Jun 2013 21:35:54 +0200 Subject: [PATCH 4/6] Minimize the number of constructors in the Runtime class To minimize the number of constructors in the Runtime class, and to handle that by default a UndefinedStepTracker is created and then injected both into the Runtime and the RuntimeGlue, create a factory method as the main entry. Expose additional conveniece factory methods for testing in the core module in RuntimeTest. --- core/src/main/java/cucumber/api/cli/Main.java | 2 +- .../main/java/cucumber/runtime/Runtime.java | 18 +++++------------- .../java/cucumber/runtime/BackgroundTest.java | 2 +- .../java/cucumber/runtime/HookOrderTest.java | 2 +- .../test/java/cucumber/runtime/HookTest.java | 2 +- .../java/cucumber/runtime/RuntimeTest.java | 19 ++++++++++++++++--- .../formatter/JSONPrettyFormatterTest.java | 4 ++-- .../runtime/formatter/JUnitFormatterTest.java | 4 ++-- .../runtime/java/JavaStepDefinitionTest.java | 15 ++++++++++++++- .../java/cucumber/api/junit/Cucumber.java | 2 +- 10 files changed, 44 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/cucumber/api/cli/Main.java b/core/src/main/java/cucumber/api/cli/Main.java index 2621774a16..25be6d8080 100644 --- a/core/src/main/java/cucumber/api/cli/Main.java +++ b/core/src/main/java/cucumber/api/cli/Main.java @@ -15,7 +15,7 @@ public static void main(String[] argv) throws Throwable { public static void run(String[] argv, ClassLoader classLoader) throws IOException { RuntimeOptions runtimeOptions = new RuntimeOptions(System.getProperties(), argv); - Runtime runtime = new Runtime(new MultiLoader(classLoader), classLoader, runtimeOptions); + Runtime runtime = Runtime.createRuntime(new MultiLoader(classLoader), classLoader, runtimeOptions); runtime.writeStepdefsJson(); runtime.run(); System.exit(runtime.exitStatus()); diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index cf9489d875..7c56e67f34 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -59,21 +59,13 @@ public class Runtime implements UnreportedStepExecutor { private boolean skipNextStep = false; private ScenarioImpl scenarioResult = null; - public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) { - this(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions); + public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) { + UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + return new Runtime(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions, + undefinedStepsTracker, new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); } - public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions) { - this(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker()); - } - - private Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, - RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker) { - this(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, - new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); - } - - Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, + public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker, RuntimeGlue glue) { if (backends.isEmpty()) { throw new CucumberException("No backends were found. Please make sure you have a backend module on your CLASSPATH."); diff --git a/core/src/test/java/cucumber/runtime/BackgroundTest.java b/core/src/test/java/cucumber/runtime/BackgroundTest.java index eb558aa829..30cbd466a8 100644 --- a/core/src/test/java/cucumber/runtime/BackgroundTest.java +++ b/core/src/test/java/cucumber/runtime/BackgroundTest.java @@ -18,7 +18,7 @@ public class BackgroundTest { public void should_run_background() throws IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(mock(Backend.class)), runtimeOptions); + Runtime runtime = RuntimeTest.createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(mock(Backend.class)), runtimeOptions); CucumberFeature feature = feature("test.feature", "" + "Feature:\n" + " Background:\n" + diff --git a/core/src/test/java/cucumber/runtime/HookOrderTest.java b/core/src/test/java/cucumber/runtime/HookOrderTest.java index b8025382a9..a3de0cbdbe 100644 --- a/core/src/test/java/cucumber/runtime/HookOrderTest.java +++ b/core/src/test/java/cucumber/runtime/HookOrderTest.java @@ -31,7 +31,7 @@ public class HookOrderTest { public void buildMockWorld() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - runtime = new Runtime(mock(ResourceLoader.class), classLoader, asList(mock(Backend.class)), runtimeOptions); + runtime = RuntimeTest.createRuntime(mock(ResourceLoader.class), classLoader, asList(mock(Backend.class)), runtimeOptions); runtime.buildBackendWorlds(null, Collections.emptySet()); glue = runtime.getGlue(); } diff --git a/core/src/test/java/cucumber/runtime/HookTest.java b/core/src/test/java/cucumber/runtime/HookTest.java index 9f9f6ca7ac..74bac6b42d 100644 --- a/core/src/test/java/cucumber/runtime/HookTest.java +++ b/core/src/test/java/cucumber/runtime/HookTest.java @@ -45,7 +45,7 @@ public void after_hooks_execute_before_objects_are_disposed() throws Throwable { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); + Runtime runtime = RuntimeTest.createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); runtime.getGlue().addAfterHook(hook); scenario.run(mock(Formatter.class), mock(Reporter.class), runtime); diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index cdb563d387..953b8aa98e 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -5,6 +5,7 @@ import cucumber.runtime.io.ClasspathResourceLoader; import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.model.CucumberFeature; +import cucumber.runtime.xstream.LocalizedXStreams; import gherkin.I18n; import gherkin.formatter.JSONFormatter; import gherkin.formatter.Reporter; @@ -54,7 +55,7 @@ public void runs_feature_with_json_formatter() throws Exception { List backends = asList(mock(Backend.class)); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, backends, runtimeOptions); + Runtime runtime = createRuntime(new ClasspathResourceLoader(classLoader), classLoader, backends, runtimeOptions); feature.run(jsonFormatter, jsonFormatter, runtime); jsonFormatter.done(); String expected = "" + @@ -182,7 +183,7 @@ public void strict_with_errors() { 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.emptyList(), + createRuntime(new ClasspathResourceLoader(classLoader), classLoader, Collections.emptyList(), new RuntimeOptions(new Properties())); fail("A CucumberException should have been thrown"); } catch (CucumberException e) { @@ -363,7 +364,19 @@ private Runtime createRuntime(String... runtimeArgs) { Backend backend = mock(Backend.class); Collection backends = Arrays.asList(backend); - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions); + return createRuntime(resourceLoader, classLoader, backends, runtimeOptions); + } + + public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, + Collection backends, RuntimeOptions runtimeOptions) { + UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, + new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + } + + public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, + Collection backends, RuntimeOptions runtimeOptions, RuntimeGlue glue) { + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker(), glue); } private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, String... runtimeArgs) { diff --git a/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java b/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java index 8d559e39e1..0660e5d328 100644 --- a/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java +++ b/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java @@ -1,8 +1,8 @@ package cucumber.runtime.formatter; import cucumber.runtime.Backend; -import cucumber.runtime.Runtime; import cucumber.runtime.RuntimeOptions; +import cucumber.runtime.RuntimeTest; import cucumber.runtime.io.ClasspathResourceLoader; import gherkin.formatter.model.Step; import org.junit.Test; @@ -45,7 +45,7 @@ private File runFeaturesWithJSONPrettyFormatter(final List featurePaths) RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties(), args.toArray(new String[args.size()])); Backend backend = mock(Backend.class); when(backend.getSnippet(any(Step.class))).thenReturn("TEST SNIPPET"); - final cucumber.runtime.Runtime runtime = new Runtime(resourceLoader, classLoader, asList(backend), runtimeOptions); + final cucumber.runtime.Runtime runtime = RuntimeTest.createRuntime(resourceLoader, classLoader, asList(backend), runtimeOptions); runtime.run(); return report; } diff --git a/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java b/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java index 70fc5e693d..01267c5a23 100644 --- a/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java +++ b/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java @@ -1,8 +1,8 @@ package cucumber.runtime.formatter; import cucumber.runtime.Backend; -import cucumber.runtime.Runtime; import cucumber.runtime.RuntimeOptions; +import cucumber.runtime.RuntimeTest; import cucumber.runtime.io.ClasspathResourceLoader; import gherkin.formatter.model.Step; import org.custommonkey.xmlunit.Diff; @@ -58,7 +58,7 @@ private File runFeaturesWithJunitFormatter(final List featurePaths) thro RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties(), args.toArray(new String[args.size()])); Backend backend = mock(Backend.class); when(backend.getSnippet(any(Step.class))).thenReturn("TEST SNIPPET"); - final cucumber.runtime.Runtime runtime = new Runtime(resourceLoader, classLoader, asList(backend), runtimeOptions); + final cucumber.runtime.Runtime runtime = RuntimeTest.createRuntime(resourceLoader, classLoader, asList(backend), runtimeOptions); runtime.run(); return report; } diff --git a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java index 0c3fb06220..5b5a4d97a8 100644 --- a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java +++ b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java @@ -2,11 +2,16 @@ import cucumber.api.java.en.Given; import cucumber.runtime.AmbiguousStepDefinitionsException; +import cucumber.runtime.Backend; import cucumber.runtime.DuplicateStepDefinitionException; import cucumber.runtime.Glue; import cucumber.runtime.Runtime; +import cucumber.runtime.RuntimeGlue; import cucumber.runtime.RuntimeOptions; +import cucumber.runtime.UndefinedStepsTracker; import cucumber.runtime.io.ClasspathResourceLoader; +import cucumber.runtime.io.ResourceLoader; +import cucumber.runtime.xstream.LocalizedXStreams; import gherkin.I18n; import gherkin.formatter.Reporter; import gherkin.formatter.model.Comment; @@ -18,6 +23,7 @@ import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -50,7 +56,7 @@ public class JavaStepDefinitionTest { private final JavaBackend backend = new JavaBackend(new SingletonFactory(defs)); private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); private final RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - private final Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); + private final Runtime runtime = createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); private final Glue glue = runtime.getGlue(); @org.junit.Before @@ -144,4 +150,11 @@ private Set asSet(T... items) { set.addAll(asList(items)); return set; } + + private Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, + Collection backends, RuntimeOptions runtimeOptions) { + UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, + new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + } } diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index cdbbf82692..e8453231c9 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -56,7 +56,7 @@ public Cucumber(Class clazz) throws InitializationError, IOException { RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); ResourceLoader resourceLoader = new MultiLoader(classLoader); - runtime = new Runtime(resourceLoader, classLoader, runtimeOptions); + runtime = Runtime.createRuntime(resourceLoader, classLoader, runtimeOptions); jUnitReporter = new JUnitReporter(runtimeOptions.reporter(classLoader), runtimeOptions.formatter(classLoader), runtimeOptions.strict); addChildren(runtimeOptions.cucumberFeatures(resourceLoader)); From 3a77cff87b642b4916f75d93c65ae59781ecb66f Mon Sep 17 00:00:00 2001 From: brasmusson Date: Tue, 25 Jun 2013 10:27:39 +0200 Subject: [PATCH 5/6] Localise the UndefinedStepTracker in the Runtime Localise the UndefinedStepTracker in the Runtime and remove that argument from the constructor. Use that the optionalGlue argument is null, as the cue to let the Runtime create the default RuntimeGlue. When the optionalGlue argument is not null, the glue injected with that argument will be used by the Runtime. --- core/src/main/java/cucumber/runtime/Runtime.java | 11 ++++------- core/src/test/java/cucumber/runtime/RuntimeTest.java | 9 +++------ .../cucumber/runtime/java/JavaStepDefinitionTest.java | 7 +------ 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 7c56e67f34..c5da9ff36d 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -44,7 +44,7 @@ public class Runtime implements UnreportedStepExecutor { private static final byte ERRORS = 0x1; private final SummaryCounter summaryCounter; - final UndefinedStepsTracker undefinedStepsTracker; + final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); private final Glue glue; private final RuntimeOptions runtimeOptions; @@ -60,13 +60,11 @@ public class Runtime implements UnreportedStepExecutor { private ScenarioImpl scenarioResult = null; public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) { - UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); - return new Runtime(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions, - undefinedStepsTracker, new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + return new Runtime(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions, null); } public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, - RuntimeOptions runtimeOptions, UndefinedStepsTracker undefinedStepsTracker, RuntimeGlue glue) { + 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."); } @@ -74,8 +72,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this.classLoader = classLoader; this.backends = backends; this.runtimeOptions = runtimeOptions; - this.undefinedStepsTracker = undefinedStepsTracker; - this.glue = glue; + this.glue = optionalGlue != null ? optionalGlue : new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader)); this.summaryCounter = new SummaryCounter(runtimeOptions.monochrome); for (Backend backend : backends) { diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index 953b8aa98e..bebba709c5 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -5,7 +5,6 @@ import cucumber.runtime.io.ClasspathResourceLoader; import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.model.CucumberFeature; -import cucumber.runtime.xstream.LocalizedXStreams; import gherkin.I18n; import gherkin.formatter.JSONFormatter; import gherkin.formatter.Reporter; @@ -369,14 +368,12 @@ private Runtime createRuntime(String... runtimeArgs) { public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions) { - UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, - new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, null); } public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions, RuntimeGlue glue) { - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker(), glue); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, glue); } private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, String... runtimeArgs) { @@ -403,7 +400,7 @@ private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, boolean i mockHook(glue, hook, isBefore); Collection backends = Arrays.asList(backend); - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, new UndefinedStepsTracker(), glue); + return createRuntime(resourceLoader, classLoader, backends, runtimeOptions, glue); } private void mockMatch(RuntimeGlue glue, StepDefinitionMatch match, boolean isAmbiguous) { diff --git a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java index 5b5a4d97a8..857b663b5f 100644 --- a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java +++ b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java @@ -6,12 +6,9 @@ import cucumber.runtime.DuplicateStepDefinitionException; import cucumber.runtime.Glue; import cucumber.runtime.Runtime; -import cucumber.runtime.RuntimeGlue; import cucumber.runtime.RuntimeOptions; -import cucumber.runtime.UndefinedStepsTracker; import cucumber.runtime.io.ClasspathResourceLoader; import cucumber.runtime.io.ResourceLoader; -import cucumber.runtime.xstream.LocalizedXStreams; import gherkin.I18n; import gherkin.formatter.Reporter; import gherkin.formatter.model.Comment; @@ -153,8 +150,6 @@ private Set asSet(T... items) { private Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions) { - UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, undefinedStepsTracker, - new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader))); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, null); } } From 442c4ed533ffb11abf031ed386075d57555a16cc Mon Sep 17 00:00:00 2001 From: brasmusson Date: Fri, 28 Jun 2013 13:35:07 +0200 Subject: [PATCH 6/6] Add RuntimeOptions.isMonochrome(), rm Runtime factory methods Add RuntimeOptions.isMonochorme(), since commit 65f3bd6 on the master branch change RuntimeOptions to have private fields and getters. Basically revert commit c8feb10. Since the new android support on the master banch sends backends to the Runtime constructor, which previously only was done in tests, the change to use factory methods in Runtime no longer make sence. --- core/src/main/java/cucumber/api/cli/Main.java | 2 +- .../main/java/cucumber/runtime/Runtime.java | 25 +++++++------------ .../java/cucumber/runtime/RuntimeOptions.java | 4 +++ .../java/cucumber/runtime/BackgroundTest.java | 2 +- .../java/cucumber/runtime/HookOrderTest.java | 2 +- .../test/java/cucumber/runtime/HookTest.java | 2 +- .../java/cucumber/runtime/RuntimeTest.java | 18 +++---------- .../formatter/JSONPrettyFormatterTest.java | 4 +-- .../runtime/formatter/JUnitFormatterTest.java | 4 +-- .../runtime/java/JavaStepDefinitionTest.java | 9 +------ .../java/cucumber/api/junit/Cucumber.java | 2 +- 11 files changed, 27 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/cucumber/api/cli/Main.java b/core/src/main/java/cucumber/api/cli/Main.java index 25be6d8080..2621774a16 100644 --- a/core/src/main/java/cucumber/api/cli/Main.java +++ b/core/src/main/java/cucumber/api/cli/Main.java @@ -15,7 +15,7 @@ public static void main(String[] argv) throws Throwable { public static void run(String[] argv, ClassLoader classLoader) throws IOException { RuntimeOptions runtimeOptions = new RuntimeOptions(System.getProperties(), argv); - Runtime runtime = Runtime.createRuntime(new MultiLoader(classLoader), classLoader, runtimeOptions); + Runtime runtime = new Runtime(new MultiLoader(classLoader), classLoader, runtimeOptions); runtime.writeStepdefsJson(); runtime.run(); System.exit(runtime.exitStatus()); diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index c5da9ff36d..aa2721fd6a 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -10,22 +10,11 @@ import gherkin.formatter.Argument; import gherkin.formatter.Formatter; import gherkin.formatter.Reporter; -import gherkin.formatter.model.Comment; -import gherkin.formatter.model.DataTableRow; -import gherkin.formatter.model.DocString; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Step; -import gherkin.formatter.model.Tag; +import gherkin.formatter.model.*; import java.io.IOException; import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; /** * This is the main entry point for running Cucumber features. @@ -59,8 +48,12 @@ public class Runtime implements UnreportedStepExecutor { private boolean skipNextStep = false; private ScenarioImpl scenarioResult = null; - public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) { - return new Runtime(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions, null); + public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) { + this(resourceLoader, classLoader, loadBackends(resourceLoader, classLoader), runtimeOptions); + } + + public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, RuntimeOptions runtimeOptions) { + this(resourceLoader, classLoader, backends, runtimeOptions, null); } public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collection backends, @@ -73,7 +66,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this.backends = backends; this.runtimeOptions = runtimeOptions; this.glue = optionalGlue != null ? optionalGlue : new RuntimeGlue(undefinedStepsTracker, new LocalizedXStreams(classLoader)); - this.summaryCounter = new SummaryCounter(runtimeOptions.monochrome); + this.summaryCounter = new SummaryCounter(runtimeOptions.isMonochrome()); for (Backend backend : backends) { backend.loadGlue(glue, runtimeOptions.glue); diff --git a/core/src/main/java/cucumber/runtime/RuntimeOptions.java b/core/src/main/java/cucumber/runtime/RuntimeOptions.java index 582c8716bd..655cb9c989 100644 --- a/core/src/main/java/cucumber/runtime/RuntimeOptions.java +++ b/core/src/main/java/cucumber/runtime/RuntimeOptions.java @@ -149,4 +149,8 @@ public Object invoke(Object target, Method method, Object[] args) throws Throwab } }); } + + public boolean isMonochrome() { + return monochrome; + } } diff --git a/core/src/test/java/cucumber/runtime/BackgroundTest.java b/core/src/test/java/cucumber/runtime/BackgroundTest.java index 30cbd466a8..eb558aa829 100644 --- a/core/src/test/java/cucumber/runtime/BackgroundTest.java +++ b/core/src/test/java/cucumber/runtime/BackgroundTest.java @@ -18,7 +18,7 @@ public class BackgroundTest { public void should_run_background() throws IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = RuntimeTest.createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(mock(Backend.class)), runtimeOptions); + Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(mock(Backend.class)), runtimeOptions); CucumberFeature feature = feature("test.feature", "" + "Feature:\n" + " Background:\n" + diff --git a/core/src/test/java/cucumber/runtime/HookOrderTest.java b/core/src/test/java/cucumber/runtime/HookOrderTest.java index a3de0cbdbe..b8025382a9 100644 --- a/core/src/test/java/cucumber/runtime/HookOrderTest.java +++ b/core/src/test/java/cucumber/runtime/HookOrderTest.java @@ -31,7 +31,7 @@ public class HookOrderTest { public void buildMockWorld() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - runtime = RuntimeTest.createRuntime(mock(ResourceLoader.class), classLoader, asList(mock(Backend.class)), runtimeOptions); + runtime = new Runtime(mock(ResourceLoader.class), classLoader, asList(mock(Backend.class)), runtimeOptions); runtime.buildBackendWorlds(null, Collections.emptySet()); glue = runtime.getGlue(); } diff --git a/core/src/test/java/cucumber/runtime/HookTest.java b/core/src/test/java/cucumber/runtime/HookTest.java index 74bac6b42d..9f9f6ca7ac 100644 --- a/core/src/test/java/cucumber/runtime/HookTest.java +++ b/core/src/test/java/cucumber/runtime/HookTest.java @@ -45,7 +45,7 @@ public void after_hooks_execute_before_objects_are_disposed() throws Throwable { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = RuntimeTest.createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); + Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); runtime.getGlue().addAfterHook(hook); scenario.run(mock(Formatter.class), mock(Reporter.class), runtime); diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index bebba709c5..1f66289398 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -54,7 +54,7 @@ public void runs_feature_with_json_formatter() throws Exception { List backends = asList(mock(Backend.class)); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - Runtime runtime = createRuntime(new ClasspathResourceLoader(classLoader), classLoader, backends, runtimeOptions); + Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, backends, runtimeOptions); feature.run(jsonFormatter, jsonFormatter, runtime); jsonFormatter.done(); String expected = "" + @@ -182,7 +182,7 @@ public void strict_with_errors() { public void should_throw_cucumer_exception_if_no_backends_are_found() throws Exception { try { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - createRuntime(new ClasspathResourceLoader(classLoader), classLoader, Collections.emptyList(), + new Runtime(new ClasspathResourceLoader(classLoader), classLoader, Collections.emptyList(), new RuntimeOptions(new Properties())); fail("A CucumberException should have been thrown"); } catch (CucumberException e) { @@ -363,17 +363,7 @@ private Runtime createRuntime(String... runtimeArgs) { Backend backend = mock(Backend.class); Collection backends = Arrays.asList(backend); - return createRuntime(resourceLoader, classLoader, backends, runtimeOptions); - } - - public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, - Collection backends, RuntimeOptions runtimeOptions) { - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, null); - } - - public static Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, - Collection backends, RuntimeOptions runtimeOptions, RuntimeGlue glue) { - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, glue); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions); } private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, String... runtimeArgs) { @@ -400,7 +390,7 @@ private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, boolean i mockHook(glue, hook, isBefore); Collection backends = Arrays.asList(backend); - return createRuntime(resourceLoader, classLoader, backends, runtimeOptions, glue); + return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, glue); } private void mockMatch(RuntimeGlue glue, StepDefinitionMatch match, boolean isAmbiguous) { diff --git a/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java b/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java index 0660e5d328..8d559e39e1 100644 --- a/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java +++ b/core/src/test/java/cucumber/runtime/formatter/JSONPrettyFormatterTest.java @@ -1,8 +1,8 @@ package cucumber.runtime.formatter; import cucumber.runtime.Backend; +import cucumber.runtime.Runtime; import cucumber.runtime.RuntimeOptions; -import cucumber.runtime.RuntimeTest; import cucumber.runtime.io.ClasspathResourceLoader; import gherkin.formatter.model.Step; import org.junit.Test; @@ -45,7 +45,7 @@ private File runFeaturesWithJSONPrettyFormatter(final List featurePaths) RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties(), args.toArray(new String[args.size()])); Backend backend = mock(Backend.class); when(backend.getSnippet(any(Step.class))).thenReturn("TEST SNIPPET"); - final cucumber.runtime.Runtime runtime = RuntimeTest.createRuntime(resourceLoader, classLoader, asList(backend), runtimeOptions); + final cucumber.runtime.Runtime runtime = new Runtime(resourceLoader, classLoader, asList(backend), runtimeOptions); runtime.run(); return report; } diff --git a/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java b/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java index 01267c5a23..70fc5e693d 100644 --- a/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java +++ b/core/src/test/java/cucumber/runtime/formatter/JUnitFormatterTest.java @@ -1,8 +1,8 @@ package cucumber.runtime.formatter; import cucumber.runtime.Backend; +import cucumber.runtime.Runtime; import cucumber.runtime.RuntimeOptions; -import cucumber.runtime.RuntimeTest; import cucumber.runtime.io.ClasspathResourceLoader; import gherkin.formatter.model.Step; import org.custommonkey.xmlunit.Diff; @@ -58,7 +58,7 @@ private File runFeaturesWithJunitFormatter(final List featurePaths) thro RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties(), args.toArray(new String[args.size()])); Backend backend = mock(Backend.class); when(backend.getSnippet(any(Step.class))).thenReturn("TEST SNIPPET"); - final cucumber.runtime.Runtime runtime = RuntimeTest.createRuntime(resourceLoader, classLoader, asList(backend), runtimeOptions); + final cucumber.runtime.Runtime runtime = new Runtime(resourceLoader, classLoader, asList(backend), runtimeOptions); runtime.run(); return report; } diff --git a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java index 857b663b5f..f8f1c20cfb 100644 --- a/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java +++ b/java/src/test/java/cucumber/runtime/java/JavaStepDefinitionTest.java @@ -2,7 +2,6 @@ import cucumber.api.java.en.Given; import cucumber.runtime.AmbiguousStepDefinitionsException; -import cucumber.runtime.Backend; import cucumber.runtime.DuplicateStepDefinitionException; import cucumber.runtime.Glue; import cucumber.runtime.Runtime; @@ -20,7 +19,6 @@ import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -53,7 +51,7 @@ public class JavaStepDefinitionTest { private final JavaBackend backend = new JavaBackend(new SingletonFactory(defs)); private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); private final RuntimeOptions runtimeOptions = new RuntimeOptions(new Properties()); - private final Runtime runtime = createRuntime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); + private final Runtime runtime = new Runtime(new ClasspathResourceLoader(classLoader), classLoader, asList(backend), runtimeOptions); private final Glue glue = runtime.getGlue(); @org.junit.Before @@ -147,9 +145,4 @@ private Set asSet(T... items) { set.addAll(asList(items)); return set; } - - private Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, - Collection backends, RuntimeOptions runtimeOptions) { - return new Runtime(resourceLoader, classLoader, backends, runtimeOptions, null); - } } diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index e8453231c9..cdbbf82692 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -56,7 +56,7 @@ public Cucumber(Class clazz) throws InitializationError, IOException { RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); ResourceLoader resourceLoader = new MultiLoader(classLoader); - runtime = Runtime.createRuntime(resourceLoader, classLoader, runtimeOptions); + runtime = new Runtime(resourceLoader, classLoader, runtimeOptions); jUnitReporter = new JUnitReporter(runtimeOptions.reporter(classLoader), runtimeOptions.formatter(classLoader), runtimeOptions.strict); addChildren(runtimeOptions.cucumberFeatures(resourceLoader));