package org.test4j.junit.filter.finder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.test4j.junit.filter.acceptor.TestAcceptor;
import org.test4j.junit.filter.iterator.DirFileIterator;
import org.test4j.junit.filter.iterator.JarFileIterator;
import org.test4j.junit.filter.iterator.NonFileIterator;
import org.test4j.module.core.utility.MessageHelper;
import org.test4j.tools.commons.ClazzHelper;
import org.test4j.tools.commons.ResourceHelper;
/**
* Utility class to find classes within the class path, both inside and outside
* of jar files. Inner and anonymous classes are not being considered in the
* first place. It's originally evolved out of ClassPathTestCollector in JUnit
* 3.8.1
*/
public class ClasspathTestClazFinder implements TestClazFinder {
private static final int CLASS_SUFFIX_LENGTH = ".class".length();
private final TestAcceptor tester;
public ClasspathTestClazFinder(TestAcceptor tester) {
this.tester = tester;
}
public List<Class<?>> find() {
String classPath = System.getProperty("java.class.path");
List<String> paths = this.splitClassPath(classPath);
return findClassesInRoots(paths);
}
private List<String> splitClassPath(String classPath) {
final String separator = System.getProperty("path.separator");
return Arrays.asList(classPath.split(separator));
}
private List<Class<?>> findClassesInRoots(List<String> roots) {
List<Class<?>> classes = new ArrayList<Class<?>>(100);
for (String root : roots) {
this.gatherClassesInRoot(new File(root), classes);
}
return classes;
}
private void gatherClassesInRoot(File classpathRoot, List<Class<?>> classes) {
Iterable<String> relativeFilenames = new NonFileIterator<String>();
if (ResourceHelper.isJarFile(classpathRoot)) {
if (tester.searchInJars()) {
try {
relativeFilenames = new JarFileIterator(classpathRoot);
} catch (IOException e) {
MessageHelper.error(
"search test in jar[" + String.valueOf(classpathRoot) + "] error:" + e.getMessage(), e);
}
}
} else {
relativeFilenames = new DirFileIterator(classpathRoot);
}
for (String fileName : relativeFilenames) {
this.addTestClazzIfAccepted(classes, fileName);
}
}
/**
* 往列表中增加测试类
*
* @param classes
* @param fileName
*/
private void addTestClazzIfAccepted(List<Class<?>> classes, String fileName) {
if (!ClazzHelper.isClassFile(fileName)) {
return;
}
String clazzPath = fileName.substring(0, fileName.length() - CLASS_SUFFIX_LENGTH);
String clazzName = ClazzHelper.replaceFileSeparators(clazzPath);
if (!tester.isAcceptedByPatterns(clazzName)) {
return;
}
if (!tester.acceptInnerClass() && ClazzHelper.isInnerClass(clazzName)) {
return;
}
try {
Class<?> clazz = Class.forName(clazzName);
boolean isAcceptedByBaseType = tester.isCorrectClazType(clazz);
if (!isAcceptedByBaseType) {
return;
}
if (tester.isCorrectTestType(clazz)) {
classes.add(clazz);
}
} catch (ClassNotFoundException cnfe) {
// ignore not instantiable classes
} catch (NoClassDefFoundError ncdfe) {
// ignore not instantiable classes
} catch (ExceptionInInitializerError ciie) {
// ignore not instantiable classes
} catch (UnsatisfiedLinkError ule) {
// ignore not instantiable classes
}
}
public TestAcceptor getTester() {
return tester;
}
}