From d8559dccdb4a3c13173b7a82387c84a2ce0df4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Rasmusson?= Date: Sun, 2 Jul 2017 20:50:59 +0200 Subject: [PATCH] [Core] Add TestRunStarted event, let Stats handle the exit code Add the TestRunStarted event and present the duration between the TestRunStarted and TestRunFinished events in the summary print out. Move the handling of exit code and errors to the summary print out to the Stats class. --- .../cucumber/api/event/TestRunStarted.java | 8 ++ .../main/java/cucumber/runtime/Runtime.java | 104 +----------------- .../java/cucumber/runtime/RuntimeOptions.java | 2 + .../src/main/java/cucumber/runtime/Stats.java | 90 ++++++++++++--- .../java/cucumber/runtime/RuntimeTest.java | 38 +++---- .../test/java/cucumber/runtime/StatsTest.java | 54 ++++----- 6 files changed, 132 insertions(+), 164 deletions(-) create mode 100644 core/src/main/java/cucumber/api/event/TestRunStarted.java diff --git a/core/src/main/java/cucumber/api/event/TestRunStarted.java b/core/src/main/java/cucumber/api/event/TestRunStarted.java new file mode 100644 index 0000000000..1dc1453a2b --- /dev/null +++ b/core/src/main/java/cucumber/api/event/TestRunStarted.java @@ -0,0 +1,8 @@ +package cucumber.api.event; + +public final class TestRunStarted extends TimeStampedEvent { + + public TestRunStarted(Long timeStamp) { + super(timeStamp); + } +} diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index 8f7a08a445..34174a352a 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -1,11 +1,7 @@ package cucumber.runtime; -import cucumber.api.Pending; -import cucumber.api.Result; import cucumber.api.StepDefinitionReporter; import cucumber.api.SummaryPrinter; -import cucumber.api.event.EventHandler; -import cucumber.api.event.TestCaseFinished; import cucumber.api.event.TestRunFinished; import cucumber.api.event.TestStepFinished; import cucumber.runner.EventBus; @@ -21,7 +17,6 @@ import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; @@ -32,50 +27,17 @@ */ public class Runtime { - private static final String[] ASSUMPTION_VIOLATED_EXCEPTIONS = { - "org.junit.AssumptionViolatedException", - "org.junit.internal.AssumptionViolatedException" - }; - - static { - Arrays.sort(ASSUMPTION_VIOLATED_EXCEPTIONS); - } - - private static final byte ERRORS = 0x1; - - private final Stats stats; - UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); // package private to be avaiable for tests. + final Stats stats; // package private to be avaiable for tests. + private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); private final RuntimeOptions runtimeOptions; - private final List errors = new ArrayList(); private final ResourceLoader resourceLoader; private final ClassLoader classLoader; private final Runner runner; private final List filters; private final EventBus bus; private final Compiler compiler = new Compiler(); - private final EventHandler stepFinishedHandler = new EventHandler() { - @Override - public void receive(TestStepFinished event) { - Result result = event.result; - if (result.getError() != null) { - addError(result.getError()); - } - if (event.testStep.isHook()) { - addHookToCounterAndResult(result); - } else { - addStepToCounterAndResult(result); - } - } - }; - private final EventHandler testCaseFinishedHandler = new EventHandler() { - @Override - public void receive(TestCaseFinished event) { - stats.addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation()); - } - }; - public Runtime(ResourceLoader resourceLoader, ClassFinder classFinder, ClassLoader classLoader, RuntimeOptions runtimeOptions) { this(resourceLoader, classLoader, loadBackends(resourceLoader, classFinder), runtimeOptions); } @@ -115,8 +77,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio this.filters.add(new LinePredicate(lineFilters)); } - bus.registerHandlerFor(TestStepFinished.class, stepFinishedHandler); - bus.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler); + stats.setEventPublisher(bus); undefinedStepsTracker.setEventPublisher(bus); runtimeOptions.setEventBus(bus); } @@ -126,10 +87,6 @@ private static Collection loadBackends(ResourceLoader resourc return reflections.instantiateSubclasses(Backend.class, "cucumber.runtime", new Class[]{ResourceLoader.class}, new Object[]{resourceLoader}); } - public void addError(Throwable error) { - errors.add(error); - } - /** * This is the main entry point. Used from CLI, but not from JUnit. */ @@ -191,40 +148,11 @@ void printStats(PrintStream out) { } public List getErrors() { - return errors; + return stats.getErrors(); } public byte exitStatus() { - byte result = 0x0; - if (hasErrors() || hasUndefinedOrPendingStepsAndIsStrict()) { - result |= ERRORS; - } - return result; - } - - private boolean hasUndefinedOrPendingStepsAndIsStrict() { - return runtimeOptions.isStrict() && hasUndefinedOrPendingSteps(); - } - - private boolean hasUndefinedOrPendingSteps() { - return hasUndefinedSteps() || hasPendingSteps(); - } - - private boolean hasUndefinedSteps() { - return undefinedStepsTracker.hasUndefinedSteps(); - } - - private boolean hasPendingSteps() { - return !errors.isEmpty() && !hasErrors(); - } - - private boolean hasErrors() { - for (Throwable error : errors) { - if (!isPending(error) && !isAssumptionViolated(error)) { - return true; - } - } - return false; + return stats.exitStatus(runtimeOptions.isStrict()); } public List getSnippets() { @@ -235,28 +163,6 @@ public Glue getGlue() { return runner.getGlue(); } - public static boolean isPending(Throwable t) { - if (t == null) { - return false; - } - return t.getClass().isAnnotationPresent(Pending.class); - } - - public static boolean isAssumptionViolated(Throwable t) { - if (t == null) { - return false; - } - return Arrays.binarySearch(ASSUMPTION_VIOLATED_EXCEPTIONS, t.getClass().getName()) >= 0; - } - - private void addStepToCounterAndResult(Result result) { - stats.addStep(result); - } - - private void addHookToCounterAndResult(Result result) { - stats.addHookTime(result.getDuration()); - } - public EventBus getEventBus() { return bus; } diff --git a/core/src/main/java/cucumber/runtime/RuntimeOptions.java b/core/src/main/java/cucumber/runtime/RuntimeOptions.java index 073759a793..d12b2c1dbf 100644 --- a/core/src/main/java/cucumber/runtime/RuntimeOptions.java +++ b/core/src/main/java/cucumber/runtime/RuntimeOptions.java @@ -3,6 +3,7 @@ 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; import cucumber.api.formatter.StrictAware; @@ -308,6 +309,7 @@ private void addKeywordRow(List> table, String key, List ke public List cucumberFeatures(ResourceLoader resourceLoader, EventBus bus) { List features = load(resourceLoader, featurePaths, System.out); getPlugins(); // to create the formatter objects + bus.send(new TestRunStarted(bus.getTime())); for (CucumberFeature feature : features) { feature.sendTestSourceRead(bus); } diff --git a/core/src/main/java/cucumber/runtime/Stats.java b/core/src/main/java/cucumber/runtime/Stats.java index 53723b59b5..21ac544d19 100755 --- a/core/src/main/java/cucumber/runtime/Stats.java +++ b/core/src/main/java/cucumber/runtime/Stats.java @@ -1,6 +1,13 @@ 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 cucumber.api.event.TestRunFinished; +import cucumber.api.event.TestRunStarted; +import cucumber.api.event.TestStepFinished; import cucumber.runtime.formatter.AnsiFormats; import cucumber.runtime.formatter.Format; import cucumber.runtime.formatter.Formats; @@ -13,18 +20,51 @@ import java.util.List; import java.util.Locale; -class Stats { +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; private SubCounts scenarioSubCounts = new SubCounts(); private SubCounts stepSubCounts = new SubCounts(); + private long startTime = 0; private long totalDuration = 0; private Formats formats; private Locale locale; - private List failedScenarios = new ArrayList(); + private final List failedScenarios = new ArrayList(); private List ambiguousScenarios = new ArrayList(); - private List pendingScenarios = new ArrayList(); - private List undefinedScenarios = new ArrayList(); + private final List pendingScenarios = new ArrayList(); + private final List undefinedScenarios = new ArrayList(); + private final List errors = new ArrayList(); + private final EventHandler testRunStartedHandler = new EventHandler() { + @Override + public void receive(TestRunStarted event) { + setStartTime(event.getTimeStamp()); + } + }; + private final EventHandler stepFinishedHandler = new EventHandler() { + @Override + public void receive(TestStepFinished event) { + Result result = event.result; + if (result.getError() != null) { + addError(result.getError()); + } + if (!event.testStep.isHook()) { + addStep(result.getStatus()); + } + } + }; + private final EventHandler testCaseFinishedHandler = new EventHandler() { + @Override + public void receive(TestCaseFinished event) { + addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation()); + } + }; + private final EventHandler testRunFinishedHandler = new EventHandler() { + @Override + public void receive(TestRunFinished event) { + setFinishTime(event.getTimeStamp()); + } + }; public Stats(boolean monochrome) { this(monochrome, Locale.getDefault()); @@ -39,6 +79,27 @@ public Stats(boolean monochrome, Locale locale) { } } + + @Override + public void setEventPublisher(EventPublisher publisher) { + publisher.registerHandlerFor(TestRunStarted.class, testRunStartedHandler); + publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler); + publisher.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler); + publisher.registerHandlerFor(TestRunFinished.class, testRunFinishedHandler); + } + + public List getErrors() { + return errors; + } + + public byte exitStatus(boolean isStrict) { + byte result = 0x0; + if (!failedScenarios.isEmpty() || (isStrict && (!pendingScenarios.isEmpty() || !undefinedScenarios.isEmpty()))) { + result |= ERRORS; + } + return result; + } + public void printStats(PrintStream out, boolean isStrict) { printNonZeroResultScenarios(out, isStrict); if (stepSubCounts.getTotal() == 0) { @@ -119,21 +180,20 @@ private void printScenarios(PrintStream out, List scenarios, Result.Type } } - public void addStep(Result result) { - addResultToSubCount(stepSubCounts, result.getStatus()); - addTime(result.getDuration()); + void addStep(Result.Type resultStatus) { + addResultToSubCount(stepSubCounts, resultStatus); } - public void addScenario(Result.Type resultStatus) { - addResultToSubCount(scenarioSubCounts, resultStatus); + private void addError(Throwable error) { + errors.add(error); } - public void addHookTime(Long duration) { - addTime(duration); + void setStartTime(Long startTime) { + this.startTime = startTime; } - private void addTime(Long duration) { - totalDuration += duration != null ? duration : 0; + void setFinishTime(Long finishTime) { + this.totalDuration = finishTime - startTime; } private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus) { @@ -158,7 +218,7 @@ private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus) } } - public void addScenario(Result.Type resultStatus, String scenarioDesignation) { + void addScenario(Result.Type resultStatus, String scenarioDesignation) { addResultToSubCount(scenarioSubCounts, resultStatus); switch (resultStatus) { case FAILED: @@ -178,7 +238,7 @@ public void addScenario(Result.Type resultStatus, String scenarioDesignation) { } } - class SubCounts { + static class SubCounts { public int passed = 0; public int failed = 0; public int ambiguous = 0; diff --git a/core/src/test/java/cucumber/runtime/RuntimeTest.java b/core/src/test/java/cucumber/runtime/RuntimeTest.java index 1b62ddda13..42adae05de 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.api.Scenario; import cucumber.api.StepDefinitionReporter; import cucumber.api.TestCase; -import cucumber.api.TestStep; import cucumber.api.event.TestCaseFinished; import cucumber.runtime.formatter.FormatterSpy; import cucumber.runtime.io.ClasspathResourceLoader; @@ -13,14 +12,12 @@ import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.model.CucumberFeature; import gherkin.events.PickleEvent; -import gherkin.pickles.Argument; import gherkin.pickles.Pickle; import gherkin.pickles.PickleLocation; import gherkin.pickles.PickleStep; import gherkin.pickles.PickleTag; import org.junit.Ignore; import org.junit.Test; -import org.junit.AssumptionViolatedException; import org.mockito.ArgumentCaptor; import java.io.ByteArrayOutputStream; @@ -129,76 +126,79 @@ public void runs_feature_with_json_formatter() throws Exception { } @Test - public void strict_without_pending_steps_or_errors() { + public void strict_with_passed_scenarios() { Runtime runtime = createStrictRuntime(); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.PASSED)); assertEquals(0x0, runtime.exitStatus()); } @Test - public void non_strict_without_pending_steps_or_errors() { + public void non_strict_with_passed_scenarios() { Runtime runtime = createNonStrictRuntime(); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.PASSED)); assertEquals(0x0, runtime.exitStatus()); } @Test - public void non_strict_with_undefined_steps() { + public void non_strict_with_undefined_scenarios() { Runtime runtime = createNonStrictRuntime(); runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.UNDEFINED)); assertEquals(0x0, runtime.exitStatus()); } - public void strict_with_undefined_steps() { + @Test + public void strict_with_undefined_scenarios() { Runtime runtime = createStrictRuntime(); runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.UNDEFINED)); assertEquals(0x1, runtime.exitStatus()); } @Test - public void strict_with_pending_steps_and_no_errors() { + public void strict_with_pending_scenarios() { Runtime runtime = createStrictRuntime(); - runtime.addError(new PendingException()); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.PENDING)); assertEquals(0x1, runtime.exitStatus()); } @Test - public void non_strict_with_pending_steps() { + public void non_strict_with_pending_scenarios() { Runtime runtime = createNonStrictRuntime(); - runtime.addError(new PendingException()); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.PENDING)); assertEquals(0x0, runtime.exitStatus()); } @Test - public void non_strict_with_failed_junit_assumption_prior_to_junit_412() { + public void non_strict_with_skipped_scenarios() { Runtime runtime = createNonStrictRuntime(); - runtime.addError(new org.junit.internal.AssumptionViolatedException("should be treated like skipped")); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.SKIPPED)); assertEquals(0x0, runtime.exitStatus()); } @Test - public void non_strict_with_failed_junit_assumption_from_junit_412_on() { + public void strict_with_skipped_scenarios() { Runtime runtime = createNonStrictRuntime(); - runtime.addError(new AssumptionViolatedException("should be treated like skipped")); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.SKIPPED)); assertEquals(0x0, runtime.exitStatus()); } @Test - public void non_strict_with_errors() { + public void non_strict_with_failed_scenarios() { Runtime runtime = createNonStrictRuntime(); - runtime.addError(new RuntimeException()); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.FAILED)); assertEquals(0x1, runtime.exitStatus()); } @Test - public void strict_with_errors() { + public void strict_with_failed_scenarios() { Runtime runtime = createStrictRuntime(); - runtime.addError(new RuntimeException()); + runtime.getEventBus().send(testCaseFinishedWithStatus(Result.Type.FAILED)); assertEquals(0x1, runtime.exitStatus()); } diff --git a/core/src/test/java/cucumber/runtime/StatsTest.java b/core/src/test/java/cucumber/runtime/StatsTest.java index 8860a4a8c1..c6ae63dec6 100755 --- a/core/src/test/java/cucumber/runtime/StatsTest.java +++ b/core/src/test/java/cucumber/runtime/StatsTest.java @@ -15,6 +15,7 @@ import org.junit.Test; public class StatsTest { + public static final long ANY_TIME = 1234567890; public static final long ONE_MILLI_SECOND = 1000000; private static final long ONE_HOUR = 60 * Stats.ONE_MINUTE; @@ -33,13 +34,12 @@ public void should_print_zero_scenarios_zero_steps_if_nothing_has_executed() { @Test public void should_only_print_sub_counts_if_not_zero() { Stats counter = createMonochromeSummaryCounter(); - Result passedResult = createResultWithStatus(Result.Type.PASSED); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(passedResult); - counter.addStep(passedResult); - counter.addStep(passedResult); - counter.addScenario(Result.Type.PASSED); + counter.addStep(Result.Type.PASSED); + counter.addStep(Result.Type.PASSED); + counter.addStep(Result.Type.PASSED); + counter.addScenario(Result.Type.PASSED, "scenario designation"); counter.printStats(new PrintStream(baos), isStrict(false)); assertThat(baos.toString(), startsWith(String.format( @@ -102,14 +102,12 @@ public void should_print_zero_m_zero_s_if_nothing_has_executed() { } @Test - public void should_include_hook_time_and_step_time_has_executed() { + public void should_report_the_difference_between_finish_time_and_start_time() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addHookTime(ONE_MILLI_SECOND); - counter.addStep(new Result(Result.Type.PASSED, ONE_MILLI_SECOND, null)); - counter.addStep(new Result(Result.Type.PASSED, ONE_MILLI_SECOND, null)); - counter.addHookTime(ONE_MILLI_SECOND); + counter.setStartTime(ANY_TIME); + counter.setFinishTime(ANY_TIME + 4*ONE_MILLI_SECOND); counter.printStats(new PrintStream(baos), isStrict(false)); assertThat(baos.toString(), endsWith(String.format( @@ -121,9 +119,8 @@ public void should_print_minutes_seconds_and_milliseconds() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(new Result(Result.Type.PASSED, Stats.ONE_MINUTE, null)); - counter.addStep(new Result(Result.Type.PASSED, Stats.ONE_SECOND, null)); - counter.addStep(new Result(Result.Type.PASSED, ONE_MILLI_SECOND, null)); + counter.setStartTime(ANY_TIME); + counter.setFinishTime(ANY_TIME + Stats.ONE_MINUTE + Stats.ONE_SECOND + ONE_MILLI_SECOND); counter.printStats(new PrintStream(baos), isStrict(false)); assertThat(baos.toString(), endsWith(String.format( @@ -135,8 +132,8 @@ public void should_print_minutes_instead_of_hours() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(new Result(Result.Type.PASSED, ONE_HOUR, null)); - counter.addStep(new Result(Result.Type.PASSED, Stats.ONE_MINUTE, null)); + counter.setStartTime(ANY_TIME); + counter.setFinishTime(ANY_TIME + ONE_HOUR + Stats.ONE_MINUTE); counter.printStats(new PrintStream(baos), isStrict(false)); assertThat(baos.toString(), endsWith(String.format( @@ -148,9 +145,8 @@ public void should_use_locale_for_decimal_separator() { Stats counter = new Stats(true, Locale.GERMANY); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(new Result(Result.Type.PASSED, Stats.ONE_MINUTE, null)); - counter.addStep(new Result(Result.Type.PASSED, Stats.ONE_SECOND, null)); - counter.addStep(new Result(Result.Type.PASSED, ONE_MILLI_SECOND, null)); + counter.setStartTime(ANY_TIME); + counter.setFinishTime(ANY_TIME + Stats.ONE_MINUTE + Stats.ONE_SECOND + ONE_MILLI_SECOND); counter.printStats(new PrintStream(baos), isStrict(false)); assertThat(baos.toString(), endsWith(String.format( @@ -162,13 +158,13 @@ public void should_print_failed_ambiguous_scenarios() { Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(createResultWithStatus(Result.Type.FAILED)); + counter.addStep(Result.Type.FAILED); counter.addScenario(Result.Type.FAILED, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.AMBIGUOUS)); + counter.addStep(Result.Type.AMBIGUOUS); counter.addScenario(Result.Type.AMBIGUOUS, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.UNDEFINED)); + counter.addStep(Result.Type.UNDEFINED); counter.addScenario(Result.Type.UNDEFINED, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.PENDING)); + counter.addStep(Result.Type.PENDING); counter.addScenario(Result.Type.PENDING, "path/file.feature:3 # Scenario: scenario_name"); counter.printStats(new PrintStream(baos), isStrict(false)); @@ -187,13 +183,13 @@ public void should_print_failed_ambiguous_pending_undefined_scenarios_if_strict( Stats counter = createMonochromeSummaryCounter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - counter.addStep(createResultWithStatus(Result.Type.FAILED)); + counter.addStep(Result.Type.FAILED); counter.addScenario(Result.Type.FAILED, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.AMBIGUOUS)); + counter.addStep(Result.Type.AMBIGUOUS); counter.addScenario(Result.Type.AMBIGUOUS, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.UNDEFINED)); + counter.addStep(Result.Type.UNDEFINED); counter.addScenario(Result.Type.UNDEFINED, "path/file.feature:3 # Scenario: scenario_name"); - counter.addStep(createResultWithStatus(Result.Type.PENDING)); + counter.addStep(Result.Type.PENDING); counter.addScenario(Result.Type.PENDING, "path/file.feature:3 # Scenario: scenario_name"); counter.printStats(new PrintStream(baos), isStrict(true)); @@ -214,14 +210,10 @@ public void should_print_failed_ambiguous_pending_undefined_scenarios_if_strict( } private void addOneStepScenario(Stats counter, Result.Type status) { - counter.addStep(createResultWithStatus(status)); + counter.addStep(status); counter.addScenario(status, "scenario designation"); } - private Result createResultWithStatus(Result.Type status) { - return new Result(status, 0l, null); - } - private Stats createMonochromeSummaryCounter() { return new Stats(true, Locale.US); }