Fix "Virtual pointer hasn't been disposed" exception in tests. Add sdk to ProjectJdkTable.

This commit is contained in:
Natalia Selezneva
2018-01-30 16:11:31 +03:00
parent f05e926670
commit 74a9881e9d
11 changed files with 74 additions and 36 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.android;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.tools.idea.res.ResourceHelper; import com.android.tools.idea.res.ResourceHelper;
import com.android.tools.idea.startup.ExternalAnnotationsSupport; import com.android.tools.idea.startup.ExternalAnnotationsSupport;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
@@ -56,6 +57,8 @@ public abstract class AndroidTestBase extends UsefulTestCase {
protected JavaCodeInsightTestFixture myFixture; protected JavaCodeInsightTestFixture myFixture;
protected static final String ANDROID_SDK_NAME = "android_test_sdk";
protected AndroidTestBase() { protected AndroidTestBase() {
// IDEA14 seems to be stricter regarding validating accesses against known roots. By default, it contains the entire idea folder, // IDEA14 seems to be stricter regarding validating accesses against known roots. By default, it contains the entire idea folder,
// but it doesn't seem to include our custom structure tools/idea/../adt/idea where the android plugin is placed. // but it doesn't seem to include our custom structure tools/idea/../adt/idea where the android plugin is placed.
@@ -100,7 +103,7 @@ public abstract class AndroidTestBase extends UsefulTestCase {
String sdkPath = TestUtils.getSdk().toString(); String sdkPath = TestUtils.getSdk().toString();
String platformDir = TestUtils.getLatestAndroidPlatform(); String platformDir = TestUtils.getLatestAndroidPlatform();
Sdk sdk = ProjectJdkTable.getInstance().createSdk("android_test_sdk", AndroidSdkType.getInstance()); Sdk sdk = ProjectJdkTable.getInstance().createSdk(ANDROID_SDK_NAME, AndroidSdkType.getInstance());
SdkModificator sdkModificator = sdk.getSdkModificator(); SdkModificator sdkModificator = sdk.getSdkModificator();
sdkModificator.setHomePath(sdkPath); sdkModificator.setHomePath(sdkPath);
@@ -131,6 +134,9 @@ public abstract class AndroidTestBase extends UsefulTestCase {
sdkModificator.setSdkAdditionalData(data); sdkModificator.setSdkAdditionalData(data);
ExternalAnnotationsSupport.attachJdkAnnotations(sdkModificator); ExternalAnnotationsSupport.attachJdkAnnotations(sdkModificator);
sdkModificator.commitChanges(); sdkModificator.commitChanges();
ApplicationManager.getApplication().runWriteAction(() -> ProjectJdkTable.getInstance().addJdk(sdk));
return sdk; return sdk;
} }
@@ -29,6 +29,8 @@ import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Disposer;
@@ -153,6 +155,11 @@ public abstract class AndroidTestCase extends AndroidTestBase {
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
try { try {
Sdk androidSdk = ProjectJdkTable.getInstance().findJdk(ANDROID_SDK_NAME);
if (androidSdk != null) {
ApplicationManager.getApplication().runWriteAction(() -> ProjectJdkTable.getInstance().removeJdk(androidSdk));
}
CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings(); CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings();
myModule = null; myModule = null;
myAdditionalModules = null; myAdditionalModules = null;
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.test
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModifiableRootModel import com.intellij.openapi.roots.ModifiableRootModel
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import java.io.File import java.io.File
import java.util.* import java.util.*
import kotlin.test.assertNotNull
/** /**
* Helper for configuring kotlin runtime in tested project. * Helper for configuring kotlin runtime in tested project.
@@ -88,6 +90,13 @@ object ConfigLibraryUtil {
val rootManager = ModuleRootManager.getInstance(module) val rootManager = ModuleRootManager.getInstance(module)
val rootModel = rootManager.modifiableModel val rootModel = rootManager.modifiableModel
assertNotNull(
ProjectJdkTable.getInstance().findJdk(sdk.name),
"Cannot find sdk in ProjectJdkTable. This may cause sdk leak.\n" +
"You can use ProjectPluginTestBase.addJdk(Disposable ...) to register sdk in ProjectJdkTable.\n" +
"Then sdk will be removed in tearDown"
)
rootModel.sdk = sdk rootModel.sdk = sdk
rootModel.commit() rootModel.commit()
} }
@@ -25,6 +25,7 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.KotlinTestUtils;
@@ -52,6 +53,11 @@ public class PluginTestCaseBase {
@NotNull @NotNull
private static Sdk getSdk(String sdkHome, String name) { private static Sdk getSdk(String sdkHome, String name) {
ProjectJdkTable table = ProjectJdkTable.getInstance();
Sdk existing = table.findJdk(name);
if (existing != null) {
return existing;
}
return JavaSdk.getInstance().createJdk(name, sdkHome, true); return JavaSdk.getInstance().createJdk(name, sdkHome, true);
} }
@@ -84,6 +90,13 @@ public class PluginTestCaseBase {
return getSdk(javaHome, "Full JDK"); return getSdk(javaHome, "Full JDK");
} }
@NotNull
public static Sdk addJdk(@NotNull Disposable disposable, @NotNull Function0<Sdk> getJdk) {
Sdk jdk = getJdk.invoke();
ApplicationManager.getApplication().runWriteAction(() -> ProjectJdkTable.getInstance().addJdk(jdk, disposable));
return jdk;
}
@NotNull @NotNull
public static Sdk jdk(@NotNull TestJdkKind kind) { public static Sdk jdk(@NotNull TestJdkKind kind) {
switch (kind) { switch (kind) {
@@ -18,17 +18,18 @@ package org.jetbrains.kotlin.asJava
import com.intellij.psi.JavaPsiFacade import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.impl.ResolveScopeManager import com.intellij.psi.impl.ResolveScopeManager
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.KtLightClassForDecompiledDeclaration import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.KtLightClassForDecompiledDeclaration
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.SdkAndMockLibraryProjectDescriptor import org.jetbrains.kotlin.idea.test.SdkAndMockLibraryProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.test.configureAs
import java.io.File import java.io.File
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
class LightClassesClasspathSortingTest : KotlinCodeInsightTestCase() { class LightClassesClasspathSortingTest : KotlinLightCodeInsightFixtureTestCase() {
fun testExplicitClass() { fun testExplicitClass() {
doTest("test1.A") doTest("test1.A")
} }
@@ -40,13 +41,11 @@ class LightClassesClasspathSortingTest : KotlinCodeInsightTestCase() {
private fun doTest(fqName: String) { private fun doTest(fqName: String) {
// Same classes are in sources and in compiled Kotlin library. Test that light classes from sources have a priority. // Same classes are in sources and in compiled Kotlin library. Test that light classes from sources have a priority.
// Configure library first to make classes be indexed before correspondent classes from sources
val dirName = getTestName(true) val dirName = getTestName(true)
module.configureAs(getProjectDescriptor(dirName))
val testDirRoot = File(testDataPath) val testDirRoot = File(testDataPath)
val filePaths = File(testDirRoot, dirName).listFiles().map { it.toRelativeString(testDirRoot) }.toTypedArray() val filePaths = File(testDirRoot, dirName).listFiles().map { it.toRelativeString(testDirRoot) }.toTypedArray()
configureByFiles(null, *filePaths) myFixture.configureByFiles(*filePaths)
checkLightClassBeforeDecompiled(fqName) checkLightClassBeforeDecompiled(fqName)
} }
@@ -60,13 +59,14 @@ class LightClassesClasspathSortingTest : KotlinCodeInsightTestCase() {
assert(psiClass !is KtLightClassForDecompiledDeclaration) { "Should not be decompiled light class: $fqName ${psiClass::class.java}" } assert(psiClass !is KtLightClassForDecompiledDeclaration) { "Should not be decompiled light class: $fqName ${psiClass::class.java}" }
} }
private fun getProjectDescriptor(dir: String) = override fun getProjectDescriptor(): LightProjectDescriptor {
SdkAndMockLibraryProjectDescriptor( return SdkAndMockLibraryProjectDescriptor(
PluginTestCaseBase.getTestDataPathBase() + "/decompiler/lightClassesOrder/$dir", "$testDataPath${getTestName(true)}",
true true
) )
}
override fun getTestDataPath(): String? { override fun getTestDataPath(): String {
return PluginTestCaseBase.getTestDataPathBase() + "/decompiler/lightClassesOrder/" return KotlinTestUtils.getHomeDirectory() + "/idea/testData/decompiler/lightClassesOrder/"
} }
} }
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.idea.inspections.runInspection
import org.jetbrains.kotlin.idea.jsonUtils.getString import org.jetbrains.kotlin.idea.jsonUtils.getString
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.*
import org.jetbrains.kotlin.idea.util.projectStructure.allModules import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import java.io.File import java.io.File
@@ -41,13 +41,13 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
isMultiModule = config["isMultiModule"]?.asBoolean ?: false isMultiModule = config["isMultiModule"]?.asBoolean ?: false
doTest({ _, _ -> doTest({ _, _ ->
val sdk = if (withFullJdk) fullJdk() else mockJdk()
addJdk(testRootDisposable) { sdk }
try { try {
if (withRuntime) { if (withRuntime) {
project.allModules().forEach { module -> project.allModules().forEach { module ->
ConfigLibraryUtil.configureKotlinRuntimeAndSdk( ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, sdk)
module,
if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
)
} }
} }
@@ -57,10 +57,7 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
finally { finally {
if (withRuntime) { if (withRuntime) {
project.allModules().forEach { module -> project.allModules().forEach { module ->
ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk( ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(module, sdk)
module,
if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
)
} }
} }
} }
@@ -73,6 +70,6 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
} }
override fun getTestDataPath() : String { override fun getTestDataPath() : String {
return PluginTestCaseBase.getTestDataPathBase() return getTestDataPathBase()
} }
} }
@@ -331,6 +331,8 @@ abstract class AbstractExtractionTest : KotlinLightCodeInsightFixtureTestCase()
protected fun doTest(path: String, checkAdditionalAfterdata: Boolean = false, action: (PsiFile) -> Unit) { protected fun doTest(path: String, checkAdditionalAfterdata: Boolean = false, action: (PsiFile) -> Unit) {
val mainFile = File(path) val mainFile = File(path)
PluginTestCaseBase.addJdk(myFixture.projectDisposable, PluginTestCaseBase::mockJdk)
fixture.testDataPath = "${KotlinTestUtils.getHomeDirectory()}/${mainFile.parent}" fixture.testDataPath = "${KotlinTestUtils.getHomeDirectory()}/${mainFile.parent}"
val mainFileName = mainFile.name val mainFileName = mainFile.name
@@ -38,6 +38,8 @@ abstract class AbstractMultiModuleMoveTest : KotlinMultiFileTestCase() {
val modulesWithJvmRuntime: List<Module> val modulesWithJvmRuntime: List<Module>
val modulesWithJsRuntime: List<Module> val modulesWithJsRuntime: List<Module>
PluginTestCaseBase.addJdk(testRootDisposable, PluginTestCaseBase::mockJdk)
val withRuntime = config["withRuntime"]?.asBoolean ?: false val withRuntime = config["withRuntime"]?.asBoolean ?: false
if (withRuntime) { if (withRuntime) {
val moduleManager = ModuleManager.getInstance(project) val moduleManager = ModuleManager.getInstance(project)
@@ -38,7 +38,7 @@ import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren import org.jetbrains.kotlin.psi.psiUtil.allChildren
@@ -56,7 +56,7 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
fun testMainInTest() { fun testMainInTest() {
val createResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!) val createResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!)
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createResult.module, PluginTestCaseBase.mockJdk()) ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createResult.module, addJdk(testRootDisposable, ::mockJdk))
val runConfiguration = createConfigurationFromMain("some.main") val runConfiguration = createConfigurationFromMain("some.main")
val javaParameters = getJavaRunParameters(runConfiguration) val javaParameters = getJavaRunParameters(runConfiguration)
@@ -142,7 +142,7 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
fun testUpdateOnClassRename() { fun testUpdateOnClassRename() {
val createModuleResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!) val createModuleResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!)
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createModuleResult.module, PluginTestCaseBase.mockJdk()) ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createModuleResult.module, addJdk(testRootDisposable, ::mockJdk))
val runConfiguration = createConfigurationFromObject("renameTest.Foo", save = true) val runConfiguration = createConfigurationFromObject("renameTest.Foo", save = true)
@@ -155,7 +155,7 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
fun testUpdateOnPackageRename() { fun testUpdateOnPackageRename() {
val createModuleResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!) val createModuleResult = configureModule(moduleDirPath("module"), getTestProject().baseDir!!)
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createModuleResult.module, PluginTestCaseBase.mockJdk()) ConfigLibraryUtil.configureKotlinRuntimeAndSdk(createModuleResult.module, addJdk(testRootDisposable, ::mockJdk))
val runConfiguration = createConfigurationFromObject("renameTest.Foo", save = true) val runConfiguration = createConfigurationFromObject("renameTest.Foo", save = true)
@@ -167,15 +167,15 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
} }
fun testWithModuleForJdk6() { fun testWithModuleForJdk6() {
checkModuleInfoName(null, PluginTestCaseBase.mockJdk()) checkModuleInfoName(null, addJdk(testRootDisposable, ::mockJdk))
} }
fun testWithModuleForJdk9() { fun testWithModuleForJdk9() {
checkModuleInfoName("MAIN", PluginTestCaseBase.mockJdk9()) checkModuleInfoName("MAIN", addJdk(testRootDisposable, ::mockJdk9))
} }
fun testWithModuleForJdk9WithoutModuleInfo() { fun testWithModuleForJdk9WithoutModuleInfo() {
checkModuleInfoName(null, PluginTestCaseBase.mockJdk9()) checkModuleInfoName(null, addJdk(testRootDisposable, ::mockJdk9))
} }
private fun checkModuleInfoName(moduleName: String?, sdk: Sdk) { private fun checkModuleInfoName(moduleName: String?, sdk: Sdk) {
@@ -192,7 +192,7 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
val createModuleResult = configureModule(moduleDirPath("module"), baseDir) val createModuleResult = configureModule(moduleDirPath("module"), baseDir)
val srcDir = createModuleResult.srcDir val srcDir = createModuleResult.srcDir
configureRuntime(createModuleResult.module, PluginTestCaseBase.mockJdk()) configureRuntime(createModuleResult.module, addJdk(testRootDisposable, ::mockJdk))
try { try {
val expectedClasses = ArrayList<String>() val expectedClasses = ArrayList<String>()
@@ -222,7 +222,7 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
Assert.assertEquals(expectedClasses, actualClasses) Assert.assertEquals(expectedClasses, actualClasses)
} }
finally { finally {
ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(createModuleResult.module, PluginTestCaseBase.mockJdk()) ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(createModuleResult.module, mockJdk())
} }
} }
@@ -266,8 +266,8 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
private fun moduleDirPath(moduleName: String) = "${testDataPath}${getTestName(false)}/$moduleName" private fun moduleDirPath(moduleName: String) = "${testDataPath}${getTestName(false)}/$moduleName"
override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/run/" override fun getTestDataPath() = getTestDataPathBase() + "/run/"
override fun getTestProjectJdk() = PluginTestCaseBase.mockJdk() override fun getTestProjectJdk() = mockJdk()
private class CreateModuleResult( private class CreateModuleResult(
val module: Module, val module: Module,
@@ -51,7 +51,7 @@ abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() {
setTestRoot(moduleWithSrcRootSet, name) setTestRoot(moduleWithSrcRootSet, name)
} }
ConfigLibraryUtil.configureSdk(moduleWithSrcRootSet, PluginTestCaseBase.jdk(jdk)) ConfigLibraryUtil.configureSdk(moduleWithSrcRootSet, PluginTestCaseBase.addJdk(testRootDisposable) { PluginTestCaseBase.jdk(jdk) })
return moduleWithSrcRootSet return moduleWithSrcRootSet
} }
@@ -55,6 +55,8 @@ abstract class AbstractSpringClassAnnotatorTest : KotlinLightCodeInsightFixtureT
val config = JsonParser().parse(FileUtil.loadFile(configFile, true)) as JsonObject val config = JsonParser().parse(FileUtil.loadFile(configFile, true)) as JsonObject
PluginTestCaseBase.addJdk(myFixture.projectDisposable, PluginTestCaseBase::mockJdk)
val withRuntime = config["withRuntime"]?.asBoolean ?: false val withRuntime = config["withRuntime"]?.asBoolean ?: false
if (withRuntime) { if (withRuntime) {
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk()) ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())