package cucumber.contrib.junit; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; import cucumber.contrib.util.Filter; import cucumber.contrib.util.Filters; import cucumber.runtime.*; import cucumber.runtime.Runtime; import cucumber.runtime.io.MultiLoader; import cucumber.runtime.io.ResourceLoader; import cucumber.runtime.io.ResourceLoaderClassFinder; import cucumber.runtime.junit.Assertions; import cucumber.runtime.junit.FeatureRunner; import cucumber.runtime.junit.JUnitReporter; import cucumber.runtime.model.CucumberFeature; import cucumber.runtime.snippets.SummaryPrinter; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Classes annotated with {@code @RunWith(Cucumber.class)} will run a Cucumber Feature. * The class should be empty without any fields or methods. * <p/> * Cucumber will look for a {@code .feature} file on the classpath, using the same resource * path as the annotated class ({@code .class} substituted by {@code .feature}). * <p/> * Additional hints can be given to Cucumber by annotating the class with {@link cucumber.api.junit.Cucumber.Options}. * * @see cucumber.api.junit.Cucumber.Options */ public class CucumberExt extends ParentRunner<FeatureRunner> { private final JUnitReporter jUnitReporter; private final List<FeatureRunner> children = new ArrayList<FeatureRunner>(); private final Runtime runtime; /** * Constructor called by JUnit. * * @param clazz the class with the @RunWith annotation. * @throws java.io.IOException if there is a problem * @throws org.junit.runners.model.InitializationError * if there is another problem */ public CucumberExt(Class clazz) throws InitializationError, IOException { super(clazz); ClassLoader classLoader = clazz.getClassLoader(); Assertions.assertNoCucumberAnnotatedMethods(clazz); @SuppressWarnings("unchecked") RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(clazz, new Class[]{CucumberOptions.class, Cucumber.Options.class}); RuntimeOptions runtimeOptions = runtimeOptionsFactory.create(); ResourceLoader resourceLoader = createResourceLoader(clazz); ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader); runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions); jUnitReporter = new JUnitReporter(runtimeOptions.reporter(classLoader), runtimeOptions.formatter(classLoader), runtimeOptions.isStrict()); addChildren(runtimeOptions.cucumberFeatures(resourceLoader)); } protected ResourceLoader createResourceLoader(Class<?> clazz) { ClassLoader classLoader = clazz.getClassLoader(); MultiLoader loader = new MultiLoader(classLoader); List<Filter<InputStream>> filters = instanciateFilters(clazz); if(filters.isEmpty()) return loader; else return new ResourceLoaderWrapper(loader, Filters.chain(filters)); } private List<Filter<InputStream>> instanciateFilters(Class<?> clazz) { if (!clazz.isAnnotationPresent(CucumberExtOptions.class)) { return Collections.emptyList(); } CucumberExtOptions opts = clazz.getAnnotation(CucumberExtOptions.class); Class<? extends Filter<InputStream>>[] filterClasses = opts.filters(); if (filterClasses.length == 0) { return Collections.emptyList(); } List<Filter<InputStream>> filters = new ArrayList<Filter<InputStream>>(filterClasses.length); for (Class<? extends Filter<InputStream>> filterClazz : filterClasses) { Filter<InputStream> filter = instanciate(filterClazz); filters.add(filter); } return filters; } private static <T> T instanciate(Class<? extends T> clazz) { try { return clazz.newInstance(); } catch (InstantiationException e) { throw new CucumberException(e); } catch (IllegalAccessException e) { throw new CucumberException(e); } } @Override public List<FeatureRunner> getChildren() { return children; } @Override protected Description describeChild(FeatureRunner child) { return child.getDescription(); } @Override protected void runChild(FeatureRunner child, RunNotifier notifier) { child.run(notifier); } @Override public void run(RunNotifier notifier) { super.run(notifier); jUnitReporter.done(); new SummaryPrinter(System.out).print(runtime); jUnitReporter.close(); } private void addChildren(List<CucumberFeature> cucumberFeatures) throws InitializationError { for (CucumberFeature cucumberFeature : cucumberFeatures) { children.add(new FeatureRunner(cucumberFeature, runtime, jUnitReporter)); } } }