package org.codemap.tasks;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import org.codemap.util.Log;
import org.codemap.util.Resources;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.junit.JUnitCore;
import ch.akuhn.util.Files;
import ch.akuhn.util.ProgressMonitor;
import ch.akuhn.values.Arguments;
import ch.akuhn.values.TaskValue;
import ch.akuhn.values.Value;
public class ComputeElementsTask extends TaskValue<Collection<String>> {
public ComputeElementsTask(Value<Collection<String>> projects, Value<Collection<String>> extensions) {
super("Collecting selected resources", projects, extensions);
}
@Override
protected Collection<String> computeValue(ProgressMonitor monitor, Arguments args) {
Collection<String> projects = args.nextOrFail();
final Collection<String> extensions = args.nextOrFail();
final Collection<IResource> result = new HashSet<IResource>();
for (String path: projects) {
IResource resource = Resources.asResource(path);
// fix error for closed projects
if (!resource.isAccessible()) continue;
FindElementsVisitor visitor = new FindElementsVisitor(extensions);
try {
resource.accept(visitor);
} catch (CoreException e) {
Log.error(e);
}
visitor.storeResult(result);
}
return new TestFileFilter(result).run(monitor);
}
}
class TestFileFilter {
private Collection<IResource> elements;
public TestFileFilter(Collection<IResource> elements) {
this.elements = elements;
}
public Collection<String> run(ProgressMonitor monitor) {
monitor.begin(elements.size());
Collection<String> result = new HashSet<String>();
for(IResource each: elements) {
if (!isJavaTestFile(each)) {
result.add(Resources.asPath(each));
}
monitor.worked(1);
}
return new ArrayList<String>(result);
}
private boolean isJavaTestFile(IResource resource) {
/*
* If the resource contains compilation errors, it maybe that
* we get a false positive. As a work around we could look at
* the path (does it include test) and at the name (does it end
* with Test).
*
* This is a TODO for a world where days have more than 24h.
*
*/
IJavaElement javaElement = Resources.asJavaElement(resource);
if (javaElement == null) return false;
// find all tests for the given file
IType[] findTestTypes;
try {
findTestTypes = JUnitCore.findTestTypes(javaElement, null);
} catch (OperationCanceledException e) {
return false; // be conservative
} catch (CoreException e) {
return false; // be conservative
} catch (NullPointerException e){
// JunitCore might throw some nullpointers from time to time if
// the project is not set-up correctly, especially if a java file is
// not on the build path.
return false;
}
// if we found one (or maybe more) then we have a java test file
return findTestTypes.length > 0;
}
}
class FindElementsVisitor implements IResourceVisitor {
private Collection<String> extensions;
private Collection<IResource> myResult;
public FindElementsVisitor(Collection<String> extensions) {
this.extensions = extensions;
this.myResult = new ArrayList<IResource>();
}
public void storeResult(Collection<IResource> result) {
result.addAll(myResult);
}
@Override
public boolean visit(IResource resource) throws CoreException {
if (resource.getType() == IResource.FILE) {
for (String pattern: extensions) {
if (!Files.match(pattern, resource.getName())) continue;
myResult.add(resource);
}
}
return true;
}
}