package org.ant4eclipse.ant.pde.analysis;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import org.ant4eclipse.lib.core.Assure;
import org.ant4eclipse.lib.core.ClassName;
import org.ant4eclipse.lib.core.util.Utilities;
import org.ant4eclipse.lib.jdt.ecj.ClassFile;
import org.ant4eclipse.lib.jdt.ecj.ClassFileLoader;
import org.ant4eclipse.lib.jdt.ecj.ClassFileLoaderFactory;
import org.ant4eclipse.lib.jdt.ecj.EcjAdapter;
import org.ant4eclipse.lib.jdt.model.project.JavaProjectRole;
import org.ant4eclipse.lib.jdt.tools.JdtResolver;
import org.ant4eclipse.lib.jdt.tools.ResolvedClasspath;
import org.ant4eclipse.lib.jdt.tools.container.JdtClasspathContainerArgument;
import org.ant4eclipse.lib.platform.model.resource.EclipseProject;
import org.objectweb.asm.ClassReader;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class TestClassAnalyser {
/** the eclipse project to test */
private EclipseProject _eclipseProject;
private ClassFileLoader _fileLoader;
/**
* <p>
* Creates a new instance of type {@link TestClassAnalyser}.
* </p>
*
* @param eclipseProject
* the eclipse project to test.
*/
public TestClassAnalyser(EclipseProject eclipseProject) {
Assure.notNull("eclipseProject", eclipseProject);
//
this._eclipseProject = eclipseProject;
ResolvedClasspath classpath = JdtResolver.resolveProjectClasspath(this._eclipseProject, false, false,
new LinkedList<JdtClasspathContainerArgument>());
this._fileLoader = ClassFileLoaderFactory.createClasspathClassFileLoader(this._eclipseProject.getFolder(),
EcjAdapter.PROJECT, classpath.getClasspathFiles(), new File[0]);
}
/**
* <p>
* Returns the test classes as a string.
* </p>
*
* @return the test classes as a string.
*/
public String getTestClassesAsString() {
// create result
StringBuilder builder = new StringBuilder();
//
Set<String> testClasses = getTestClasses();
//
if (testClasses.isEmpty()) {
throw new RuntimeException(String.format("Project '%s' does not contain any test classes!",
this._eclipseProject.getSpecifiedName()));
}
// iterate over all the
for (Iterator<String> iterator = testClasses.iterator(); iterator.hasNext();) {
builder.append(iterator.next());
if (iterator.hasNext()) {
builder.append("\n");
}
}
// returns the result
return builder.toString();
}
/**
* <p>
* Returns a set with the names of all contained test classes.
* </p>
*
* @return a set with the names of all contained test classes.
*/
public Set<String> getTestClasses() {
// create the result set
Set<String> result = new HashSet<String>();
// get the java projetc role
JavaProjectRole javaProjectRole = this._eclipseProject.getRole(JavaProjectRole.class);
// iterate over all the output folder names
for (String outputFolderName : javaProjectRole.getAllOutputFolders()) {
// get the output folder
File outputFolder = this._eclipseProject.getChild(outputFolderName);
// iterate over all contained children
for (File file : Utilities.getAllChildren(outputFolder)) {
// scan the class files
try {
String className = scanClass(file);
if (className != null) {
result.add(className);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// return the result
return result;
}
/**
* <p>
* Scans the class files.
* </p>
*
* @param classFile
* @return the name of the class file if a the class file is a junit test class.
* @throws FileNotFoundException
* @throws IOException
*/
private String scanClass(File classFile) throws FileNotFoundException, IOException {
// return if file is no class file
if (!classFile.getName().endsWith(".class")) {
return null;
}
// return if file is an inner type
if (classFile.getName().contains("$")) {
return null;
}
// scan the file
JUnitVisitor classVisitor = new JUnitVisitor();
new ClassReader(new FileInputStream(classFile)).accept(classVisitor, 0);
boolean isTestClass = classVisitor.isTestClass();
if (!isTestClass) {
String superClass = classVisitor.getSuperClassName();
isTestClass = scanSuperClasses(superClass);
}
// return the result
return isTestClass ? classVisitor.getClassName() : null;
}
/**
* <p>
* </p>
*
* @param className
* @return
*/
private boolean scanSuperClasses(String className) {
if (className == null || className.equals("java.lang.Object")) {
return false;
}
ClassFile superClassFile = this._fileLoader.loadClass(ClassName.fromQualifiedClassName(className));
JUnitVisitor classVisitor = new JUnitVisitor();
new ClassReader(superClassFile.getBytes()).accept(classVisitor, 0);
boolean isTestClass = classVisitor.hasTestAnnotations();
if (!isTestClass) {
String superClass = classVisitor.getSuperClassName();
isTestClass = scanSuperClasses(superClass);
}
return isTestClass;
}
}