package net.thucydides.junit.finder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.thucydides.core.reflection.ClassFinder;
import net.thucydides.junit.annotations.UseTestDataFrom;
import net.thucydides.junit.runners.ThucydidesRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
/**
* The TestFinder class lets you find the Thucydides tests or test methods underneath a given package.
* <p>You instantiate a TestFinder by providing the top-level package where the tests live.</p>
* <p>You can then find the list of Thucydides test classes using getNormalTestClasses(), getDataDrivenTestClasses(),
* and getAllTestClasses() (which returns both normal and data-driven tests).</p>
* <p>You may also need to retrieve the list of test methods for a particular category of class. You can do this using the
* getTestMethodsFrom() method, e.g.
* <pre>new TestFinder("my.package").getTestMethodsFrom().normalTestClasses()</pre>
*/
public abstract class TestFinder {
protected final String rootPackage;
/**
* Create a new test finder instance that will look for tests in the packages underneath the given root package.
* @param rootPackage The root package used as the starting point when looking for test classes.
*/
protected TestFinder(final String rootPackage) {
this.rootPackage = rootPackage;
}
public static TestFinderBuilderFactory thatFinds() {
return new TestFinderBuilderFactory();
}
public abstract List<Class<?>> getClasses();
public abstract int countTestMethods();
public TestMethodFinder findTestMethods() {
return new TestMethodFinder(this);
}
protected List<Class<?>> getAllTestClasses() {
return ClassFinder.loadClasses().annotatedWith(RunWith.class).fromPackage(rootPackage);
}
protected Set<Class<?>> getNormalTestClasses() {
Set<Class<?>> normalTestClasses = Sets.newHashSet();
for(Class<?> testClass : getAllTestClasses()) {
if (normalThucydidesTest(testClass)) {
normalTestClasses.add(testClass);
}
}
return normalTestClasses;
}
protected List<Class<?>> getDataDrivenTestClasses() {
return ClassFinder.loadClasses().annotatedWith(UseTestDataFrom.class).fromPackage(rootPackage);
}
protected List<Class<?>> sorted(List<Class<?>> classes) {
Collections.sort(classes, byClassName());
return classes;
}
private boolean normalThucydidesTest(Class<?> testClass) {
RunWith runWith = testClass.getAnnotation(RunWith.class);
return ((runWith != null) && (runWith.value() == ThucydidesRunner.class));
}
public List<Method> getAllTestMethods() {
return findMethodsFrom(getClasses());
}
private List<Method> findMethodsFrom(List<Class<?>> testClasses) {
List<Method> methods = Lists.newArrayList();
for (Class<?> testClass : testClasses) {
addEachMatchingTestMethodFrom(testClass).to(methods);
}
Collections.sort(methods, byName());
return methods;
}
private Comparator<Method> byName() {
return new Comparator<Method>() {
public int compare(Method method, Method method1) {
return method.getName().compareTo(method1.getName());
}
};
}
private static class TestMethodSearchBuilder {
private final Class<?> testClass;
private TestMethodSearchBuilder(Class<?> testClass) {
this.testClass = testClass;
}
public void to(List<Method> methods) {
for(Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
methods.add(method);
}
}
}
}
private TestMethodSearchBuilder addEachMatchingTestMethodFrom(Class<?> testClass) {
return new TestMethodSearchBuilder(testClass);
}
private Comparator<Class<?>> byClassName() {
return new Comparator<Class<?>>() {
public int compare(Class<?> class1, Class<?> class2) {
return class1.getName().compareTo(class2.getName());
}
};
}
}