getTestDataPath optimized

This commit is contained in:
nik
2012-09-06 16:18:31 +04:00
parent 675529ce18
commit 5563b8404d
@@ -25,18 +25,25 @@
package com.intellij.openapi.application.ex;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.module.impl.ModuleManagerImpl;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.testFramework.TestRunnerUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ConcurrentHashMap;
import gnu.trove.THashSet;
import junit.framework.TestCase;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.serialization.JDomSerializationUtil;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
import static java.util.Arrays.asList;
@@ -59,14 +66,7 @@ public class PathManagerEx {
/** Caches test data lookup strategy by class. */
private static final ConcurrentMap<Class, TestDataLookupStrategy> CLASS_STRATEGY_CACHE = new ConcurrentHashMap<Class, TestDataLookupStrategy>();
private static final ConcurrentMap<String, Class> CLASS_CACHE = new ConcurrentHashMap<String, Class>();
/**
* Holds names of the files that contain community test classes.
* <p/>
* <b>Note:</b> stored names are relative to the source roots.
*/
private static final Set<String> COMMUNITY_TEST_FILES = new HashSet<String>();
private static final AtomicBoolean COMMUNITY_TEST_FILES_PARSED_FLAG = new AtomicBoolean();
private static Set<String> ourCommunityModules;
private PathManagerEx() {
}
@@ -170,11 +170,19 @@ public class PathManagerEx {
/**
* @return path to 'community' project home irrespective of current project
*/
public static String getCommunityHomePath() {
private static String getCommunityHomePath() {
String path = PathManager.getHomePath();
return isLocatedInCommunity() ? path : path + File.separator + "community";
}
/**
* @return path to 'community' project home if {@code testClass} is located in the community project and path to 'ultimate' project otherwise
*/
public static String getHomePath(Class<? extends TestCase> testClass) {
TestDataLookupStrategy strategy = isLocatedInCommunity() ? TestDataLookupStrategy.COMMUNITY : determineLookupStrategy(testClass);
return strategy == TestDataLookupStrategy.COMMUNITY_FROM_ULTIMATE ? getCommunityHomePath() : PathManager.getHomePath();
}
/**
* Find file by its path relative to 'community' directory irrespective of current project
* @param relativePath path to file relative to 'community' directory
@@ -188,6 +196,19 @@ public class PathManagerEx {
return file;
}
/**
* Find file by its path relative to project home directory (the 'commmunity' project if {@code testClass} is located in the community project
* and the 'ultimate' project otherwise)
*/
public static File findFileUnderProjectHome(String relativePath, Class<? extends TestCase> testClass) {
String homePath = getHomePath(testClass);
File file = new File(homePath, toSystemDependentName(relativePath));
if (!file.exists()) {
throw new IllegalArgumentException("Cannot find file '" + relativePath + "' under '" + homePath + "' directory");
}
return file;
}
private static boolean isLocatedInCommunity() {
FileSystemLocation projectLocation = parseProjectLocation();
return projectLocation == FileSystemLocation.COMMUNITY;
@@ -326,13 +347,7 @@ public class PathManagerEx {
return result;
}
String targetFile = toSystemDependentName(clazz.getName().replace('.', '/'));
if (COMMUNITY_TEST_FILES_PARSED_FLAG.compareAndSet(false, true)) {
parseCommunityTestFiles();
}
FileSystemLocation classFileLocation = COMMUNITY_TEST_FILES.contains(targetFile) ? FileSystemLocation.COMMUNITY
: FileSystemLocation.ULTIMATE;
FileSystemLocation classFileLocation = computeClassLocation(clazz);
// We know that project location is ULTIMATE if control flow reaches this place.
result = classFileLocation == FileSystemLocation.COMMUNITY ? TestDataLookupStrategy.COMMUNITY_FROM_ULTIMATE
@@ -341,6 +356,53 @@ public class PathManagerEx {
return result;
}
private static FileSystemLocation computeClassLocation(Class<?> clazz) {
String classRootPath = PathManager.getJarPathForClass(clazz);
if (classRootPath == null) {
throw new IllegalStateException("Cannot find root directory for " + clazz);
}
File root = new File(classRootPath);
if (!root.exists()) {
throw new IllegalStateException("Classes root " + root + " doesn't exist");
}
if (!root.isDirectory()) {
//this means that clazz is located in a library, perhaps we should throw exception here
return FileSystemLocation.ULTIMATE;
}
String moduleName = root.getName();
return getCommunityModules().contains(moduleName) ? FileSystemLocation.COMMUNITY : FileSystemLocation.ULTIMATE;
}
private synchronized static Set<String> getCommunityModules() {
if (ourCommunityModules != null) {
return ourCommunityModules;
}
ourCommunityModules = new THashSet<String>();
File modulesXml = findFileUnderCommunityHome(".idea/modules.xml");
if (!modulesXml.exists()) {
throw new IllegalStateException("Cannot obtain test data path: " + modulesXml.getAbsolutePath() + " not found");
}
try {
Element componentRoot = JDomSerializationUtil
.findComponent(JDOMUtil.loadDocument(modulesXml).getRootElement(), ModuleManagerImpl.COMPONENT_NAME);
ModuleManagerImpl.ModulePath[] files = ModuleManagerImpl.getPathsToModuleFiles(componentRoot);
for (ModuleManagerImpl.ModulePath file : files) {
String name = FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.getPath()));
ourCommunityModules.add(name);
}
return ourCommunityModules;
}
catch (JDOMException e) {
throw new RuntimeException("Cannot read modules from " + modulesXml.getAbsolutePath(), e);
}
catch (IOException e) {
throw new RuntimeException("Cannot read modules from " + modulesXml.getAbsolutePath(), e);
}
}
/**
* Allows to determine project type by its file system location.
*
@@ -350,10 +412,6 @@ public class PathManagerEx {
return new File(PathManager.getHomePath(), "community").isDirectory() ? FileSystemLocation.ULTIMATE : FileSystemLocation.COMMUNITY;
}
private static void parseCommunityTestFiles() {
new CommunityClassesResolver().dispatch(new File(PathManager.getHomePath(), "community"));
}
/**
* Tries to check test data lookup strategy by target test data directories availability.
* <p/>
@@ -373,49 +431,4 @@ public class PathManagerEx {
}
return TestDataLookupStrategy.ULTIMATE;
}
/**
* Recursively processes all files under directory given to {@link #dispatch(File)} and updates {@link #COMMUNITY_TEST_FILES} with
* all <code>'*.java'</code> files accordingly.
*/
private static class CommunityClassesResolver {
@SuppressWarnings({"MethodMayBeStatic"})
public void dispatch(File dir) {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
if (!ignoreDirectory(file, dir)) dispatch(file);
}
else {
process(file);
}
}
}
private static boolean ignoreDirectory(File file, File parent) {
String fileName = file.getName();
return fileName.startsWith(".") || "out".equals(fileName) || "testData".equalsIgnoreCase(fileName) ||
("src".equals(fileName) && !"testFramework".equals(parent.getName()));
}
private static void process(File file) {
String path = file.getAbsolutePath();
if (!path.endsWith(".java") && !path.endsWith(".groovy")) {
return;
}
String src = "src";
String testSrc = "testSrc";
int srcIndex = path.indexOf(src);
int testSrcIndex = path.indexOf(testSrc);
int indexToUse = srcIndex > testSrcIndex ? srcIndex + src.length() : testSrcIndex + testSrc.length();
indexToUse++; // for path separator
if (indexToUse < 0 || indexToUse >= path.length()) {
// Never expect to be here.
return;
}
COMMUNITY_TEST_FILES.add(StringUtil.trimEnd(StringUtil.trimEnd(path.substring(indexToUse), ".java"), ".groovy"));
}
}
}