From 118e7328454acdc288a999b0398ae309370cce91 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Wed, 16 May 2018 23:36:28 +0200 Subject: [PATCH] Collect stats in SummaryPrinter and AndroidLogcatReporter --- .../runtime/android/CucumberExecutor.java | 13 +- .../AndroidInstrumentationReporter.java | 17 ++- .../formatter/AndroidLogcatReporter.java | 25 ++-- .../AndroidInstrumentationReporterTest.java | 4 +- .../java/cucumber/api/SummaryPrinter.java | 6 +- .../api/SummaryPrintingInterface.java | 31 ----- core/src/main/java/cucumber/api/cli/Main.java | 5 +- .../runtime/DefaultSummaryPrinter.java | 56 +++++++-- .../java/cucumber/runtime/ExitStatus.java | 39 ++++++ .../cucumber/runtime/NullSummaryPrinter.java | 6 - .../main/java/cucumber/runtime/Runtime.java | 35 +----- .../java/cucumber/runtime/RuntimeOptions.java | 17 +-- .../src/main/java/cucumber/runtime/Stats.java | 42 +++---- .../java/cucumber/runtime/RuntimeTest.java | 112 ------------------ .../test/java/cucumber/runtime/StatsTest.java | 36 +++--- .../java/paxexam/test/CalculatorTest.java | 21 +++- .../java/cucumber/api/junit/Cucumber.java | 1 - .../api/testng/TestNGCucumberRunner.java | 1 - 18 files changed, 188 insertions(+), 279 deletions(-) delete mode 100644 core/src/main/java/cucumber/api/SummaryPrintingInterface.java create mode 100755 core/src/main/java/cucumber/runtime/ExitStatus.java diff --git a/android/src/main/java/cucumber/runtime/android/CucumberExecutor.java b/android/src/main/java/cucumber/runtime/android/CucumberExecutor.java index 08aeea3c10..6f729cda02 100644 --- a/android/src/main/java/cucumber/runtime/android/CucumberExecutor.java +++ b/android/src/main/java/cucumber/runtime/android/CucumberExecutor.java @@ -14,6 +14,8 @@ import cucumber.runtime.Runtime; import cucumber.runtime.RuntimeOptions; import cucumber.runtime.RuntimeOptionsFactory; +import cucumber.runtime.Stats; +import cucumber.runtime.UndefinedStepsTracker; import cucumber.runtime.formatter.AndroidInstrumentationReporter; import cucumber.runtime.formatter.AndroidLogcatReporter; import cucumber.runtime.io.ResourceLoader; @@ -88,13 +90,18 @@ public CucumberExecutor(final Arguments arguments, final Instrumentation instrum this.instrumentation = instrumentation; this.classLoader = context.getClassLoader(); this.classFinder = createDexClassFinder(context); - this.runtimeOptions = createRuntimeOptions(context); + this.runtimeOptions = createRuntimeOptions(context).noSummaryPrinter(); ResourceLoader resourceLoader = new AndroidResourceLoader(context); this.runtime = new Runtime(resourceLoader, classLoader, createBackends(), runtimeOptions); - AndroidInstrumentationReporter instrumentationReporter = new AndroidInstrumentationReporter(runtime, instrumentation); + UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + undefinedStepsTracker.setEventPublisher(runtime.getEventBus()); + Stats stats = new Stats(); + stats.setEventPublisher(runtime.getEventBus()); + + AndroidInstrumentationReporter instrumentationReporter = new AndroidInstrumentationReporter(undefinedStepsTracker, instrumentation); runtimeOptions.addPlugin(instrumentationReporter); - runtimeOptions.addPlugin(new AndroidLogcatReporter(runtime, TAG)); + runtimeOptions.addPlugin(new AndroidLogcatReporter(stats, undefinedStepsTracker, TAG)); List cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader, runtime.getEventBus()); this.pickleEvents = FeatureCompiler.compile(cucumberFeatures, this.runtime); diff --git a/android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java b/android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java index 9dcc7d0be3..cd6579c4e8 100644 --- a/android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java +++ b/android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java @@ -11,7 +11,7 @@ import cucumber.api.event.TestSourceRead; import cucumber.api.event.TestStepFinished; import cucumber.api.formatter.Formatter; -import cucumber.runtime.Runtime; +import cucumber.runtime.UndefinedStepsTracker; import cucumber.runtime.Utils; import java.io.PrintWriter; @@ -68,11 +68,6 @@ static class StatusCodes { */ private final TestSourcesModel testSources = new TestSourcesModel(); - /** - * The current cucumber runtime. - */ - private final Runtime runtime; - /** * The instrumentation to report to. */ @@ -144,14 +139,16 @@ public void receive(TestCaseFinished event) { } }; + private final UndefinedStepsTracker undefinedStepsTracker; + + /** * Creates a new instance for the given parameters * - * @param runtime the {@link cucumber.runtime.Runtime} to use * @param instrumentation the {@link android.app.Instrumentation} to report statuses to */ - public AndroidInstrumentationReporter(final Runtime runtime, final Instrumentation instrumentation) { - this.runtime = runtime; + public AndroidInstrumentationReporter(final UndefinedStepsTracker undefinedStepsTracker, final Instrumentation instrumentation) { + this.undefinedStepsTracker = undefinedStepsTracker; this.instrumentation = instrumentation; } @@ -242,7 +239,7 @@ private Bundle createBundle(final String path, final String testCaseName) { * @return string representation of the snippet */ private String getLastSnippet() { - return runtime.getSnippets().get(runtime.getSnippets().size() - 1); + return undefinedStepsTracker.getSnippets().get(undefinedStepsTracker.getSnippets().size() - 1); } /** diff --git a/android/src/main/java/cucumber/runtime/formatter/AndroidLogcatReporter.java b/android/src/main/java/cucumber/runtime/formatter/AndroidLogcatReporter.java index 1a2b40950d..961d1b0405 100644 --- a/android/src/main/java/cucumber/runtime/formatter/AndroidLogcatReporter.java +++ b/android/src/main/java/cucumber/runtime/formatter/AndroidLogcatReporter.java @@ -8,17 +8,13 @@ import cucumber.api.event.TestRunFinished; import cucumber.api.event.TestStepStarted; import cucumber.api.formatter.Formatter; -import cucumber.runtime.Runtime; +import cucumber.runtime.Stats; +import cucumber.runtime.UndefinedStepsTracker; /** * Logs information about the currently executed statements to androids logcat. */ -public final class AndroidLogcatReporter implements Formatter { - - /** - * The {@link cucumber.runtime.Runtime} to get the errors and snippets from for writing them to the logcat at the end of the execution. - */ - private final Runtime runtime; +public final class AndroidLogcatReporter implements Formatter { /** * The log tag to be used when logging to logcat. @@ -35,6 +31,10 @@ public void receive(TestCaseStarted event) { } }; + private final Stats stats; + + private final UndefinedStepsTracker undefinedStepsTracker; + /** * The event handler that logs the {@link TestStepStarted} events. */ @@ -55,11 +55,11 @@ public void receive(TestStepStarted event) { @Override public void receive(TestRunFinished event) { - for (final Throwable throwable : runtime.getErrors()) { + for (final Throwable throwable : stats.getErrors()) { Log.e(logTag, throwable.toString()); } - for (final String snippet : runtime.getSnippets()) { + for (final String snippet : undefinedStepsTracker.getSnippets()) { Log.w(logTag, snippet); } } @@ -68,11 +68,12 @@ public void receive(TestRunFinished event) { /** * Creates a new instance for the given parameters. * - * @param runtime the {@link cucumber.runtime.Runtime} to get the errors and snippets from + * @param undefinedStepsTracker * @param logTag the tag to use for logging to logcat */ - public AndroidLogcatReporter(final Runtime runtime, final String logTag) { - this.runtime = runtime; + public AndroidLogcatReporter(Stats stats, UndefinedStepsTracker undefinedStepsTracker, final String logTag) { + this.stats = stats; + this.undefinedStepsTracker = undefinedStepsTracker; this.logTag = logTag; } diff --git a/android/src/test/java/cucumber/runtime/formatter/AndroidInstrumentationReporterTest.java b/android/src/test/java/cucumber/runtime/formatter/AndroidInstrumentationReporterTest.java index d6007f1525..124be16293 100644 --- a/android/src/test/java/cucumber/runtime/formatter/AndroidInstrumentationReporterTest.java +++ b/android/src/test/java/cucumber/runtime/formatter/AndroidInstrumentationReporterTest.java @@ -17,7 +17,7 @@ import cucumber.api.Result; import cucumber.api.TestCase; import cucumber.api.event.TestSourceRead; -import cucumber.runtime.Runtime; +import cucumber.runtime.UndefinedStepsTracker; import cucumber.runtime.formatter.AndroidInstrumentationReporter.StatusCodes; import edu.emory.mathcs.backport.java.util.Collections; import org.junit.Before; @@ -39,7 +39,7 @@ public class AndroidInstrumentationReporterTest { @Rule public final ExpectedException expectedException = ExpectedException.none(); - private final Runtime runtime = mock(Runtime.class); + private final UndefinedStepsTracker runtime = mock(UndefinedStepsTracker.class); private final Instrumentation instrumentation = mock(Instrumentation.class); private final TestSourceRead testSourceRead = new TestSourceRead( diff --git a/core/src/main/java/cucumber/api/SummaryPrinter.java b/core/src/main/java/cucumber/api/SummaryPrinter.java index 69ba17cdea..a5ba643673 100644 --- a/core/src/main/java/cucumber/api/SummaryPrinter.java +++ b/core/src/main/java/cucumber/api/SummaryPrinter.java @@ -6,9 +6,5 @@ * @see Plugin */ public interface SummaryPrinter extends Plugin { - /** - * Handles the printing of the summary to the console - * @param summaryPrinting Provides method to print the stats, errors and snippets - */ - void print(SummaryPrintingInterface summaryPrinting); + } diff --git a/core/src/main/java/cucumber/api/SummaryPrintingInterface.java b/core/src/main/java/cucumber/api/SummaryPrintingInterface.java deleted file mode 100644 index eb5d83d574..0000000000 --- a/core/src/main/java/cucumber/api/SummaryPrintingInterface.java +++ /dev/null @@ -1,31 +0,0 @@ -package cucumber.api; - -import java.io.PrintStream; -import java.util.List; - -/** - * Provides methods for printing the statistics, errors and snippets to - * a SummaryPrinter plugin. - * - */ -public interface SummaryPrintingInterface { - /** - * Prints the statistics to the PrintStream argument. - * @param out The PrintStream to print to. - */ - void printStats(PrintStream out); - - /** - * Returns the errors that occurred during the execution of the test cases - * from the feature files. - * @return the errors. - */ - List getErrors(); - - /** - * Returns the snippets created for the undefined steps encountered during - * the execution of the test cases from the feature files. - * @return the snippets. - */ - List getSnippets(); -} diff --git a/core/src/main/java/cucumber/api/cli/Main.java b/core/src/main/java/cucumber/api/cli/Main.java index 1801e84b85..0628abebb0 100644 --- a/core/src/main/java/cucumber/api/cli/Main.java +++ b/core/src/main/java/cucumber/api/cli/Main.java @@ -14,7 +14,7 @@ public class Main { - public static void main(String[] argv) throws Throwable { + public static void main(String[] argv) { byte exitstatus = run(argv, Thread.currentThread().getContextClassLoader()); System.exit(exitstatus); } @@ -25,9 +25,8 @@ public static void main(String[] argv) throws Throwable { * @param argv runtime options. See details in the {@code cucumber.api.cli.Usage.txt} resource. * @param classLoader classloader used to load the runtime * @return 0 if execution was successful, 1 if it was not (test failures) - * @throws IOException if resources couldn't be loaded during the run. */ - public static byte run(String[] argv, ClassLoader classLoader) throws IOException { + public static byte run(String[] argv, ClassLoader classLoader) { RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList(asList(argv))); ResourceLoader resourceLoader = new MultiLoader(classLoader); diff --git a/core/src/main/java/cucumber/runtime/DefaultSummaryPrinter.java b/core/src/main/java/cucumber/runtime/DefaultSummaryPrinter.java index bc1674efc4..c5ca68e128 100644 --- a/core/src/main/java/cucumber/runtime/DefaultSummaryPrinter.java +++ b/core/src/main/java/cucumber/runtime/DefaultSummaryPrinter.java @@ -1,40 +1,48 @@ package cucumber.runtime; import cucumber.api.SummaryPrinter; -import cucumber.api.SummaryPrintingInterface; +import cucumber.api.event.EventHandler; +import cucumber.api.event.EventPublisher; +import cucumber.api.event.TestRunFinished; +import cucumber.api.formatter.ColorAware; +import cucumber.api.formatter.Formatter; +import cucumber.api.formatter.StrictAware; import java.io.PrintStream; import java.util.List; -public class DefaultSummaryPrinter implements SummaryPrinter { +public class DefaultSummaryPrinter implements SummaryPrinter, ColorAware, StrictAware, Formatter { + + private final Stats stats = new Stats(); + private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + private final PrintStream out; public DefaultSummaryPrinter() { this.out = System.out; } - @Override - public void print(SummaryPrintingInterface summaryPrinting) { + private void print() { out.println(); - printStats(summaryPrinting); + printStats(); out.println(); - printErrors(summaryPrinting); - printSnippets(summaryPrinting); + printErrors(); + printSnippets(); } - private void printStats(SummaryPrintingInterface summaryPrinting) { - summaryPrinting.printStats(out); + private void printStats() { + stats.printStats(out); } - private void printErrors(SummaryPrintingInterface summaryPrinting) { - for (Throwable error : summaryPrinting.getErrors()) { + private void printErrors() { + for (Throwable error : stats.getErrors()) { error.printStackTrace(out); out.println(); } } - private void printSnippets(SummaryPrintingInterface summaryPrinting) { - List snippets = summaryPrinting.getSnippets(); + private void printSnippets() { + List snippets = undefinedStepsTracker.getSnippets(); if (!snippets.isEmpty()) { out.append("\n"); out.println("You can implement missing steps with the snippets below:"); @@ -44,4 +52,26 @@ private void printSnippets(SummaryPrintingInterface summaryPrinting) { } } } + + @Override + public void setEventPublisher(EventPublisher publisher) { + stats.setEventPublisher(publisher); + undefinedStepsTracker.setEventPublisher(publisher); + publisher.registerHandlerFor(TestRunFinished.class, new EventHandler() { + @Override + public void receive(TestRunFinished event) { + print(); + } + }); + } + + @Override + public void setMonochrome(boolean monochrome) { + stats.setMonochrome(monochrome); + } + + @Override + public void setStrict(boolean strict) { + stats.setStrict(strict); + } } diff --git a/core/src/main/java/cucumber/runtime/ExitStatus.java b/core/src/main/java/cucumber/runtime/ExitStatus.java new file mode 100755 index 0000000000..d0dd29c9db --- /dev/null +++ b/core/src/main/java/cucumber/runtime/ExitStatus.java @@ -0,0 +1,39 @@ +package cucumber.runtime; + +import cucumber.api.Result; +import cucumber.api.event.EventHandler; +import cucumber.api.event.EventListener; +import cucumber.api.event.EventPublisher; +import cucumber.api.event.TestCaseFinished; + +import java.util.ArrayList; +import java.util.List; + +import static cucumber.api.Result.SEVERITY; +import static java.util.Collections.max; + +class ExitStatus implements EventListener { + private static final byte ERRORS = 0x1; + + private final List results = new ArrayList(); + + private final EventHandler testCaseFinishedHandler = new EventHandler() { + @Override + public void receive(TestCaseFinished event) { + results.add(event.result); + } + }; + + ExitStatus() { + } + + + @Override + public void setEventPublisher(EventPublisher publisher) { + publisher.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler); + } + + public byte exitStatus(boolean isStrict) { + return results.isEmpty() || max(results, SEVERITY).isOk(isStrict) ? 0x0 : ERRORS; + } +} diff --git a/core/src/main/java/cucumber/runtime/NullSummaryPrinter.java b/core/src/main/java/cucumber/runtime/NullSummaryPrinter.java index 696c384e3c..3b0fc2ee73 100644 --- a/core/src/main/java/cucumber/runtime/NullSummaryPrinter.java +++ b/core/src/main/java/cucumber/runtime/NullSummaryPrinter.java @@ -1,13 +1,7 @@ package cucumber.runtime; import cucumber.api.SummaryPrinter; -import cucumber.api.SummaryPrintingInterface; public class NullSummaryPrinter implements SummaryPrinter { - @Override - public void print(SummaryPrintingInterface summaryPrinting) { - // Do nothing - } - } diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 6c53eadfd5..fb548ad8cd 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -1,8 +1,6 @@ package cucumber.runtime; import cucumber.api.StepDefinitionReporter; -import cucumber.api.SummaryPrinter; -import cucumber.api.SummaryPrintingInterface; import cucumber.api.event.TestRunFinished; import cucumber.runner.EventBus; import cucumber.runner.Runner; @@ -14,8 +12,6 @@ import gherkin.pickles.Compiler; import gherkin.pickles.Pickle; -import java.io.IOException; -import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -25,10 +21,9 @@ /** * This is the main entry point for running Cucumber features. */ -public class Runtime implements SummaryPrintingInterface { +public class Runtime { - final Stats stats; // package private to be available for tests. - private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); + private final ExitStatus exitStatus = new ExitStatus(); private final RuntimeOptions runtimeOptions; @@ -61,7 +56,6 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this.runtimeOptions = runtimeOptions; final Glue glue; glue = optionalGlue == null ? new RuntimeGlue(new LocalizedXStreams(classLoader, runtimeOptions.getConverters())) : optionalGlue; - this.stats = new Stats(runtimeOptions.isMonochrome()); this.bus = new EventBus(stopWatch); this.runner = new Runner(glue, bus, backends, runtimeOptions); this.filters = new ArrayList(); @@ -78,8 +72,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this.filters.add(new LinePredicate(lineFilters)); } - stats.setEventPublisher(bus); - undefinedStepsTracker.setEventPublisher(bus); + exitStatus.setEventPublisher(bus); runtimeOptions.setEventBus(bus); } @@ -91,7 +84,7 @@ private static Collection loadBackends(ResourceLoader resourc /** * This is the main entry point. Used from CLI, but not from JUnit. */ - public void run() throws IOException { + public void run() { // Make sure all features parse before initialising any reporters/formatters List features = runtimeOptions.cucumberFeatures(resourceLoader, bus); @@ -106,7 +99,6 @@ public void run() throws IOException { } bus.send(new TestRunFinished(bus.getTime())); - printSummary(); } public void reportStepDefinitions(StepDefinitionReporter stepDefinitionReporter) { @@ -139,25 +131,8 @@ public boolean matchesFilters(PickleEvent pickleEvent) { return true; } - public void printSummary() { - SummaryPrinter summaryPrinter = runtimeOptions.summaryPrinter(classLoader); - summaryPrinter.print(this); - } - - public void printStats(PrintStream out) { - stats.printStats(out, runtimeOptions.isStrict()); - } - - public List getErrors() { - return stats.getErrors(); - } - public byte exitStatus() { - return stats.exitStatus(runtimeOptions.isStrict()); - } - - public List getSnippets() { - return undefinedStepsTracker.getSnippets(); + return exitStatus.exitStatus(runtimeOptions.isStrict()); } public Glue getGlue() { diff --git a/core/src/main/java/cucumber/runtime/RuntimeOptions.java b/core/src/main/java/cucumber/runtime/RuntimeOptions.java index a7611362b5..a1b71f1a6d 100644 --- a/core/src/main/java/cucumber/runtime/RuntimeOptions.java +++ b/core/src/main/java/cucumber/runtime/RuntimeOptions.java @@ -3,7 +3,6 @@ import cucumber.api.Plugin; import cucumber.api.SnippetType; import cucumber.api.StepDefinitionReporter; -import cucumber.api.SummaryPrinter; import cucumber.api.event.TestRunStarted; import cucumber.api.formatter.ColorAware; import cucumber.api.formatter.Formatter; @@ -127,6 +126,12 @@ public RuntimeOptions(Env env, PluginFactory pluginFactory, List argv) { } } + public RuntimeOptions noSummaryPrinter(){ + pluginSummaryPrinterNames.clear(); + return this; + } + + private void parse(List args) { List parsedTagFilters = new ArrayList(); List parsedNameFilters = new ArrayList(); @@ -348,10 +353,6 @@ public StepDefinitionReporter stepDefinitionReporter(ClassLoader classLoader) { return pluginProxy(classLoader, StepDefinitionReporter.class); } - public SummaryPrinter summaryPrinter(ClassLoader classLoader) { - return pluginProxy(classLoader, SummaryPrinter.class); - } - /** * Creates a dynamic proxy that multiplexes method invocations to all plugins of the same type. * @@ -465,12 +466,12 @@ class ParsedPluginData { ParsedOptionNames summaryPrinterNames = new ParsedOptionNames(); public void addPluginName(String name, boolean isAddPlugin) { - if (PluginFactory.isFormatterName(name)) { - formatterNames.addName(name, isAddPlugin); - } else if (PluginFactory.isStepDefinitionReporterName(name)) { + if (PluginFactory.isStepDefinitionReporterName(name)) { stepDefinitionReporterNames.addName(name, isAddPlugin); } else if (PluginFactory.isSummaryPrinterName(name)) { summaryPrinterNames.addName(name, isAddPlugin); + } else if (PluginFactory.isFormatterName(name)) { + formatterNames.addName(name, isAddPlugin); } else { throw new CucumberException("Unrecognized plugin: " + name); } diff --git a/core/src/main/java/cucumber/runtime/Stats.java b/core/src/main/java/cucumber/runtime/Stats.java index 249a899e37..fe4b4d8bea 100755 --- a/core/src/main/java/cucumber/runtime/Stats.java +++ b/core/src/main/java/cucumber/runtime/Stats.java @@ -9,6 +9,8 @@ import cucumber.api.event.TestRunFinished; import cucumber.api.event.TestRunStarted; import cucumber.api.event.TestStepFinished; +import cucumber.api.formatter.ColorAware; +import cucumber.api.formatter.StrictAware; import cucumber.runtime.formatter.AnsiFormats; import cucumber.runtime.formatter.Format; import cucumber.runtime.formatter.Formats; @@ -21,15 +23,14 @@ import java.util.List; import java.util.Locale; -class Stats implements EventListener { - public static final long ONE_SECOND = 1000000000; - public static final long ONE_MINUTE = 60 * ONE_SECOND; - private static final byte ERRORS = 0x1; +public class Stats implements EventListener, ColorAware, StrictAware { + static final long ONE_SECOND = 1000000000; + static final long ONE_MINUTE = 60 * ONE_SECOND; private SubCounts scenarioSubCounts = new SubCounts(); private SubCounts stepSubCounts = new SubCounts(); private long startTime = 0; private long totalDuration = 0; - private Formats formats; + private Formats formats = new AnsiFormats(); private Locale locale; private final List failedScenarios = new ArrayList(); private List ambiguousScenarios = new ArrayList(); @@ -66,13 +67,18 @@ public void receive(TestRunFinished event) { setFinishTime(event.getTimeStamp()); } }; + private boolean strict; - public Stats(boolean monochrome) { - this(monochrome, Locale.getDefault()); + public Stats() { + this(Locale.getDefault()); } - public Stats(boolean monochrome, Locale locale) { + Stats(Locale locale) { this.locale = locale; + } + + @Override + public void setMonochrome(boolean monochrome) { if (monochrome) { formats = new MonochromeFormats(); } else { @@ -80,6 +86,10 @@ public Stats(boolean monochrome, Locale locale) { } } + @Override + public void setStrict(boolean strict) { + this.strict = true; + } @Override public void setEventPublisher(EventPublisher publisher) { @@ -93,16 +103,8 @@ public List getErrors() { return errors; } - public byte exitStatus(boolean isStrict) { - byte result = 0x0; - if (!failedScenarios.isEmpty() || !ambiguousScenarios.isEmpty() || (isStrict && (!pendingScenarios.isEmpty() || !undefinedScenarios.isEmpty()))) { - result |= ERRORS; - } - return result; - } - - public void printStats(PrintStream out, boolean isStrict) { - printNonZeroResultScenarios(out, isStrict); + public void printStats(PrintStream out) { + printNonZeroResultScenarios(out); if (stepSubCounts.getTotal() == 0) { out.println("0 Scenarios"); out.println("0 Steps"); @@ -155,10 +157,10 @@ private void printDuration(PrintStream out) { out.println(format.format(((double) (totalDuration % ONE_MINUTE)) / ONE_SECOND) + "s"); } - private void printNonZeroResultScenarios(PrintStream out, boolean isStrict) { + private void printNonZeroResultScenarios(PrintStream out) { printScenarios(out, failedScenarios, Result.Type.FAILED); printScenarios(out, ambiguousScenarios, Result.Type.AMBIGUOUS); - if (isStrict) { + if (strict) { printScenarios(out, pendingScenarios, Result.Type.PENDING); printScenarios(out, undefinedScenarios, Result.Type.UNDEFINED); } diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index 7596b02300..18c56fbfe6 100644 --- a/core/src/test/java/cucumber/runtime/RuntimeTest.java +++ b/core/src/test/java/cucumber/runtime/RuntimeTest.java @@ -268,118 +268,6 @@ public void should_throw_cucumer_exception_if_no_backends_are_found() throws Exc } } - @Test - public void should_add_passed_result_to_the_summary_counter() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = mock(PickleStepDefinitionMatch.class); - - Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), startsWith(String.format( - "1 Scenarios (1 passed)%n" + - "1 Steps (1 passed)%n"))); - } - - @Test - public void should_add_pending_result_to_the_summary_counter() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = createExceptionThrowingMatch(new PendingException()); - - Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 pending)%n" + - "1 Steps (1 pending)%n"))); - } - - @Test - public void should_add_failed_result_to_the_summary_counter() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = createExceptionThrowingMatch(new Exception()); - - Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 failed)%n" + - "1 Steps (1 failed)%n"))); - } - - @Test - public void should_add_ambiguous_match_as_failed_result_to_the_summary_counter() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - Runtime runtime = createRuntimeWithMockedGlueWithAmbiguousMatch("--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format(""+ - "1 Scenarios (1 ambiguous)%n" + - "1 Steps (1 ambiguous)%n"))); - } - - @Test - public void should_add_skipped_result_to_the_summary_counter() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = createExceptionThrowingMatch(new Exception()); - - Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome"); - runScenario(runtime, stepCount(2)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 failed)%n" + - "2 Steps (1 failed, 1 skipped)%n"))); - } - - @Test - public void should_add_undefined_result_to_the_summary_counter() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - Runtime runtime = createRuntimeWithMockedGlue(null, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 undefined)%n" + - "1 Steps (1 undefined)%n"))); - } - - @Test - public void should_fail_the_scenario_if_before_fails() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = mock(PickleStepDefinitionMatch.class); - HookDefinition hook = createExceptionThrowingHook(); - - Runtime runtime = createRuntimeWithMockedGlue(match, hook, HookType.Before, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 failed)%n" + - "1 Steps (1 skipped)%n"))); - } - - @Test - public void should_fail_the_scenario_if_after_fails() throws Throwable { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PickleStepDefinitionMatch match = mock(PickleStepDefinitionMatch.class); - HookDefinition hook = createExceptionThrowingHook(); - - Runtime runtime = createRuntimeWithMockedGlue(match, hook, HookType.After, "--monochrome"); - runScenario(runtime, stepCount(1)); - runtime.printStats(new PrintStream(baos)); - - assertThat(baos.toString(), containsString(String.format("" + - "1 Scenarios (1 failed)%n" + - "1 Steps (1 passed)%n"))); - } - @Test public void should_make_scenario_name_available_to_hooks() throws Throwable { CucumberFeature feature = TestHelper.feature("path/test.feature", diff --git a/core/src/test/java/cucumber/runtime/StatsTest.java b/core/src/test/java/cucumber/runtime/StatsTest.java index c6ae63dec6..f02a26f022 100755 --- a/core/src/test/java/cucumber/runtime/StatsTest.java +++ b/core/src/test/java/cucumber/runtime/StatsTest.java @@ -23,8 +23,7 @@ public class StatsTest { public void should_print_zero_scenarios_zero_steps_if_nothing_has_executed() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "0 Scenarios%n" + @@ -40,7 +39,7 @@ public void should_only_print_sub_counts_if_not_zero() { counter.addStep(Result.Type.PASSED); counter.addStep(Result.Type.PASSED); counter.addScenario(Result.Type.PASSED, "scenario designation"); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format( "1 Scenarios (1 passed)%n" + @@ -58,7 +57,7 @@ public void should_print_sub_counts_in_order_failed_ambiguous_skipped_pending_un addOneStepScenario(counter, Result.Type.PENDING); addOneStepScenario(counter, Result.Type.UNDEFINED); addOneStepScenario(counter, Result.Type.SKIPPED); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), containsString(String.format("" + "6 Scenarios (1 failed, 1 ambiguous, 1 skipped, 1 pending, 1 undefined, 1 passed)%n" + @@ -76,7 +75,7 @@ public void should_print_sub_counts_in_order_failed_ambiguous_skipped_undefined_ addOneStepScenario(counter, Result.Type.PENDING); addOneStepScenario(counter, Result.Type.UNDEFINED); addOneStepScenario(counter, Result.Type.SKIPPED); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); String colorSubCounts = "" + AnsiEscapes.RED + "1 failed" + AnsiEscapes.RESET + ", " + @@ -95,7 +94,7 @@ public void should_print_zero_m_zero_s_if_nothing_has_executed() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), endsWith(String.format( "0m0.000s%n"))); @@ -108,7 +107,7 @@ public void should_report_the_difference_between_finish_time_and_start_time() { counter.setStartTime(ANY_TIME); counter.setFinishTime(ANY_TIME + 4*ONE_MILLI_SECOND); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), endsWith(String.format( "0m0.004s%n"))); @@ -121,7 +120,7 @@ public void should_print_minutes_seconds_and_milliseconds() { counter.setStartTime(ANY_TIME); counter.setFinishTime(ANY_TIME + Stats.ONE_MINUTE + Stats.ONE_SECOND + ONE_MILLI_SECOND); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), endsWith(String.format( "1m1.001s%n"))); @@ -134,7 +133,7 @@ public void should_print_minutes_instead_of_hours() { counter.setStartTime(ANY_TIME); counter.setFinishTime(ANY_TIME + ONE_HOUR + Stats.ONE_MINUTE); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), endsWith(String.format( "61m0.000s%n"))); @@ -142,12 +141,13 @@ public void should_print_minutes_instead_of_hours() { @Test public void should_use_locale_for_decimal_separator() { - Stats counter = new Stats(true, Locale.GERMANY); + Stats counter = new Stats(Locale.GERMANY); + counter.setStrict(true); ByteArrayOutputStream baos = new ByteArrayOutputStream(); counter.setStartTime(ANY_TIME); counter.setFinishTime(ANY_TIME + Stats.ONE_MINUTE + Stats.ONE_SECOND + ONE_MILLI_SECOND); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), endsWith(String.format( "1m1,001s%n"))); @@ -166,7 +166,7 @@ public void should_print_failed_ambiguous_scenarios() { counter.addScenario(Result.Type.UNDEFINED, "path/file.feature:3 # Scenario: scenario_name"); counter.addStep(Result.Type.PENDING); counter.addScenario(Result.Type.PENDING, "path/file.feature:3 # Scenario: scenario_name"); - counter.printStats(new PrintStream(baos), isStrict(false)); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format("" + "Failed scenarios:%n" + @@ -191,7 +191,8 @@ public void should_print_failed_ambiguous_pending_undefined_scenarios_if_strict( counter.addScenario(Result.Type.UNDEFINED, "path/file.feature:3 # Scenario: scenario_name"); counter.addStep(Result.Type.PENDING); counter.addScenario(Result.Type.PENDING, "path/file.feature:3 # Scenario: scenario_name"); - counter.printStats(new PrintStream(baos), isStrict(true)); + counter.setStrict(true); + counter.printStats(new PrintStream(baos)); assertThat(baos.toString(), startsWith(String.format("" + "Failed scenarios:%n" + @@ -215,14 +216,13 @@ private void addOneStepScenario(Stats counter, Result.Type status) { } private Stats createMonochromeSummaryCounter() { - return new Stats(true, Locale.US); + Stats stats = new Stats(Locale.US); + stats.setMonochrome(true); + return stats; } private Stats createColorSummaryCounter() { - return new Stats(false, Locale.US); + return new Stats(Locale.US); } - private boolean isStrict(boolean isStrict) { - return isStrict; - } } diff --git a/examples/pax-exam/calculator-test/src/test/java/cucumber/examples/java/paxexam/test/CalculatorTest.java b/examples/pax-exam/calculator-test/src/test/java/cucumber/examples/java/paxexam/test/CalculatorTest.java index becb5d64da..e006519ba5 100644 --- a/examples/pax-exam/calculator-test/src/test/java/cucumber/examples/java/paxexam/test/CalculatorTest.java +++ b/examples/pax-exam/calculator-test/src/test/java/cucumber/examples/java/paxexam/test/CalculatorTest.java @@ -1,15 +1,18 @@ package cucumber.examples.java.paxexam.test; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.options; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import javax.inject.Inject; +import cucumber.api.event.EventHandler; +import cucumber.api.event.TestStepFinished; import cucumber.api.java.ObjectFactory; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,14 +84,24 @@ public void cucumber() throws Exception { final RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); final Runtime runtime = new Runtime(resourceLoader, classLoader, Collections.singleton(backend), runtimeOptions); + final List errors = new ArrayList(); + + + runtime.getEventBus().registerHandlerFor(TestStepFinished.class, new EventHandler() { + @Override + public void receive(TestStepFinished event) { + Throwable error = event.result.getError(); + if(error != null) + errors.add(error); + } + }); runtime.run(); - if (!runtime.getErrors().isEmpty()) { - throw new CucumberException(runtime.getErrors().get(0)); + if (!errors.isEmpty()) { + throw new CucumberException(errors.get(0)); } else if (runtime.exitStatus() != 0x00) { throw new CucumberException("There are pending or undefined steps."); } - assertEquals(runtime.getErrors().size(), 0); } } diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index 49894cc279..7126b38f1d 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -107,7 +107,6 @@ protected Statement childrenInvoker(RunNotifier notifier) { public void evaluate() throws Throwable { features.evaluate(); runtime.getEventBus().send(new TestRunFinished(runtime.getEventBus().getTime())); - runtime.printSummary(); } }; } diff --git a/testng/src/main/java/cucumber/api/testng/TestNGCucumberRunner.java b/testng/src/main/java/cucumber/api/testng/TestNGCucumberRunner.java index 91ec91e74c..45574645f5 100644 --- a/testng/src/main/java/cucumber/api/testng/TestNGCucumberRunner.java +++ b/testng/src/main/java/cucumber/api/testng/TestNGCucumberRunner.java @@ -62,7 +62,6 @@ public void runScenario(PickleEvent pickle) throws Throwable { public void finish() { runtime.getEventBus().send(new TestRunFinished(runtime.getEventBus().getTime())); - runtime.printSummary(); } /**