Skip to content

Commit

Permalink
[Core] The SummaryPrinter should only depend on api classes (#1361)
Browse files Browse the repository at this point in the history
* [Core] The SummaryPrinter should only depend on api classes

A plugin interface like the SummaryPrinter should only depend on
classes in cucumber.api packages.
  • Loading branch information
brasmusson authored and mpkorstanje committed May 18, 2018
1 parent 4d09d8c commit afc2581
Show file tree
Hide file tree
Showing 19 changed files with 206 additions and 254 deletions.
Expand Up @@ -18,6 +18,8 @@
import cucumber.runtime.Runtime; import cucumber.runtime.Runtime;
import cucumber.runtime.RuntimeOptions; import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.RuntimeOptionsFactory; import cucumber.runtime.RuntimeOptionsFactory;
import cucumber.runtime.Stats;
import cucumber.runtime.UndefinedStepsTracker;
import cucumber.runtime.formatter.AndroidInstrumentationReporter; import cucumber.runtime.formatter.AndroidInstrumentationReporter;
import cucumber.runtime.formatter.AndroidLogcatReporter; import cucumber.runtime.formatter.AndroidLogcatReporter;
import cucumber.runtime.io.MultiLoader; import cucumber.runtime.io.MultiLoader;
Expand Down Expand Up @@ -94,13 +96,18 @@ public CucumberExecutor(final Arguments arguments, final Instrumentation instrum
this.instrumentation = instrumentation; this.instrumentation = instrumentation;
this.classLoader = context.getClassLoader(); this.classLoader = context.getClassLoader();
this.classFinder = createDexClassFinder(context); this.classFinder = createDexClassFinder(context);
this.runtimeOptions = createRuntimeOptions(context); this.runtimeOptions = createRuntimeOptions(context).noSummaryPrinter();


ResourceLoader resourceLoader = new AndroidResourceLoader(context); ResourceLoader resourceLoader = new AndroidResourceLoader(context);
this.runtime = new Runtime(resourceLoader, classLoader, createBackends(), runtimeOptions); 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(instrumentationReporter);
runtimeOptions.addPlugin(new AndroidLogcatReporter(runtime, TAG)); runtimeOptions.addPlugin(new AndroidLogcatReporter(stats, undefinedStepsTracker, TAG));


List<CucumberFeature> cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader, runtime.getEventBus()); List<CucumberFeature> cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader, runtime.getEventBus());
this.pickleEvents = FeatureCompiler.compile(cucumberFeatures, this.runtime); this.pickleEvents = FeatureCompiler.compile(cucumberFeatures, this.runtime);
Expand Down
Expand Up @@ -11,7 +11,7 @@
import cucumber.api.event.TestSourceRead; import cucumber.api.event.TestSourceRead;
import cucumber.api.event.TestStepFinished; import cucumber.api.event.TestStepFinished;
import cucumber.api.formatter.Formatter; import cucumber.api.formatter.Formatter;
import cucumber.runtime.Runtime; import cucumber.runtime.UndefinedStepsTracker;
import cucumber.runtime.Utils; import cucumber.runtime.Utils;


import java.io.PrintWriter; import java.io.PrintWriter;
Expand Down Expand Up @@ -68,11 +68,6 @@ static class StatusCodes {
*/ */
private final TestSourcesModel testSources = new TestSourcesModel(); private final TestSourcesModel testSources = new TestSourcesModel();


/**
* The current cucumber runtime.
*/
private final Runtime runtime;

/** /**
* The instrumentation to report to. * The instrumentation to report to.
*/ */
Expand Down Expand Up @@ -144,14 +139,16 @@ public void receive(TestCaseFinished event) {
} }
}; };


private final UndefinedStepsTracker undefinedStepsTracker;


/** /**
* Creates a new instance for the given parameters * 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 * @param instrumentation the {@link android.app.Instrumentation} to report statuses to
*/ */
public AndroidInstrumentationReporter(final Runtime runtime, final Instrumentation instrumentation) { public AndroidInstrumentationReporter(final UndefinedStepsTracker undefinedStepsTracker, final Instrumentation instrumentation) {
this.runtime = runtime; this.undefinedStepsTracker = undefinedStepsTracker;
this.instrumentation = instrumentation; this.instrumentation = instrumentation;
} }


Expand Down Expand Up @@ -242,7 +239,7 @@ private Bundle createBundle(final String path, final String testCaseName) {
* @return string representation of the snippet * @return string representation of the snippet
*/ */
private String getLastSnippet() { private String getLastSnippet() {
return runtime.getSnippets().get(runtime.getSnippets().size() - 1); return undefinedStepsTracker.getSnippets().get(undefinedStepsTracker.getSnippets().size() - 1);
} }


/** /**
Expand Down
Expand Up @@ -8,17 +8,13 @@
import cucumber.api.event.TestRunFinished; import cucumber.api.event.TestRunFinished;
import cucumber.api.event.TestStepStarted; import cucumber.api.event.TestStepStarted;
import cucumber.api.formatter.Formatter; 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. * Logs information about the currently executed statements to androids logcat.
*/ */
public final class AndroidLogcatReporter implements Formatter { 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;


/** /**
* The log tag to be used when logging to logcat. * The log tag to be used when logging to logcat.
Expand All @@ -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. * The event handler that logs the {@link TestStepStarted} events.
*/ */
Expand All @@ -55,11 +55,11 @@ public void receive(TestStepStarted event) {


@Override @Override
public void receive(TestRunFinished event) { public void receive(TestRunFinished event) {
for (final Throwable throwable : runtime.getErrors()) { for (final Throwable throwable : stats.getErrors()) {
Log.e(logTag, throwable.toString()); Log.e(logTag, throwable.toString());
} }


for (final String snippet : runtime.getSnippets()) { for (final String snippet : undefinedStepsTracker.getSnippets()) {
Log.w(logTag, snippet); Log.w(logTag, snippet);
} }
} }
Expand All @@ -68,11 +68,12 @@ public void receive(TestRunFinished event) {
/** /**
* Creates a new instance for the given parameters. * 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 * @param logTag the tag to use for logging to logcat
*/ */
public AndroidLogcatReporter(final Runtime runtime, final String logTag) { public AndroidLogcatReporter(Stats stats, UndefinedStepsTracker undefinedStepsTracker, final String logTag) {
this.runtime = runtime; this.stats = stats;
this.undefinedStepsTracker = undefinedStepsTracker;
this.logTag = logTag; this.logTag = logTag;
} }


Expand Down
Expand Up @@ -17,7 +17,7 @@
import cucumber.api.Result; import cucumber.api.Result;
import cucumber.api.TestCase; import cucumber.api.TestCase;
import cucumber.api.event.TestSourceRead; import cucumber.api.event.TestSourceRead;
import cucumber.runtime.Runtime; import cucumber.runtime.UndefinedStepsTracker;
import cucumber.runtime.formatter.AndroidInstrumentationReporter.StatusCodes; import cucumber.runtime.formatter.AndroidInstrumentationReporter.StatusCodes;
import edu.emory.mathcs.backport.java.util.Collections; import edu.emory.mathcs.backport.java.util.Collections;
import org.junit.Before; import org.junit.Before;
Expand All @@ -39,7 +39,7 @@ public class AndroidInstrumentationReporterTest {
@Rule @Rule
public final ExpectedException expectedException = ExpectedException.none(); 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 Instrumentation instrumentation = mock(Instrumentation.class);


private final TestSourceRead testSourceRead = new TestSourceRead( private final TestSourceRead testSourceRead = new TestSourceRead(
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/cucumber/api/Plugin.java
Expand Up @@ -29,6 +29,14 @@
* </ul> * </ul>
* <p> * <p>
* To make the parameter optional the plugin must also have a public default constructor. * To make the parameter optional the plugin must also have a public default constructor.
* <p>
* Plugins may also implement one of these interfaces:
* <ul>
* <li>{@link cucumber.api.formatter.ColorAware}</li>
* <li>{@link cucumber.api.formatter.StrictAware}</li>
* <li>{@link cucumber.api.event.EventListener}</li>
* </ul>
* <p>
*/ */
public interface Plugin { public interface Plugin {
} }
4 changes: 1 addition & 3 deletions core/src/main/java/cucumber/api/SummaryPrinter.java
@@ -1,12 +1,10 @@
package cucumber.api; package cucumber.api;


import cucumber.runtime.Runtime;

/** /**
* Interface for plugins that print a summary after test execution. * Interface for plugins that print a summary after test execution.
* *
* @see Plugin * @see Plugin
*/ */
public interface SummaryPrinter extends Plugin { public interface SummaryPrinter extends Plugin {
void print(Runtime runtime);
} }
5 changes: 2 additions & 3 deletions core/src/main/java/cucumber/api/cli/Main.java
Expand Up @@ -14,7 +14,7 @@


public class Main { public class Main {


public static void main(String[] argv) throws Throwable { public static void main(String[] argv) {
byte exitstatus = run(argv, Thread.currentThread().getContextClassLoader()); byte exitstatus = run(argv, Thread.currentThread().getContextClassLoader());
System.exit(exitstatus); System.exit(exitstatus);
} }
Expand All @@ -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 argv runtime options. See details in the {@code cucumber.api.cli.Usage.txt} resource.
* @param classLoader classloader used to load the runtime * @param classLoader classloader used to load the runtime
* @return 0 if execution was successful, 1 if it was not (test failures) * @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<String>(asList(argv))); RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList<String>(asList(argv)));


ResourceLoader resourceLoader = new MultiLoader(classLoader); ResourceLoader resourceLoader = new MultiLoader(classLoader);
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/cucumber/api/event/EventListener.java
@@ -1,8 +1,7 @@
package cucumber.api.event; package cucumber.api.event;


/** /**
* This is the interface you should implement if you want your own custom * This is the interface you should implement if your plugin listens to cucumber execution events
* formatter.
*/ */
public interface EventListener { public interface EventListener {


Expand Down
55 changes: 43 additions & 12 deletions core/src/main/java/cucumber/runtime/DefaultSummaryPrinter.java
@@ -1,39 +1,48 @@
package cucumber.runtime; package cucumber.runtime;


import cucumber.api.SummaryPrinter; import cucumber.api.SummaryPrinter;
import cucumber.api.event.EventHandler;
import cucumber.api.event.EventListener;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.TestRunFinished;
import cucumber.api.formatter.ColorAware;
import cucumber.api.formatter.StrictAware;


import java.io.PrintStream; import java.io.PrintStream;
import java.util.List; import java.util.List;


public class DefaultSummaryPrinter implements SummaryPrinter { public class DefaultSummaryPrinter implements SummaryPrinter, ColorAware, StrictAware, EventListener {

private final Stats stats = new Stats();
private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker();

private final PrintStream out; private final PrintStream out;


public DefaultSummaryPrinter() { public DefaultSummaryPrinter() {
this.out = System.out; this.out = System.out;
} }


@Override private void print() {
public void print(Runtime runtime) {
out.println(); out.println();
printStats(runtime); printStats();
out.println(); out.println();
printErrors(runtime); printErrors();
printSnippets(runtime); printSnippets();
} }


private void printStats(Runtime runtime) { private void printStats() {
runtime.printStats(out); stats.printStats(out);
} }


private void printErrors(Runtime runtime) { private void printErrors() {
for (Throwable error : runtime.getErrors()) { for (Throwable error : stats.getErrors()) {
error.printStackTrace(out); error.printStackTrace(out);
out.println(); out.println();
} }
} }


private void printSnippets(Runtime runtime) { private void printSnippets() {
List<String> snippets = runtime.getSnippets(); List<String> snippets = undefinedStepsTracker.getSnippets();
if (!snippets.isEmpty()) { if (!snippets.isEmpty()) {
out.append("\n"); out.append("\n");
out.println("You can implement missing steps with the snippets below:"); out.println("You can implement missing steps with the snippets below:");
Expand All @@ -43,4 +52,26 @@ private void printSnippets(Runtime runtime) {
} }
} }
} }

@Override
public void setEventPublisher(EventPublisher publisher) {
stats.setEventPublisher(publisher);
undefinedStepsTracker.setEventPublisher(publisher);
publisher.registerHandlerFor(TestRunFinished.class, new EventHandler<TestRunFinished>() {
@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);
}
} }
39 changes: 39 additions & 0 deletions 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<Result> results = new ArrayList<Result>();

private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
@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;
}
}
5 changes: 0 additions & 5 deletions core/src/main/java/cucumber/runtime/NullSummaryPrinter.java
Expand Up @@ -4,9 +4,4 @@


public class NullSummaryPrinter implements SummaryPrinter { public class NullSummaryPrinter implements SummaryPrinter {


@Override
public void print(Runtime runtime) {
// Do nothing
}

} }

0 comments on commit afc2581

Please sign in to comment.