prohibit modifications of mock jdk to avoid corrupting it by unrelated tests

This commit is contained in:
Alexey Kudravtsev
2016-08-19 14:11:34 +03:00
parent 997b9896b9
commit 45bfad69ed
9 changed files with 255 additions and 68 deletions
@@ -81,7 +81,8 @@ public final class MockJdkWrapper implements Sdk {
@NotNull
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
Sdk delegateClone = (Sdk)myDelegate.clone();
return new MockJdkWrapper(myHomePath, delegateClone);
}
public SdkAdditionalData getSdkAdditionalData() {
@@ -19,6 +19,7 @@ import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.util.ExecUtil;
import com.intellij.icons.AllIcons;
import com.intellij.lang.LangBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -30,16 +31,19 @@ import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.JavadocOrderRootType;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.RootProvider;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.impl.jrt.JrtFileSystem;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jps.model.java.impl.JavaSdkUtil;
import javax.swing.*;
@@ -527,12 +531,136 @@ public class JavaSdkImpl extends JavaSdk {
return jdk;
}
@NotNull
@TestOnly
public Sdk createMockJdk(@NotNull String jdkName, @NotNull String home, boolean isJre) {
String homePath = home.replace(File.separatorChar, '/');
File jdkHomeFile = new File(homePath);
List<VirtualFile> classes = findClasses(jdkHomeFile, isJre);
VirtualFile sources = findSources(jdkHomeFile);
VirtualFile docs = findDocs(jdkHomeFile, "docs/api");
ProjectRootContainerImpl rootContainer = new ProjectRootContainerImpl(true);
rootContainer.startChange();
for (VirtualFile aClass : classes) {
rootContainer.addRoot(aClass, OrderRootType.CLASSES);
}
if (sources != null) {
rootContainer.addRoot(sources, OrderRootType.SOURCES);
}
if (docs != null) {
rootContainer.addRoot(docs, OrderRootType.DOCUMENTATION);
}
rootContainer.finishChange();
ProjectJdkImpl jdk = new ProjectJdkImpl(jdkName, this, homePath, jdkName) {
@Override
public void setName(@NotNull String name) {
throwReadOnly();
}
@Override
public void readExternal(@NotNull Element element) {
throwReadOnly();
}
@Override
public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) {
throwReadOnly();
}
@NotNull
@Override
public SdkModificator getSdkModificator() {
throwReadOnly();
return null;
}
@Override
public void setSdkAdditionalData(SdkAdditionalData data) {
throwReadOnly();
}
@Override
public void addRoot(VirtualFile root, OrderRootType rootType) {
throwReadOnly();
}
@Override
public void removeRoot(VirtualFile root, OrderRootType rootType) {
throwReadOnly();
}
@Override
public void removeRoots(OrderRootType rootType) {
throwReadOnly();
}
@Override
public void removeAllRoots() {
throwReadOnly();
}
@Override
public boolean isWritable() {
return false;
}
@Override
public void update() {
throwReadOnly();
}
@Override
public VirtualFile[] getRoots(OrderRootType rootType) {
return rootContainer.getRootFiles(rootType);
}
@NotNull
@Override
public RootProvider getRootProvider() {
return new RootProvider() {
@NotNull
@Override
public String[] getUrls(@NotNull OrderRootType rootType) {
return ContainerUtil.map2Array(getFiles(rootType), String.class, VirtualFile::getUrl);
}
@NotNull
@Override
public VirtualFile[] getFiles(@NotNull OrderRootType rootType) {
return getRoots(rootType);
}
@Override
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener) {
}
@Override
public void addRootSetChangedListener(@NotNull RootSetChangedListener listener, @NotNull Disposable parentDisposable) {
}
@Override
public void removeRootSetChangedListener(@NotNull RootSetChangedListener listener) {
}
};
}
};
ProjectJdkImpl.copyRoots(rootContainer, jdk);
return jdk;
}
private static void throwReadOnly() {
throw new IncorrectOperationException("Can't modify, MockJDK is read-only, consider calling .clone() first");
}
private static void addClasses(File file, SdkModificator sdkModificator, boolean isJre) {
for (VirtualFile virtualFile : findClasses(file, isJre)) {
sdkModificator.addRoot(virtualFile, OrderRootType.CLASSES);
}
}
@NotNull
private static List<VirtualFile> findClasses(File file, boolean isJre) {
List<VirtualFile> result = ContainerUtil.newArrayList();
VirtualFileManager fileManager = VirtualFileManager.getInstance();
@@ -555,7 +683,7 @@ public class JavaSdkImpl extends JavaSdk {
return result;
}
private static void addSources(File file, SdkModificator sdkModificator) {
private static void addSources(@NotNull File file, @NotNull SdkModificator sdkModificator) {
VirtualFile vFile = findSources(file);
if (vFile != null) {
sdkModificator.addRoot(vFile, OrderRootType.SOURCES);
@@ -571,7 +699,6 @@ public class JavaSdkImpl extends JavaSdk {
@Nullable
@SuppressWarnings("HardCodedStringLiteral")
private static VirtualFile findSources(File file, final String srcName) {
File srcDir = new File(file, "src");
File jarFile = new File(file, srcName + ".jar");
if (!jarFile.exists()) {
jarFile = new File(file, srcName + ".zip");
@@ -585,6 +712,7 @@ public class JavaSdkImpl extends JavaSdk {
return vFile;
}
else {
File srcDir = new File(file, "src");
if (!srcDir.exists() || !srcDir.isDirectory()) return null;
String path = srcDir.getAbsolutePath().replace(File.separatorChar, '/');
return LocalFileSystem.getInstance().findFileByPath(path);
@@ -608,7 +736,7 @@ public class JavaSdkImpl extends JavaSdk {
}
@Nullable
private static VirtualFile findDocs(File file, final String relativePath) {
private static VirtualFile findDocs(@NotNull File file, @NotNull String relativePath) {
file = new File(file.getAbsolutePath() + File.separator + relativePath.replace('/', File.separatorChar));
if (!file.exists() || !file.isDirectory()) return null;
String path = file.getAbsolutePath().replace(File.separatorChar, '/');
@@ -28,8 +28,8 @@ import com.intellij.codeInspection.nullable.NullableStuffInspection;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.InspectionTestCase;
import com.intellij.testFramework.PsiTestUtil;
@@ -55,18 +55,26 @@ public class NullableStuffInspectionAncientTest extends InspectionTestCase {
}
@Override
protected void setupRootModel(@NotNull String testDir, @NotNull VirtualFile[] sourceDir, String sdkName) {
super.setupRootModel(testDir, sourceDir, sdkName);
Sdk sdk = ModuleRootManager.getInstance(myModule).getSdk();
removeAnnotationsJar(sdk);
protected Sdk getTestProjectSdk() {
Sdk sdk = super.getTestProjectSdk();
sdk = removeAnnotationsJar(sdk);
if ("testJdkAnnotationsWithoutJetBrainsAnnotations".equals(getName())) {
PsiTestUtil.addJdkAnnotations(sdk);
sdk = PsiTestUtil.addJdkAnnotations(sdk);
}
return sdk;
}
private static void removeAnnotationsJar(final Sdk sdk) {
ApplicationManager.getApplication().runWriteAction(() -> {
final SdkModificator sdkMod = sdk.getSdkModificator();
@NotNull
private static Sdk removeAnnotationsJar(@NotNull Sdk sdk) {
return ApplicationManager.getApplication().runWriteAction((Computable<Sdk>)() -> {
Sdk clone;
try {
clone = (Sdk)sdk.clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
final SdkModificator sdkMod = clone.getSdkModificator();
for (VirtualFile file : sdkMod.getRoots(OrderRootType.CLASSES)) {
if ("annotations.jar".equals(file.getName())) {
sdkMod.removeRoot(file, OrderRootType.CLASSES);
@@ -74,6 +82,7 @@ public class NullableStuffInspectionAncientTest extends InspectionTestCase {
}
}
sdkMod.commitChanges();
return clone;
});
}
}
@@ -57,7 +57,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
private static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private MessageDigest myMessageDigest;
private List<String> myDiffs = new ArrayList<>();
private final List<String> myDiffs = new ArrayList<>();
private boolean myNullableMethodRegistryValue;
@Override
@@ -104,9 +104,17 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
}
Sdk sdk = modifiableRootModel.getSdk();
if (sdk != null) {
SdkModificator sdkModificator = sdk.getSdkModificator();
Sdk clone;
try {
clone = (Sdk)sdk.clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
SdkModificator sdkModificator = clone.getSdkModificator();
sdkModificator.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
sdkModificator.commitChanges();
modifiableRootModel.setSdk(clone);
}
}
});
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.ModuleTestCase;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.PathsList;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -58,7 +59,14 @@ public abstract class ModuleRootManagerTestCase extends ModuleTestCase {
}
@NotNull
@Contract(pure = true)
private static Sdk retainRtJarOnlyAndSetVersion(Sdk jdk) {
try {
jdk = (Sdk)jdk.clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
final SdkModificator modificator = jdk.getSdkModificator();
VirtualFile rtJar = null;
for (VirtualFile root : modificator.getRoots(OrderRootType.CLASSES)) {
@@ -126,7 +126,13 @@ public class RootsChangedTest extends ModuleTestCase {
Module a = loadModule(PathManagerEx.getHomePath(getClass()) + "/java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml");
assertEventsCount(1);
final Sdk jdk = IdeaTestUtil.getMockJdk17();
final Sdk jdk;
try {
jdk = (Sdk)IdeaTestUtil.getMockJdk17().clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
ProjectJdkTable.getInstance().addJdk(jdk);
assertEventsCount(0);
@@ -148,7 +154,13 @@ public class RootsChangedTest extends ModuleTestCase {
final Module moduleB = createModule("b.iml");
assertEventsCount(2);
final Sdk jdk = IdeaTestUtil.getMockJdk17();
final Sdk jdk;
try {
jdk = (Sdk)IdeaTestUtil.getMockJdk17().clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
ProjectJdkTable.getInstance().addJdk(jdk);
assertEventsCount(0);
@@ -156,7 +168,7 @@ public class RootsChangedTest extends ModuleTestCase {
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
rootModelA.setSdk(jdk);
rootModelB.setSdk(jdk);
ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB};
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
assertEventsCount(1);
@@ -177,11 +189,18 @@ public class RootsChangedTest extends ModuleTestCase {
final Module moduleB = createModule("b.iml");
assertEventsCount(2);
final Sdk jdk = IdeaTestUtil.getMockJdk17("AAA");
ProjectJdkTable.getInstance().addJdk(jdk);
assertEventsCount(0);
final Sdk jdk;
final Sdk jdkBBB;
try {
jdk = (Sdk)IdeaTestUtil.getMockJdk17("AAA").clone();
ProjectJdkTable.getInstance().addJdk(jdk);
assertEventsCount(0);
final Sdk jdkBBB = IdeaTestUtil.getMockJdk17("BBB");
jdkBBB = (Sdk)IdeaTestUtil.getMockJdk17("BBB").clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
ProjectJdkTable.getInstance().addJdk(jdk);
assertEventsCount(0);
@@ -192,7 +211,7 @@ public class RootsChangedTest extends ModuleTestCase {
final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel();
rootModelA.inheritSdk();
rootModelB.inheritSdk();
ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB};
ModifiableRootModel[] rootModels = {rootModelA, rootModelB};
if (rootModels.length > 0) {
ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
}
@@ -211,7 +230,7 @@ public class RootsChangedTest extends ModuleTestCase {
});
}
private void verifyLibraryTableEditing(final LibraryTable libraryTable) throws IOException {
private void verifyLibraryTableEditing(final LibraryTable libraryTable) {
final Module moduleA = createModule("a.iml");
final Module moduleB = createModule("b.iml");
assertEventsCount(2);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
@@ -27,28 +28,23 @@ import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.PathUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.junit.Assume;
import java.io.File;
import java.util.List;
import static org.junit.Assume.assumeTrue;
public class IdeaTestUtil extends PlatformTestUtil {
private static final String MOCK_JDK_DIR_NAME_PREFIX = "mockJDK-";
public static void main(String[] args) {
printDetectedPerformanceTimings();
}
@SuppressWarnings({"UseOfSystemOutOrSystemErr"})
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public static void printDetectedPerformanceTimings() {
System.out.println(Timings.getStatistics());
}
@@ -76,20 +72,30 @@ public class IdeaTestUtil extends PlatformTestUtil {
modifiable.commit();
}
@TestOnly
public static Sdk getMockJdk17() {
return getMockJdk17("java 1.7");
}
@NotNull
@TestOnly
private static Sdk createMockJdk(@NotNull String name, String path) {
return ((JavaSdkImpl)JavaSdk.getInstance()).createMockJdk(name, path, false);
}
@TestOnly
public static Sdk getMockJdk17(@NotNull String name) {
return JavaSdk.getInstance().createJdk(name, getMockJdk17Path().getPath(), false);
return createMockJdk(name, getMockJdk17Path().getPath());
}
@TestOnly
public static Sdk getMockJdk18() {
return JavaSdk.getInstance().createJdk("java 1.8", getMockJdk18Path().getPath(), false);
return createMockJdk("java 1.8", getMockJdk18Path().getPath());
}
@TestOnly
public static Sdk getMockJdk14() {
return JavaSdk.getInstance().createJdk("java 1.4", getMockJdk14Path().getPath(), false);
return createMockJdk("java 1.4", getMockJdk14Path().getPath());
}
public static File getMockJdk14Path() {
@@ -117,17 +123,27 @@ public class IdeaTestUtil extends PlatformTestUtil {
return mockJdkCEPath.exists() ? mockJdkCEPath : new File(PathManager.getHomePath(), "community/java/" + name);
}
@TestOnly
public static Sdk getWebMockJdk17() {
Sdk jdk = getMockJdk17();
addWebJarsTo(jdk);
jdk=addWebJarsTo(jdk);
return jdk;
}
public static void addWebJarsTo(@NotNull Sdk jdk) {
@NotNull
@Contract(pure=true)
public static Sdk addWebJarsTo(@NotNull Sdk jdk) {
try {
jdk = (Sdk)jdk.clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
SdkModificator sdkModificator = jdk.getSdkModificator();
sdkModificator.addRoot(findJar("lib/jsp-api.jar"), OrderRootType.CLASSES);
sdkModificator.addRoot(findJar("lib/servlet-api.jar"), OrderRootType.CLASSES);
sdkModificator.commitChanges();
return jdk;
}
private static VirtualFile findJar(String name) {
@@ -145,12 +161,7 @@ public class IdeaTestUtil extends PlatformTestUtil {
final String oldVersionString = sdk.getVersionString();
((ProjectJdkImpl)sdk).setVersionString(testVersion.getDescription());
assert JavaSdk.getInstance().getVersion(sdk) == testVersion;
Disposer.register(parentDisposable, new Disposable() {
@Override
public void dispose() {
((ProjectJdkImpl)sdk).setVersionString(oldVersionString);
}
});
Disposer.register(parentDisposable, () -> ((ProjectJdkImpl)sdk).setVersionString(oldVersionString));
}
@@ -164,7 +175,7 @@ public class IdeaTestUtil extends PlatformTestUtil {
return path;
}
}
assumeTrue("Cannot find JDK, checked paths: " + paths, false);
Assume.assumeTrue("Cannot find JDK, checked paths: " + paths, false);
return null;
}
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
import com.intellij.openapi.projectRoots.ex.ProjectRootContainer;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.RootProvider;
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
@@ -42,7 +41,7 @@ import java.util.List;
public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModificator {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectJdkImpl");
private final ProjectRootContainerImpl myRootContainer;
final ProjectRootContainerImpl myRootContainer;
private String myName;
private String myVersionString;
private boolean myVersionDefined;
@@ -248,28 +247,24 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
final String name = getName();
dest.setName(name);
dest.setHomePath(getHomePath());
if (myVersionDefined) {
dest.setVersionString(getVersionString());
}
else {
dest.resetVersionString();
}
dest.myVersionDefined = myVersionDefined;
dest.myVersionString = myVersionString;
dest.setSdkAdditionalData(getSdkAdditionalData());
copyRoots(myRootContainer, dest);
}
static void copyRoots(@NotNull ProjectRootContainerImpl rootContainer, @NotNull ProjectJdkImpl dest) {
dest.myRootContainer.startChange();
dest.myRootContainer.removeAllRoots();
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
copyRoots(myRootContainer, dest.myRootContainer, rootType);
final ProjectRoot[] newRoots = rootContainer.getRoots(rootType);
for (ProjectRoot newRoot : newRoots) {
dest.myRootContainer.addRoot(newRoot, rootType);
}
}
dest.myRootContainer.finishChange();
}
private static void copyRoots(ProjectRootContainer srcContainer, ProjectRootContainer destContainer, OrderRootType type) {
final ProjectRoot[] newRoots = srcContainer.getRoots(type);
for (ProjectRoot newRoot : newRoots) {
destContainer.addRoot(newRoot, type);
}
}
private class MyRootProvider extends RootProviderBaseImpl implements ProjectRootListener {
@Override
@NotNull
@@ -39,6 +39,7 @@ import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsElement;
@@ -371,14 +372,21 @@ public class PsiTestUtil {
ModuleRootModificationUtil.updateModel(module, model -> model.getModuleExtension(JavaModuleExternalPaths.class).setJavadocUrls(urls));
}
public static Sdk addJdkAnnotations(Sdk sdk) {
@NotNull
@Contract(pure=true)
public static Sdk addJdkAnnotations(@NotNull Sdk sdk) {
String path = FileUtil.toSystemIndependentName(PlatformTestUtil.getCommunityPath()) + "/java/jdkAnnotations";
VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path);
if (root != null) {
SdkModificator sdkModificator = sdk.getSdkModificator();
sdkModificator.addRoot(root, AnnotationOrderRootType.getInstance());
sdkModificator.commitChanges();
Sdk clone;
try {
clone = (Sdk)sdk.clone();
}
return sdk;
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
SdkModificator sdkModificator = clone.getSdkModificator();
sdkModificator.addRoot(root, AnnotationOrderRootType.getInstance());
sdkModificator.commitChanges();
return clone;
}
}