Skip to content

Commit

Permalink
Make the SummaryPrinter into a plugin
Browse files Browse the repository at this point in the history
To be able to load plugin classes by full class name on Jython the
Thread.currentThread().contextClassLoader need to be set before calling
cucumber.api.cli.Main
  • Loading branch information
brasmusson committed Jan 14, 2015
1 parent 1e79082 commit 600f877
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 32 deletions.
5 changes: 5 additions & 0 deletions core/src/main/java/cucumber/api/SummaryPrinter.java
@@ -0,0 +1,5 @@
package cucumber.api;

public interface SummaryPrinter {
public void print(cucumber.runtime.Runtime runtime);
}
@@ -1,15 +1,18 @@
package cucumber.runtime; package cucumber.runtime;


import cucumber.api.SummaryPrinter;

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


public class SummaryPrinter { public class DefaultSummaryPrinter implements SummaryPrinter {
private final PrintStream out; private final PrintStream out;


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


@Override
public void print(cucumber.runtime.Runtime runtime) { public void print(cucumber.runtime.Runtime runtime) {
out.println(); out.println();
printStats(runtime); printStats(runtime);
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/java/cucumber/runtime/NullSummaryPrinter.java
@@ -0,0 +1,12 @@
package cucumber.runtime;

import cucumber.api.SummaryPrinter;

public class NullSummaryPrinter implements SummaryPrinter {

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

}
5 changes: 3 additions & 2 deletions core/src/main/java/cucumber/runtime/Runtime.java
Expand Up @@ -2,6 +2,7 @@


import cucumber.api.Pending; import cucumber.api.Pending;
import cucumber.api.StepDefinitionReporter; import cucumber.api.StepDefinitionReporter;
import cucumber.api.SummaryPrinter;
import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.model.CucumberFeature; import cucumber.runtime.model.CucumberFeature;
import cucumber.runtime.xstream.LocalizedXStreams; import cucumber.runtime.xstream.LocalizedXStreams;
Expand Down Expand Up @@ -126,8 +127,8 @@ public void run() throws IOException {
} }


public void printSummary() { public void printSummary() {
// TODO: inject a SummaryPrinter in the ctor SummaryPrinter summaryPrinter = runtimeOptions.summaryPrinter(classLoader);
new SummaryPrinter(System.out).print(this); summaryPrinter.print(this);
} }


void printStats(PrintStream out) { void printStats(PrintStream out) {
Expand Down
21 changes: 18 additions & 3 deletions core/src/main/java/cucumber/runtime/RuntimeOptions.java
Expand Up @@ -2,13 +2,14 @@


import cucumber.api.SnippetType; import cucumber.api.SnippetType;
import cucumber.api.StepDefinitionReporter; import cucumber.api.StepDefinitionReporter;
import cucumber.api.SummaryPrinter;
import cucumber.runtime.formatter.ColorAware; import cucumber.runtime.formatter.ColorAware;
import cucumber.runtime.formatter.PluginFactory; import cucumber.runtime.formatter.PluginFactory;
import cucumber.runtime.formatter.StrictAware; import cucumber.runtime.formatter.StrictAware;
import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.model.CucumberFeature; import cucumber.runtime.model.CucumberFeature;
import gherkin.I18n;
import cucumber.runtime.model.PathWithLines; import cucumber.runtime.model.PathWithLines;
import gherkin.I18n;
import gherkin.formatter.Formatter; import gherkin.formatter.Formatter;
import gherkin.formatter.Reporter; import gherkin.formatter.Reporter;
import gherkin.util.FixJava; import gherkin.util.FixJava;
Expand All @@ -33,6 +34,7 @@ public class RuntimeOptions {
private final List<String> featurePaths = new ArrayList<String>(); private final List<String> featurePaths = new ArrayList<String>();
private final List<String> pluginFormatterNames = new ArrayList<String>(); private final List<String> pluginFormatterNames = new ArrayList<String>();
private final List<String> pluginStepDefinitionReporterNames = new ArrayList<String>(); private final List<String> pluginStepDefinitionReporterNames = new ArrayList<String>();
private final List<String> pluginSummaryPrinterNames = new ArrayList<String>();
private final PluginFactory pluginFactory; private final PluginFactory pluginFactory;
private final List<Object> plugins = new ArrayList<Object>(); private final List<Object> plugins = new ArrayList<Object>();
private boolean dryRun; private boolean dryRun;
Expand Down Expand Up @@ -85,6 +87,9 @@ public RuntimeOptions(Env env, PluginFactory pluginFactory, List<String> argv) {
if (pluginFormatterNames.isEmpty()) { if (pluginFormatterNames.isEmpty()) {
pluginFormatterNames.add("progress"); pluginFormatterNames.add("progress");
} }
if (pluginSummaryPrinterNames.isEmpty()) {
pluginSummaryPrinterNames.add("cucumber.runtime.DefaultSummaryPrinter");
}
} }


private void parse(List<String> args) { private void parse(List<String> args) {
Expand Down Expand Up @@ -152,10 +157,12 @@ private void parse(List<String> args) {
} }


private void addPluginName(String name) { private void addPluginName(String name) {
if (pluginFactory.isFormatterName(name)) { if (PluginFactory.isFormatterName(name)) {
pluginFormatterNames.add(name); pluginFormatterNames.add(name);
} else if (pluginFactory.isStepDefinitionResporterName(name)) { } else if (PluginFactory.isStepDefinitionResporterName(name)) {
pluginStepDefinitionReporterNames.add(name); pluginStepDefinitionReporterNames.add(name);
} else if (PluginFactory.isSummaryPrinterName(name)) {
pluginSummaryPrinterNames.add(name);
} else { } else {
throw new CucumberException("Unrecognized plugin: " + name); throw new CucumberException("Unrecognized plugin: " + name);
} }
Expand Down Expand Up @@ -224,6 +231,10 @@ List<Object> getPlugins() {
Object plugin = pluginFactory.create(pluginName); Object plugin = pluginFactory.create(pluginName);
plugins.add(plugin); plugins.add(plugin);
} }
for (String pluginName : pluginSummaryPrinterNames) {
Object plugin = pluginFactory.create(pluginName);
plugins.add(plugin);
}
pluginNamesInstantiated = true; pluginNamesInstantiated = true;
} }
return plugins; return plugins;
Expand All @@ -241,6 +252,10 @@ public StepDefinitionReporter stepDefinitionReporter(ClassLoader classLoader) {
return pluginProxy(classLoader, StepDefinitionReporter.class); 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. * Creates a dynamic proxy that multiplexes method invocations to all plugins of the same type.
* *
Expand Down
@@ -1,6 +1,7 @@
package cucumber.runtime.formatter; package cucumber.runtime.formatter;


import cucumber.api.StepDefinitionReporter; import cucumber.api.StepDefinitionReporter;
import cucumber.api.SummaryPrinter;
import cucumber.runtime.CucumberException; import cucumber.runtime.CucumberException;
import cucumber.runtime.io.URLOutputStream; import cucumber.runtime.io.URLOutputStream;
import cucumber.runtime.io.UTF8OutputStreamWriter; import cucumber.runtime.io.UTF8OutputStreamWriter;
Expand Down Expand Up @@ -201,6 +202,14 @@ public static boolean isStepDefinitionResporterName(String name) {
return false; return false;
} }


public static boolean isSummaryPrinterName(String name) {
Class pluginClass = getPluginClass(name);
if (SummaryPrinter.class.isAssignableFrom(pluginClass)) {
return true;
}
return false;
}

private static Class getPluginClass(String name) { private static Class getPluginClass(String name) {
Matcher pluginWithFile = PLUGIN_WITH_FILE_PATTERN.matcher(name); Matcher pluginWithFile = PLUGIN_WITH_FILE_PATTERN.matcher(name);
String pluginName; String pluginName;
Expand Down
41 changes: 26 additions & 15 deletions core/src/test/java/cucumber/runtime/RuntimeOptionsFactoryTest.java
Expand Up @@ -39,8 +39,7 @@ public void create_without_options() throws Exception {
assertFalse(runtimeOptions.isStrict()); assertFalse(runtimeOptions.isStrict());
assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getFeaturePaths()); assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getFeaturePaths());
assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getGlue()); assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getGlue());
assertEquals(1, runtimeOptions.getPlugins().size()); assertPluginExists(runtimeOptions.getPlugins(), "cucumber.runtime.formatter.NullFormatter");
assertEquals("cucumber.runtime.formatter.NullFormatter", runtimeOptions.getPlugins().get(0).getClass().getName());
} }


@Test @Test
Expand All @@ -49,8 +48,7 @@ public void create_without_options_with_base_class_without_options() throws Exce
RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getFeaturePaths()); assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getFeaturePaths());
assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getGlue()); assertEquals(asList("classpath:cucumber/runtime"), runtimeOptions.getGlue());
assertEquals(1, runtimeOptions.getPlugins().size()); assertPluginExists(runtimeOptions.getPlugins(), "cucumber.runtime.formatter.NullFormatter");
assertEquals("cucumber.runtime.formatter.NullFormatter", runtimeOptions.getPlugins().get(0).getClass().getName());
} }


@Test @Test
Expand Down Expand Up @@ -98,15 +96,14 @@ public void finds_path_for_class_in_toplevel_package() {
public void create_null_formatter_when_no_formatter_plugin_is_defined() { public void create_null_formatter_when_no_formatter_plugin_is_defined() {
RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(ClassWithNoFormatterPlugin.class); RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(ClassWithNoFormatterPlugin.class);
RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
assertPluginExists(runtimeOptions.getPlugins(), "cucumber.runtime.formatter.NullFormatter");
}


List<Object> plugins = runtimeOptions.getPlugins(); @Test
boolean found = false; public void create_default_summary_printer_when_no_summary_printer_plugin_is_defined() {
for (Object plugin : plugins) { RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(ClassWithNoSummaryPrinterPlugin.class);
if ("cucumber.runtime.formatter.NullFormatter".equals(plugin.getClass().getName())) { RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
found = true; assertPluginExists(runtimeOptions.getPlugins(), "cucumber.runtime.DefaultSummaryPrinter");
}
}
assertTrue("NullFormatter not found among plugins", found);
} }


@Test @Test
Expand All @@ -115,9 +112,8 @@ public void inherit_plugin_from_baseclass() {
RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();


List<Object> plugins = runtimeOptions.getPlugins(); List<Object> plugins = runtimeOptions.getPlugins();
assertEquals(2, plugins.size()); assertPluginExists(plugins, "cucumber.runtime.formatter.CucumberJSONFormatter");
assertTrue(plugins.get(0) instanceof PrettyFormatter); assertPluginExists(plugins, "cucumber.runtime.formatter.CucumberPrettyFormatter");
assertTrue(plugins.get(1) instanceof JSONFormatter);
} }


@Test @Test
Expand All @@ -128,6 +124,16 @@ public void override_monochrome_flag_from_baseclass() {
assertTrue(runtimeOptions.isMonochrome()); assertTrue(runtimeOptions.isMonochrome());
} }


private void assertPluginExists(List<Object> plugins, String pluginName) {
boolean found = false;
for (Object plugin : plugins) {
if (plugin.getClass().getName() == pluginName) {
found = true;
}
}
assertTrue(pluginName + " not found among the plugins", found);
}



@CucumberOptions(snippets = SnippetType.CAMELCASE) @CucumberOptions(snippets = SnippetType.CAMELCASE)
static class Snippets { static class Snippets {
Expand Down Expand Up @@ -185,4 +191,9 @@ static class BaseClassWithMonoChromeFalse {
static class ClassWithNoFormatterPlugin { static class ClassWithNoFormatterPlugin {
// empty // empty
} }

@CucumberOptions(plugin = "pretty")
static class ClassWithNoSummaryPrinterPlugin {
// empty
}
} }
41 changes: 33 additions & 8 deletions core/src/test/java/cucumber/runtime/RuntimeOptionsTest.java
Expand Up @@ -87,15 +87,22 @@ public void creates_progress_formatter_as_default() {
} }


@Test @Test
public void creates_progress_formatter_when_non_formatter_plugin_is_specified() { public void creates_progress_formatter_when_no_formatter_plugin_is_specified() {
RuntimeOptions options = new RuntimeOptions(asList("--plugin", "cucumber.runtime.formatter.AnyStepDefinitionReporter", "--glue", "somewhere")); RuntimeOptions options = new RuntimeOptions(asList("--plugin", "cucumber.runtime.formatter.AnyStepDefinitionReporter", "--glue", "somewhere"));
boolean found = false; assertPluginExists(options.getPlugins(), "cucumber.runtime.formatter.ProgressFormatter");
for (Object plugin : options.getPlugins()) { }
if (plugin.getClass().getName() == "cucumber.runtime.formatter.ProgressFormatter") {
found = true; @Test
} public void creates_default_summary_printer_when_no_summary_printer_plugin_is_specified() {
} RuntimeOptions options = new RuntimeOptions(asList("--plugin", "pretty", "--glue", "somewhere"));
assertTrue("ProgressFormatter not found among the plugins", found); assertPluginExists(options.getPlugins(), "cucumber.runtime.DefaultSummaryPrinter");
}

@Test
public void creates_null_summary_printer() {
RuntimeOptions options = new RuntimeOptions(asList("--plugin", "cucumber.runtime.NullSummaryPrinter", "--glue", "somewhere"));
assertPluginExists(options.getPlugins(), "cucumber.runtime.NullSummaryPrinter");
assertPluginNotExists(options.getPlugins(), "cucumber.runtime.DefaultSummaryPrinter");
} }


@Test @Test
Expand Down Expand Up @@ -326,5 +333,23 @@ private void mockResource(ResourceLoader resourceLoader, String featurePath, Str
when(resource1.getInputStream()).thenReturn(new ByteArrayInputStream(feature.getBytes("UTF-8"))); when(resource1.getInputStream()).thenReturn(new ByteArrayInputStream(feature.getBytes("UTF-8")));
when(resourceLoader.resources(featurePath, ".feature")).thenReturn(asList(resource1)); when(resourceLoader.resources(featurePath, ".feature")).thenReturn(asList(resource1));
} }

private void assertPluginExists(List<Object> plugins, String pluginName) {
assertTrue(pluginName + " not found among the plugins", pluginExists(plugins, pluginName));
}

private void assertPluginNotExists(List<Object> plugins, String pluginName) {
assertFalse(pluginName + " found among the plugins", pluginExists(plugins, pluginName));
}

private boolean pluginExists(List<Object> plugins, String pluginName) {
boolean found = false;
for (Object plugin : plugins) {
if (plugin.getClass().getName() == pluginName) {
found = true;
}
}
return found;
}
} }


4 changes: 3 additions & 1 deletion jython/bin/cucumber-jvm.py
Expand Up @@ -5,10 +5,12 @@
sys.path.append(cucumber_jython_shaded_path) sys.path.append(cucumber_jython_shaded_path)


from java.io import File from java.io import File
from java.lang import Thread
from java.net import URLClassLoader from java.net import URLClassLoader
from cucumber.api.cli import Main from cucumber.api.cli import Main


cl = URLClassLoader([File(cucumber_jython_shaded_path).toURL()], Main.getClassLoader()) cl = URLClassLoader([File(cucumber_jython_shaded_path).toURL()], Main.getClassLoader())
Thread.currentThread().contextClassLoader = cl


exitstatus = Main.run(sys.argv[1:], cl) exitstatus = Main.run(sys.argv[1:], cl)
sys.exit(exitstatus) sys.exit(exitstatus)

0 comments on commit 600f877

Please sign in to comment.