diff --git a/platform/testFramework/src/com/intellij/openapi/application/ex/PathManagerEx.java b/platform/testFramework/src/com/intellij/openapi/application/ex/PathManagerEx.java index c1eb38f4885f..995481b16f44 100644 --- a/platform/testFramework/src/com/intellij/openapi/application/ex/PathManagerEx.java +++ b/platform/testFramework/src/com/intellij/openapi/application/ex/PathManagerEx.java @@ -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_STRATEGY_CACHE = new ConcurrentHashMap(); private static final ConcurrentMap CLASS_CACHE = new ConcurrentHashMap(); - - /** - * Holds names of the files that contain community test classes. - *

- * Note: stored names are relative to the source roots. - */ - private static final Set COMMUNITY_TEST_FILES = new HashSet(); - private static final AtomicBoolean COMMUNITY_TEST_FILES_PARSED_FLAG = new AtomicBoolean(); + private static Set 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 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 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 getCommunityModules() { + if (ourCommunityModules != null) { + return ourCommunityModules; + } + + ourCommunityModules = new THashSet(); + 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. *

@@ -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 '*.java' 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")); - } - } }