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));
}
}
}