package org.xtest.runner; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.xtest.runner.external.ITestType; import org.xtest.runner.external.TestState; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.inject.Inject; /** * Provider for tests to run based on client contributions to the testType extension point * * @author Michael Barry */ public class TestsProvider { @Inject private Extensions extensions; private final Logger logger = Logger.getLogger(TestsProvider.class); private final AtomicInteger numTotalTests = new AtomicInteger(-1); /** * Get all tests in the workspace * * @return All tests in the workspace */ public Collection<RunnableTest> getAllTests() { final Set<RunnableTest> tests = Sets.newHashSet(); try { ResourcesPlugin.getWorkspace().getRoot().accept(testFinder(tests)); } catch (CoreException e) { } numTotalTests.set(tests.size()); return tests; } /** * Returns the total number of test files * * @return The total number of test files */ public int getNumTotalTests() { if (numTotalTests.get() < 0) { getAllTests(); } return numTotalTests.get(); } /** * Returns all of the test files of a given state * * @param state * The state of the test files to find * @return All of the test files of a given state */ public Collection<IFile> getTestFilesWithState(TestState state) { List<IFile> results = Lists.newArrayList(); for (RunnableTest test : getAllTests()) { if (test.getState().getState() == state) { results.add(test.getFile()); } } return results; } /** * Return tests that depend on the deltas provided * * @param deltas * The list of changed files * @return the set of tests that depend on {@code deltas} */ public Collection<RunnableTest> getTestsFromDeltas(Set<IFile> deltas) { Set<RunnableTest> result = Sets.newHashSet(); for (RunnableTest test : getAllTests()) { if (!test.hasRun()) { // Always re-run failing or unexecuted tests result.add(test); logger.debug("Scheduling " + test.getName() + " because it has not run before"); } else if (test.isPending()) { result.add(test); logger.debug("Scheduling " + test.getName() + " because it was pending"); } else if (TestState.FAIL == test.getState().getState()) { result.add(test); logger.debug("Scheduling " + test.getName() + " because it is failing"); } else { for (IFile delta : deltas) { if (test.isAffectedBy(delta)) { logger.debug("Scheduling " + test.getName() + " because dependency changed: " + delta.getName()); result.add(test); break; } } } } return result; } /** * Returns the tests in the project provided * * @param project * The project to search * @return The tests in that project */ public Set<RunnableTest> getTestsIn(IProject project) { final Set<RunnableTest> tests = Sets.newHashSet(); try { project.accept(testFinder(tests)); } catch (CoreException e) { } return tests; } private TestFinder testFinder(Set<RunnableTest> tests) { return new TestFinder(tests, extensions); } private static class TestFinder implements IResourceVisitor { private final Extensions extensions; private final Set<RunnableTest> tests; private TestFinder(Set<RunnableTest> tests, Extensions extensions) { this.tests = tests; this.extensions = extensions; } @Override public boolean visit(IResource resource) throws CoreException { if (resource instanceof IFile) { IFile file = (IFile) resource; for (ITestType testType : extensions.getTestTypesFor(file)) { tests.add(new RunnableTest(file, testType)); } } return true; } } }