diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt new file mode 100644 index 000000000000..eb22860ba182 --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt @@ -0,0 +1,36 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots + +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.roots.libraries.* +import com.intellij.testFramework.DisposableRule +import org.junit.Before +import org.junit.Rule + +class LibrariesFromCustomTableInRootModelTest : LibrariesFromLibraryTableInRootModelTestCase() { + @Rule + @JvmField + val disposableRule = DisposableRule() + + override val libraryTable: LibraryTable + get() = LibraryTablesRegistrar.getInstance().getCustomLibraryTableByLevel("mock")!! + + @Before + fun registerCustomLibraryTable() { + ExtensionPointName.create("com.intellij.customLibraryTable").point.registerExtension(object : CustomLibraryTableDescription { + override fun getPresentation(): LibraryTablePresentation { + return object : LibraryTablePresentation() { + override fun getLibraryTableEditorTitle(): String = "Mock" + override fun getDescription(): String = "Mock" + override fun getDisplayName(plural: Boolean): String = "Mock" + } + } + + override fun getTableLevel(): String { + return "mock" + } + }, disposableRule.disposable) + } + + override fun createLibrary(name: String): Library = projectModel.addLibrary(name, libraryTable) +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt index be02b5cb9f74..dfd3c754b7aa 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt @@ -77,6 +77,43 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { } } + @Test + fun `edit and commit library before committing root model`() { + val library = createLibrary("foo") + val model = createModifiableModel(module) + val libraryEntry = model.addLibraryEntry(library) + assertThat(libraryEntry.library).isEqualTo(library) + val libraryModel = library.modifiableModel + val libRoot = projectModel.baseProjectDir.newVirtualDirectory("lib") + libraryModel.addRoot(libRoot, OrderRootType.CLASSES) + runWriteActionAndWait { libraryModel.commit() } + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry.library).isEqualTo(library) + assertThat(committedEntry.getFiles(OrderRootType.CLASSES).single()).isEqualTo(libRoot) + } + + @Test + fun `edit library before committing root model and commit after that`() { + val library = createLibrary("foo") + val model = createModifiableModel(module) + val libraryEntry = model.addLibraryEntry(library) + assertThat(libraryEntry.library).isEqualTo(library) + val libraryModel = library.modifiableModel + val libRoot = projectModel.baseProjectDir.newVirtualDirectory("lib") + libraryModel.addRoot(libRoot, OrderRootType.CLASSES) + + val committed = commitModifiableRootModel(model) + val committedEntry1 = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry1.getFiles(OrderRootType.CLASSES)).isEmpty() + assertThat(committedEntry1.library).isEqualTo(library) + + runWriteActionAndWait { libraryModel.commit() } + val committedEntry2 = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry2.library).isEqualTo(library) + assertThat(committedEntry2.getFiles(OrderRootType.CLASSES).single()).isEqualTo(libRoot) + } + @Test fun `add same library twice`() { val library = createLibrary("foo") @@ -177,13 +214,23 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { assertThat((model.orderEntries[2] as LibraryOrderEntry).libraryName).isEqualTo("b") model.removeOrderEntry(model.orderEntries[1]) val committed = commitModifiableRootModel(model) - val libraryEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + val libraryEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry assertThat(libraryEntry.library).isEqualTo(b) } } @Test - fun `add not yet committed library`() { + fun `dispose model without committing`() { + val a = createLibrary("a") + val model = createModifiableModel(module) + val entry = model.addLibraryEntry(a) + assertThat(entry.library).isEqualTo(a) + model.dispose() + dropModuleSourceEntry(ModuleRootManager.getInstance(module), 0) + } + + @Test + fun `add not yet committed library and commit root model`() { val libraryTableModel = libraryTable.modifiableModel val a = libraryTableModel.createLibrary("a") run { @@ -202,7 +249,22 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { assertThat(libraryEntry.library).isEqualTo(a) } } - + + @Test + fun `add not yet committed library and commit before committing root model`() { + val libraryTableModel = libraryTable.modifiableModel + val a = libraryTableModel.createLibrary("a") + val model = createModifiableModel(module) + val entry = model.addLibraryEntry(a) + assertThat(entry.library).isEqualTo(a) + assertThat(entry.libraryName).isEqualTo("a") + runWriteActionAndWait { libraryTableModel.commit() } + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry.library).isEqualTo(a) + assertThat(committedEntry.libraryName).isEqualTo("a") + } + @Test fun `add not yet committed library with configuration accessor`() { val libraryTableModel = libraryTable.modifiableModel diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt new file mode 100644 index 000000000000..b8079d0b3039 --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt @@ -0,0 +1,261 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots + +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runWriteActionAndWait +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.impl.RootConfigurationAccessor +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.assertions.Assertions.assertThat +import com.intellij.testFramework.rules.ProjectModelRule +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test + +class ModuleDependencyInRootModelTest { + companion object { + @JvmField + @ClassRule + val appRule = ApplicationRule() + } + + @Rule + @JvmField + val projectModel = ProjectModelRule() + + lateinit var mainModule: Module + + @Before + fun setUp() { + mainModule = projectModel.createModule("main") + } + + @Test + fun `add edit remove module dependency`() { + val depModule = projectModel.createModule("dep") + run { + val model = createModifiableModel(mainModule) + val entry = model.addModuleOrderEntry(depModule) + assertThat(dropModuleSourceEntry(model, 1).single() as ModuleOrderEntry).isEqualTo(entry) + assertThat(entry.scope).isEqualTo(DependencyScope.COMPILE) + assertThat(entry.isExported).isFalse() + assertThat(entry.moduleName).isEqualTo("dep") + assertThat(entry.module).isEqualTo(depModule) + assertThat(model.findModuleOrderEntry(depModule)).isEqualTo(entry) + + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(committedEntry.scope).isEqualTo(DependencyScope.COMPILE) + assertThat(committedEntry.isExported).isFalse() + assertThat(committedEntry.moduleName).isEqualTo("dep") + assertThat(committedEntry.module).isEqualTo(depModule) + } + + run { + val model = createModifiableModel(mainModule) + val entry = dropModuleSourceEntry(model, 1).single() as ModuleOrderEntry + entry.scope = DependencyScope.RUNTIME + entry.isExported = true + assertThat(model.findModuleOrderEntry(depModule)).isEqualTo(entry) + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(committedEntry.module).isEqualTo(depModule) + assertThat(committedEntry.scope).isEqualTo(DependencyScope.RUNTIME) + assertThat(committedEntry.isExported).isTrue() + } + + run { + val model = createModifiableModel(mainModule) + val entry = model.findModuleOrderEntry(depModule)!! + model.removeOrderEntry(entry) + assertThat(model.orderEntries).hasSize(1) + assertThat(model.findModuleOrderEntry(depModule)).isNull() + val committed = commitModifiableRootModel(model) + assertThat(committed.orderEntries).hasSize(1) + } + } + + @Test + fun `add same module twice`() { + val depModule = projectModel.createModule("dep") + run { + val model = createModifiableModel(mainModule) + val entry1 = model.addModuleOrderEntry(depModule) + val entry2 = model.addModuleOrderEntry(depModule) + assertThat(entry1.module).isEqualTo(depModule) + assertThat(entry2.module).isEqualTo(depModule) + assertThat(model.findModuleOrderEntry(depModule)).isEqualTo(entry1) + val committed = commitModifiableRootModel(model) + val (committedEntry1, committedEntry2) = dropModuleSourceEntry(committed, 2) + assertThat((committedEntry1 as ModuleOrderEntry).module).isEqualTo(depModule) + assertThat((committedEntry2 as ModuleOrderEntry).module).isEqualTo(depModule) + } + + run { + val model = createModifiableModel(mainModule) + (model.orderEntries[2] as ModuleOrderEntry).scope = DependencyScope.RUNTIME + model.removeOrderEntry(model.orderEntries[1]) + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(committedEntry.scope).isEqualTo(DependencyScope.RUNTIME) + assertThat(committedEntry.module).isEqualTo(depModule) + } + } + + @Test + fun `remove referenced module`() { + val depModule = projectModel.createModule("dep") + run { + val model = createModifiableModel(mainModule) + model.addModuleOrderEntry(depModule) + commitModifiableRootModel(model) + } + runWriteActionAndWait { projectModel.moduleManager.disposeModule(depModule) } + + run { + val entry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(entry.module).isNull() + assertThat(entry.moduleName).isEqualTo("dep") + } + + val newModule = projectModel.createModule("dep") + run { + val entry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(entry.module).isEqualTo(newModule) + } + } + + @Test + fun `add invalid module`() { + run { + val model = createModifiableModel(mainModule) + model.addInvalidModuleEntry("foo") + val committed = commitModifiableRootModel(model) + val entry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(entry.module).isNull() + assertThat(entry.moduleName).isEqualTo("foo") + } + + val fooModule = projectModel.createModule("foo") + run { + val entry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(entry.module).isEqualTo(fooModule) + } + } + + @Test + fun `change order`() { + val a = projectModel.createModule("a") + val b = projectModel.createModule("b") + run { + val model = createModifiableModel(mainModule) + model.addModuleOrderEntry(a) + model.addModuleOrderEntry(b) + val oldOrder = model.orderEntries + assertThat(oldOrder).hasSize(3) + assertThat((oldOrder[1] as ModuleOrderEntry).moduleName).isEqualTo("a") + assertThat((oldOrder[2] as ModuleOrderEntry).moduleName).isEqualTo("b") + val newOrder = arrayOf(oldOrder[0], oldOrder[2], oldOrder[1]) + model.rearrangeOrderEntries(newOrder) + assertThat((model.orderEntries[1] as ModuleOrderEntry).moduleName).isEqualTo("b") + assertThat((model.orderEntries[2] as ModuleOrderEntry).moduleName).isEqualTo("a") + val committed = commitModifiableRootModel(model) + assertThat((committed.orderEntries[1] as ModuleOrderEntry).moduleName).isEqualTo("b") + assertThat((committed.orderEntries[2] as ModuleOrderEntry).moduleName).isEqualTo("a") + } + + run { + val model = createModifiableModel(mainModule) + val oldOrder = model.orderEntries + assertThat((oldOrder[1] as ModuleOrderEntry).moduleName).isEqualTo("b") + assertThat((oldOrder[2] as ModuleOrderEntry).moduleName).isEqualTo("a") + val newOrder = arrayOf(oldOrder[0], oldOrder[2], oldOrder[1]) + model.rearrangeOrderEntries(newOrder) + assertThat((model.orderEntries[1] as ModuleOrderEntry).moduleName).isEqualTo("a") + assertThat((model.orderEntries[2] as ModuleOrderEntry).moduleName).isEqualTo("b") + model.removeOrderEntry(model.orderEntries[1]) + val committed = commitModifiableRootModel(model) + val entry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(entry.module).isEqualTo(b) + } + } + + @Test + fun `dispose model without committing`() { + val a = projectModel.createModule("a") + val model = createModifiableModel(mainModule) + val entry = model.addModuleOrderEntry(a) + assertThat(entry.module).isEqualTo(a) + model.dispose() + dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 0) + } + + @Test + fun `add not yet committed module`() { + val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val a = projectModel.createModule("a", moduleModel) + run { + val model = createModifiableModel(mainModule) + val entry = model.addModuleOrderEntry(a) + assertThat(entry.module).isEqualTo(a) + assertThat(entry.moduleName).isEqualTo("a") + val committed = commitModifiableRootModel(model) + val moduleEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(moduleEntry.module).isEqualTo(a) + assertThat(moduleEntry.moduleName).isEqualTo("a") + } + runWriteActionAndWait { moduleModel.commit() } + run { + val entry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(entry.module).isEqualTo(a) + } + } + + @Test + fun `add not yet committed module and do not commit it`() { + val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val a = projectModel.createModule("a", moduleModel) + run { + val model = createModifiableModel(mainModule) + val entry = model.addModuleOrderEntry(a) + assertThat(entry.module).isEqualTo(a) + assertThat(entry.moduleName).isEqualTo("a") + val committed = commitModifiableRootModel(model) + val moduleEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(moduleEntry.module).isEqualTo(a) + assertThat(moduleEntry.moduleName).isEqualTo("a") + } + runWriteActionAndWait { moduleModel.dispose() } + run { + val entry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(entry.module).isNull() + assertThat(entry.moduleName).isEqualTo("a") + } + } + + @Test + fun `add not yet committed module with configuration accessor`() { + val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val a = projectModel.createModule("a", moduleModel) + run { + val model = createModifiableModel(mainModule, object : RootConfigurationAccessor() { + override fun getModule(module: Module?, moduleName: String?): Module? { + return if (moduleName == "a") a else module + } + }) + val entry = model.addModuleOrderEntry(a) + assertThat(entry.module).isEqualTo(a) + val committed = commitModifiableRootModel(model) + val moduleEntry = dropModuleSourceEntry(committed, 1).single() as ModuleOrderEntry + assertThat(moduleEntry.module).isEqualTo(a) + assertThat(moduleEntry.moduleName).isEqualTo("a") + } + runWriteActionAndWait { moduleModel.commit() } + run { + val moduleEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(mainModule), 1).single() as ModuleOrderEntry + assertThat(moduleEntry.module).isEqualTo(a) + } + } + +} \ No newline at end of file diff --git a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt index 95b6872a5f06..e2e1577fdba5 100644 --- a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt +++ b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt @@ -3,6 +3,7 @@ package com.intellij.testFramework.rules import com.intellij.openapi.application.runWriteActionAndWait import com.intellij.openapi.module.EmptyModuleType +import com.intellij.openapi.module.ModifiableModuleModel import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.ex.ProjectManagerEx @@ -24,6 +25,7 @@ import org.junit.rules.ExternalResource import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +import java.io.File class ProjectModelRule : TestRule { val baseProjectDir = TempDirectory() @@ -46,12 +48,18 @@ class ProjectModelRule : TestRule { } fun createModule(name: String = "module"): Module { - val imlFile = baseProjectDir.newFile("$name/$name.iml") + val imlFile = File(baseProjectDir.root, "$name/$name.iml") return runWriteActionAndWait { - ModuleManager.getInstance(project).newModule(imlFile.systemIndependentPath, EmptyModuleType.EMPTY_MODULE) + moduleManager.newModule(imlFile.systemIndependentPath, EmptyModuleType.EMPTY_MODULE) } } + fun createModule(name: String, moduleModel: ModifiableModuleModel): Module { + val imlFile = baseProjectDir.newFile("$name/$name.iml") + return moduleModel.newModule(imlFile.systemIndependentPath, EmptyModuleType.EMPTY_MODULE) + } + + fun createSdk(name: String = "sdk"): Sdk { return ProjectJdkTable.getInstance().createSdk(name, sdkType) } @@ -67,7 +75,7 @@ class ProjectModelRule : TestRule { return addLibrary(name, projectLibraryTable, setup) } - private fun addLibrary(name: String, libraryTable: LibraryTable, setup: (Library.ModifiableModel) -> Unit): Library { + fun addLibrary(name: String, libraryTable: LibraryTable, setup: (Library.ModifiableModel) -> Unit = {}): Library { val model = libraryTable.modifiableModel val library = model.createLibrary(name) val libraryModel = library.modifiableModel @@ -98,6 +106,9 @@ class ProjectModelRule : TestRule { val projectRootManager: ProjectRootManager get() = ProjectRootManager.getInstance(project) + val moduleManager: ModuleManager + get() = ModuleManager.getInstance(project) + val projectLibraryTable: LibraryTable get() = LibraryTablesRegistrar.getInstance().getLibraryTable(project) }