From 3b93d897dd598a4a27f9eb7554e6def2b44714dd Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Fri, 8 May 2020 22:46:28 +0300 Subject: [PATCH] [project model] add more tests for project model classes Check editing libraries and library tables, multi-commit for several root models, concurrent modifications. GitOrigin-RevId: 7ae294c1c4a20b0b18dd1f4ee46757e5995a0ce6 --- .../intellij/roots/libraries/LibraryTest.java | 149 +--------- ...pplicationLevelLibrariesInRootModelTest.kt | 13 - .../ConcurrentRootModelModificationTest.kt | 58 ++++ ...LibrariesFromCustomTableInRootModelTest.kt | 36 --- ...riesFromLibraryTableInRootModelTestCase.kt | 65 ++++- .../openapi/roots/LibraryTableTestCase.kt | 175 ++++++++++++ .../com/intellij/openapi/roots/LibraryTest.kt | 257 ++++++++++++++++++ .../MockCustomLibraryTableDescription.kt | 19 ++ .../ModuleLevelLibrariesInRootModelTest.kt | 6 +- .../roots/MultipleModuleRootModelTest.kt | 81 ++++++ .../ProjectLevelLibrariesInRootModelTest.kt | 12 - .../roots/librariesInRootModelTests.kt | 47 ++++ .../openapi/roots/libraryTableTests.kt | 46 ++++ .../testFramework/rules/ProjectModelRule.kt | 31 ++- .../testFramework/rules/TempDirectory.kt | 9 + 15 files changed, 785 insertions(+), 219 deletions(-) delete mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/ApplicationLevelLibrariesInRootModelTest.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/ConcurrentRootModelModificationTest.kt delete mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTableTestCase.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTest.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/MockCustomLibraryTableDescription.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/MultipleModuleRootModelTest.kt delete mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/ProjectLevelLibrariesInRootModelTest.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/librariesInRootModelTests.kt create mode 100644 platform/lang-impl/testSources/com/intellij/openapi/roots/libraryTableTests.kt diff --git a/java/java-tests/testSrc/com/intellij/roots/libraries/LibraryTest.java b/java/java-tests/testSrc/com/intellij/roots/libraries/LibraryTest.java index 3d3366ff1628..d123b25233cf 100644 --- a/java/java-tests/testSrc/com/intellij/roots/libraries/LibraryTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/libraries/LibraryTest.java @@ -9,8 +9,6 @@ import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.impl.OrderEntryUtil; -import com.intellij.openapi.roots.impl.libraries.LibraryEx; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.impl.libraries.LibraryTableImplUtil; import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTableImpl; @@ -19,21 +17,20 @@ import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.roots.ModuleRootManagerTestCase; import com.intellij.testFramework.PsiTestUtil; -import com.intellij.util.CommonProcessors; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.util.Collection; import java.util.Collections; import java.util.concurrent.atomic.AtomicBoolean; @@ -66,14 +63,6 @@ public class LibraryTest extends ModuleRootManagerTestCase { assertFalse(LibraryTableImplUtil.isValidLibrary(library)); } - public void testAddRemoveModuleLibrary() { - ModuleRootModificationUtil.addModuleLibrary(myModule, getJDomJar().getUrl()); - Library library = assertOneElement(OrderEntryUtil.getModuleLibraries(ModuleRootManager.getInstance(myModule))); - assertTrue(LibraryTableImplUtil.isValidLibrary(library)); - ModuleRootModificationUtil.updateModel(myModule, model -> model.getModuleLibraryTable().removeLibrary(library)); - assertFalse(LibraryTableImplUtil.isValidLibrary(library)); - } - public void testLibrarySerialization() throws IOException { final long moduleModificationCount = ModuleRootManagerEx.getInstanceEx(myModule).getModificationCountForTests(); @@ -103,16 +92,6 @@ public class LibraryTest extends ModuleRootManagerTestCase { ); } - public void testResolveDependencyToAddedLibrary() { - final ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel(); - model.addInvalidLibrary("jdom", LibraryTablesRegistrar.PROJECT_LEVEL); - commit(model); - assertEmpty(getLibraries()); - - Library library = createLibrary("jdom", getJDomJar(), null); - assertSameElements(getLibraries(), library); - } - public void testFindLibraryByNameAfterRename() { LibraryTable table = getProjectLibraryTable(); @@ -187,94 +166,6 @@ public class LibraryTest extends ModuleRootManagerTestCase { assertEquals("a", assertOneElement(getProjectLibraryTable().getLibraries()).getName()); } - public void testNonCommittedLibraryIsDisposed() { - LibraryTable table = getProjectLibraryTable(); - LibraryTable.ModifiableModel model = table.getModifiableModel(); - Library library = model.createLibrary("a"); - model.removeLibrary(library); - commit(model); - assertEmpty(table.getLibraries()); - } - - public void testMergeAddRemoveChanges() { - Library a = createLibrary("a", null, null); - LibraryTable table = getProjectLibraryTable(); - - LibraryTable.ModifiableModel model1 = table.getModifiableModel(); - model1.removeLibrary(a); - - LibraryTable.ModifiableModel model2 = table.getModifiableModel(); - model2.createLibrary("b"); - commit(model1); - commit(model2); - - assertAllLibrariesAreNotDisposed(); - assertEquals("b", assertOneElement(table.getLibraries()).getName()); - } - - public void testMergeAddAddChanges() { - createLibrary("a", null, null); - LibraryTable table = getProjectLibraryTable(); - - LibraryTable.ModifiableModel model1 = table.getModifiableModel(); - model1.createLibrary("b"); - - LibraryTable.ModifiableModel model2 = table.getModifiableModel(); - model2.createLibrary("c"); - commit(model1); - commit(model2); - - assertAllLibrariesAreNotDisposed(); - assertSameElements(ContainerUtil.map(table.getLibraries(), Library::getName), "a", "b", "c"); - } - - public void testMergeRemoveRemoveChanges() { - Library a = createLibrary("a", null, null); - Library b = createLibrary("b", null, null); - LibraryTable table = getProjectLibraryTable(); - - LibraryTable.ModifiableModel model1 = table.getModifiableModel(); - model1.removeLibrary(a); - - LibraryTable.ModifiableModel model2 = table.getModifiableModel(); - model2.removeLibrary(b); - commit(model1); - commit(model2); - - assertAllLibrariesAreNotDisposed(); - assertEmpty(table.getLibraries()); - } - - private void assertAllLibrariesAreNotDisposed() { - for (Library library : getProjectLibraryTable().getLibraries()) { - assertEmpty(library.getUrls(OrderRootType.CLASSES)); - } - } - - public void testResolveDependencyToRenamedLibrary() { - Library library = createLibrary("jdom2", getJDomJar(), null); - - final ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel(); - model.addInvalidLibrary("jdom", LibraryTablesRegistrar.PROJECT_LEVEL); - commit(model); - assertEmpty(getLibraries()); - - Library.ModifiableModel libModel = library.getModifiableModel(); - libModel.setName("jdom"); - commit(libModel); - assertSameElements(getLibraries(), library); - } - - private Collection getLibraries() { - CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor<>(); - ModuleRootManager.getInstance(myModule).orderEntries().forEachLibrary(processor); - return processor.getResults(); - } - - private static void commit(final ModifiableRootModel model) { - WriteAction.runAndWait(() -> model.commit()); - } - public void testNativePathSerialization() { LibraryTable table = getProjectLibraryTable(); Library library = WriteAction.compute(() -> table.createLibrary("native")); @@ -452,40 +343,6 @@ public class LibraryTest extends ModuleRootManagerTestCase { assertTrue(rootsChanged.get()); } - public void testAddRemoveExcludedRoot() { - VirtualFile jar = getJDomJar(); - LibraryEx library = (LibraryEx)createLibrary("junit", jar, null); - assertEmpty(library.getExcludedRoots()); - - LibraryEx.ModifiableModelEx model = library.getModifiableModel(); - model.addExcludedRoot(jar.getUrl()); - commit(model); - assertOrderedEquals(library.getExcludedRoots(), jar); - - LibraryEx.ModifiableModelEx model2 = library.getModifiableModel(); - model2.removeExcludedRoot(jar.getUrl()); - commit(model2); - assertEmpty(library.getExcludedRoots()); - } - - public void testRemoveExcludedRootWhenParentRootIsRemoved() { - VirtualFile jar = getJDomJar(); - LibraryEx library = (LibraryEx)createLibrary("junit", jar, null); - - LibraryEx.ModifiableModelEx model = library.getModifiableModel(); - VirtualFile excluded = jar.findChild("org"); - assertNotNull(excluded); - model.addExcludedRoot(excluded.getUrl()); - commit(model); - - assertOrderedEquals(library.getExcludedRoots(), excluded); - LibraryEx.ModifiableModelEx model2 = library.getModifiableModel(); - model2.removeRoot(jar.getUrl(), OrderRootType.CLASSES); - commit(model2); - - assertEmpty(library.getExcludedRoots()); - } - private static void commit(final Library.ModifiableModel modifiableModel) { ApplicationManager.getApplication().runWriteAction(modifiableModel::commit); } diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ApplicationLevelLibrariesInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ApplicationLevelLibrariesInRootModelTest.kt deleted file mode 100644 index b40d89195582..000000000000 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/ApplicationLevelLibrariesInRootModelTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -// 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.roots.libraries.Library -import com.intellij.openapi.roots.libraries.LibraryTable -import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar - -class ApplicationLevelLibrariesInRootModelTest : LibrariesFromLibraryTableInRootModelTestCase() { - override val libraryTable: LibraryTable - get() = LibraryTablesRegistrar.getInstance().libraryTable - - override fun createLibrary(name: String): Library = projectModel.addApplicationLevelLibrary(name) -} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ConcurrentRootModelModificationTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ConcurrentRootModelModificationTest.kt new file mode 100644 index 000000000000..34df005b779e --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/ConcurrentRootModelModificationTest.kt @@ -0,0 +1,58 @@ +// 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.module.Module +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.rules.ProjectModelRule +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test + +class ConcurrentRootModelModificationTest { + companion object { + @JvmField + @ClassRule + val appRule = ApplicationRule() + } + + @Rule + @JvmField + val projectModel = ProjectModelRule() + + lateinit var module: Module + + @Before + fun setUp() { + module = projectModel.createModule() + } + + @Test + fun `commit one model and dispose another`() { + val foo = projectModel.addProjectLevelLibrary("foo") + val bar = projectModel.addProjectLevelLibrary("bar") + val model1 = createModifiableModel(module) + val model2 = createModifiableModel(module) + model1.addLibraryEntry(foo) + model2.addLibraryEntry(bar) + commitModifiableRootModel(model1) + model2.dispose() + val libraryEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(foo) + } + + @Test + fun `last committed model wins`() { + val foo = projectModel.addProjectLevelLibrary("foo") + val bar = projectModel.addProjectLevelLibrary("bar") + val model1 = createModifiableModel(module) + model1.addLibraryEntry(foo) + val model2 = createModifiableModel(module) + model2.addLibraryEntry(bar) + commitModifiableRootModel(model1) + commitModifiableRootModel(model2) + val libraryEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(bar) + } +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt deleted file mode 100644 index eb22860ba182..000000000000 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromCustomTableInRootModelTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -// 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 dfd3c754b7aa..e9516af94f80 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibrariesFromLibraryTableInRootModelTestCase.kt @@ -35,6 +35,7 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { protected abstract fun createLibrary(name: String): Library protected abstract val libraryTable: LibraryTable + protected open fun createLibrary(name: String, model: LibraryTable.ModifiableModel) = model.createLibrary(name) as LibraryEx @Test fun `add edit remove library`() { @@ -219,6 +220,64 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { } } + @Test + fun `rename library`() { + val a = createLibrary("a") + ModuleRootModificationUtil.addDependency(module, a) + projectModel.renameLibrary(a, "b") + val libraryEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(a) + assertThat(libraryEntry.libraryName).isEqualTo("b") + } + + @Test + fun `rename library and commit after committing root model`() { + val a = createLibrary("a") + val model = createModifiableModel(module) + model.addLibraryEntry(a) + val libModel = a.modifiableModel + libModel.name = "b" + val libraryEntry = dropModuleSourceEntry(model, 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(a) + assertThat(libraryEntry.libraryName).isEqualTo("a") + val committed = commitModifiableRootModel(model) + val committedEntry1 = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry1.library).isEqualTo(a) + assertThat(committedEntry1.libraryName).isEqualTo("a") + runWriteActionAndWait { libModel.commit() } + val committedEntry2 = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry2.library).isEqualTo(a) + assertThat(committedEntry2.libraryName).isEqualTo("b") + } + + @Test + fun `rename library before committing root model`() { + val a = createLibrary("a") + val model = createModifiableModel(module) + model.addLibraryEntry(a) + projectModel.renameLibrary(a, "b") + val libraryEntry = dropModuleSourceEntry(model, 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(a) + assertThat(libraryEntry.libraryName).isEqualTo("b") + val committed = commitModifiableRootModel(model) + val committedEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(committedEntry.library).isEqualTo(a) + assertThat(committedEntry.libraryName).isEqualTo("b") + } + + @Test + fun `add invalid library and rename library to that name`() { + val library = createLibrary("foo") + val model = createModifiableModel(module) + model.addInvalidLibrary("bar", libraryTable.tableLevel) + commitModifiableRootModel(model) + + projectModel.renameLibrary(library, "bar") + + val libraryEntry = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(library) + } + @Test fun `dispose model without committing`() { val a = createLibrary("a") @@ -232,7 +291,7 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { @Test fun `add not yet committed library and commit root model`() { val libraryTableModel = libraryTable.modifiableModel - val a = libraryTableModel.createLibrary("a") + val a = createLibrary("a", libraryTableModel) run { val model = createModifiableModel(module) val entry = model.addLibraryEntry(a) @@ -253,7 +312,7 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { @Test fun `add not yet committed library and commit before committing root model`() { val libraryTableModel = libraryTable.modifiableModel - val a = libraryTableModel.createLibrary("a") + val a = createLibrary("a", libraryTableModel) val model = createModifiableModel(module) val entry = model.addLibraryEntry(a) assertThat(entry.library).isEqualTo(a) @@ -268,7 +327,7 @@ abstract class LibrariesFromLibraryTableInRootModelTestCase { @Test fun `add not yet committed library with configuration accessor`() { val libraryTableModel = libraryTable.modifiableModel - val a = libraryTableModel.createLibrary("a") + val a = createLibrary("a", libraryTableModel) run { val model = createModifiableModel(module, object : RootConfigurationAccessor() { override fun getLibrary(library: Library?, libraryName: String?, libraryLevel: String?): Library? { diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTableTestCase.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTableTestCase.kt new file mode 100644 index 000000000000..856846597d9f --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTableTestCase.kt @@ -0,0 +1,175 @@ +// 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.runWriteActionAndWait +import com.intellij.openapi.roots.impl.libraries.LibraryEx +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.roots.libraries.LibraryTable +import com.intellij.openapi.util.Disposer +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.DisposableRule +import com.intellij.testFramework.rules.ProjectModelRule +import org.assertj.core.api.Assertions.assertThat +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test + +abstract class LibraryTableTestCase { + companion object { + @JvmField + @ClassRule + val appRule = ApplicationRule() + } + + @Rule + @JvmField + val projectModel = ProjectModelRule() + + @Rule + @JvmField + val disposableRule = DisposableRule() + + protected abstract val libraryTable: LibraryTable + protected abstract fun createLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit = {}): LibraryEx + protected open fun createLibrary(name: String, model: LibraryTable.ModifiableModel) = model.createLibrary(name) as LibraryEx + + @Test + fun `add remove library`() { + assertThat(libraryTable.libraries).isEmpty() + val library = createLibrary("a") + checkConsistency() + assertThat(libraryTable.libraries).containsExactly(library) + assertThat(library.isDisposed).isFalse() + runWriteActionAndWait { libraryTable.removeLibrary(library) } + checkConsistency() + assertThat(libraryTable.libraries).isEmpty() + assertThat(library.isDisposed).isTrue() + } + + @Test + fun listener() { + val events = ArrayList() + libraryTable.addListener(object : LibraryTable.Listener { + override fun afterLibraryAdded(newLibrary: Library) { + events += "added ${newLibrary.name}" + } + + override fun afterLibraryRenamed(library: Library) { + events += "renamed ${library.name}" + } + + override fun beforeLibraryRemoved(library: Library) { + events += "before removed ${library.name}" + } + + override fun afterLibraryRemoved(library: Library) { + events += "removed ${library.name}" + } + }) + val library = createLibrary("a") + assertThat(events).containsExactly("added a") + events.clear() + projectModel.renameLibrary(library, "b") + assertThat(events).containsExactly("renamed b") + events.clear() + runWriteActionAndWait { libraryTable.removeLibrary(library) } + assertThat(events).containsExactly("before removed b", "removed b") + } + + @Test + fun `remove library before committing`() { + val library = edit { + val library = createLibrary("a", it) + assertThat(it.isChanged).isTrue() + it.removeLibrary(library) + assertThat(it.isChanged).isFalse() + library + } + assertThat(libraryTable.libraries).isEmpty() + assertThat(library.isDisposed).isTrue() + } + + @Test + fun `dispose model`() { + val model = libraryTable.modifiableModel + val library = createLibrary("a", model) + Disposer.dispose(model) + assertThat(libraryTable.libraries).isEmpty() + assertThat(library.isDisposed).isTrue() + } + + @Test + fun `merge add remove changes`() { + val a = createLibrary("a") + val model1 = libraryTable.modifiableModel + model1.removeLibrary(a) + val model2 = libraryTable.modifiableModel + val b = createLibrary("b", model2) + runWriteActionAndWait { + model1.commit() + model2.commit() + } + assertThat(libraryTable.libraries).containsExactly(b) + } + + @Test + fun `merge add add changes`() { + val a = createLibrary("a") + val model1 = libraryTable.modifiableModel + val b = createLibrary("b", model1) + val model2 = libraryTable.modifiableModel + val c = createLibrary("c", model2) + runWriteActionAndWait { + model1.commit() + model2.commit() + } + assertThat(libraryTable.libraries).containsExactly(a, b, c) + } + + @Test + fun `merge remove remove changes`() { + val a = createLibrary("a") + val b = createLibrary("b") + val model1 = libraryTable.modifiableModel + model1.removeLibrary(a) + val model2 = libraryTable.modifiableModel + model2.removeLibrary(b) + runWriteActionAndWait { + model1.commit() + model2.commit() + } + assertThat(libraryTable.libraries).isEmpty() + } + + + private fun edit(action: (LibraryTable.ModifiableModel) -> T): T{ + checkConsistency() + val model = libraryTable.modifiableModel + checkConsistency(model) + val result = action(model) + checkConsistency(model) + runWriteActionAndWait { model.commit() } + checkConsistency() + return result + } + + private fun checkConsistency() { + val fromIterator = ArrayList() + libraryTable.libraryIterator.forEach { fromIterator += it } + assertThat(fromIterator).containsExactly(*libraryTable.libraries) + for (library in libraryTable.libraries) { + assertThat(libraryTable.getLibraryByName(library.name!!)).isEqualTo(library) + assertThat((library as LibraryEx).isDisposed).isFalse() + } + } + + private fun checkConsistency(model: LibraryTable.ModifiableModel) { + val fromIterator = ArrayList() + model.libraryIterator.forEach { fromIterator += it } + assertThat(fromIterator).containsExactly(*model.libraries) + for (library in model.libraries) { + assertThat(model.getLibraryByName(library.name!!)).isEqualTo(library) + assertThat((library as LibraryEx).isDisposed).isFalse() + } + } +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTest.kt new file mode 100644 index 000000000000..9696cfc8a65f --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/LibraryTest.kt @@ -0,0 +1,257 @@ +// 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.runWriteActionAndWait +import com.intellij.openapi.roots.impl.libraries.LibraryEx +import com.intellij.openapi.vfs.JarFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.rules.ProjectModelRule +import org.assertj.core.api.Assertions.assertThat +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test + +class LibraryTest { + companion object { + @JvmField + @ClassRule + val appRule = ApplicationRule() + } + + @Rule + @JvmField + val projectModel = ProjectModelRule() + + @Test + fun `empty library`() { + val library = projectModel.addProjectLevelLibrary("a") + assertThat(library.name).isEqualTo("a") + assertThat(library.getUrls(OrderRootType.CLASSES)).isEmpty() + assertThat(library.table).isEqualTo(projectModel.projectLibraryTable) + assertThat(library.excludedRoots).isEmpty() + assertThat(library.getInvalidRootUrls(OrderRootType.CLASSES)).isEmpty() + assertThat(library.source).isNull() + assertThat(library.module).isNull() + checkConsistency(library) + } + + @Test + fun `add remove roots`() { + val classesRoot = projectModel.baseProjectDir.newVirtualDirectory("classes") + val sourceRoot = projectModel.baseProjectDir.newVirtualDirectory("src") + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(classesRoot, OrderRootType.CLASSES) + } + checkConsistency(library) + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + assertThat(library.getFiles(OrderRootType.SOURCES)).isEmpty() + assertThat(library.isValid(classesRoot.url, OrderRootType.CLASSES)).isTrue() + edit(library) { + assertThat(it.isChanged).isFalse() + it.addRoot(sourceRoot, OrderRootType.SOURCES) + assertThat(it.isChanged).isTrue() + assertThat(it.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + assertThat(it.getFiles(OrderRootType.SOURCES)).containsExactly(sourceRoot) + assertThat(library.getFiles(OrderRootType.SOURCES)).isEmpty() + } + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + assertThat(library.getFiles(OrderRootType.SOURCES)).containsExactly(sourceRoot) + edit(library) { + it.removeRoot(sourceRoot.url, OrderRootType.CLASSES) + assertThat(it.isChanged).isFalse() + it.removeRoot(classesRoot.url, OrderRootType.CLASSES) + assertThat(it.isChanged).isTrue() + assertThat(it.getFiles(OrderRootType.CLASSES)).isEmpty() + assertThat(it.getFiles(OrderRootType.SOURCES)).containsExactly(sourceRoot) + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + } + assertThat(library.getFiles(OrderRootType.CLASSES)).isEmpty() + assertThat(library.getFiles(OrderRootType.SOURCES)).containsExactly(sourceRoot) + } + + @Test + fun `add remove invalid root`() { + val classesRootDir = projectModel.baseProjectDir.newVirtualDirectory("lib") + val classesUrl = "${classesRootDir.url}/classes" + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(classesUrl, OrderRootType.CLASSES) + assertThat(it.getUrls(OrderRootType.CLASSES)).containsExactly(classesUrl) + assertThat(it.getFiles(OrderRootType.CLASSES)).isEmpty() + } + checkConsistency(library) + assertThat(library.getFiles(OrderRootType.CLASSES)).isEmpty() + assertThat(library.getUrls(OrderRootType.CLASSES)).containsExactly(classesUrl) + assertThat(library.isValid(classesUrl, OrderRootType.CLASSES)).isFalse() + assertThat(library.getInvalidRootUrls(OrderRootType.CLASSES)).containsExactly(classesUrl) + edit(library) { + it.removeRoot(classesUrl, OrderRootType.SOURCES) + assertThat(it.isChanged).isFalse() + it.removeRoot(classesUrl, OrderRootType.CLASSES) + assertThat(it.isChanged).isTrue() + } + assertThat(library.getUrls(OrderRootType.CLASSES)).isEmpty() + assertThat(library.getInvalidRootUrls(OrderRootType.CLASSES)).isEmpty() + assertThat(library.isValid(classesUrl, OrderRootType.CLASSES)).isFalse() + } + + @Test + fun `add invalid root and make it valid`() { + val classesRootDir = projectModel.baseProjectDir.newVirtualDirectory("lib") + val classesUrl = "${classesRootDir.url}/classes" + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(classesUrl, OrderRootType.CLASSES) + } + checkConsistency(library) + assertThat(library.isValid(classesUrl, OrderRootType.CLASSES)).isFalse() + assertThat(library.getInvalidRootUrls(OrderRootType.CLASSES)).containsExactly(classesUrl) + val classesRoot = projectModel.baseProjectDir.newVirtualDirectory("lib/classes") + assertThat(library.getUrls(OrderRootType.CLASSES)).containsExactly(classesUrl) + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + assertThat(library.getInvalidRootUrls(OrderRootType.CLASSES)).isEmpty() + assertThat(library.isValid(classesUrl, OrderRootType.CLASSES)).isTrue() + } + + @Test + fun `add remove jar directory`() { + val jarDir = projectModel.baseProjectDir.newVirtualDirectory("jarDir") + val jarDirSrc = projectModel.baseProjectDir.newVirtualDirectory("jarDirSrc") + val jarDirRec = projectModel.baseProjectDir.newVirtualDirectory("jarDirRec") + val jarDirSrcRec = projectModel.baseProjectDir.newVirtualDirectory("jarDirSrcRec") + val library = projectModel.addProjectLevelLibrary("a") { + it.addJarDirectory(jarDir, false) + it.addJarDirectory(jarDirRec, true) + it.addJarDirectory(jarDirSrc.url, false, OrderRootType.SOURCES) + it.addJarDirectory(jarDirSrcRec.url, true, OrderRootType.SOURCES) + assertThat(it.isJarDirectory(jarDir.url)).isTrue() + assertThat(it.isJarDirectory(jarDirSrc.url)).isFalse() + assertThat(it.isJarDirectory(jarDirSrc.url, OrderRootType.SOURCES)).isTrue() + assertThat(it.isJarDirectory(jarDirRec.url)).isTrue() + assertThat(it.isJarDirectory(jarDirSrcRec.url, OrderRootType.SOURCES)).isTrue() + assertThat(it.getFiles(OrderRootType.CLASSES)).isEmpty() + assertThat(it.getUrls(OrderRootType.CLASSES)).containsExactly(jarDir.url, jarDirRec.url) + } + checkConsistency(library) + assertThat(library.getUrls(OrderRootType.CLASSES)).containsExactly(jarDir.url, jarDirRec.url) + assertThat(library.isJarDirectory(jarDir.url)).isTrue() + assertThat(library.isJarDirectory(jarDirSrc.url)).isFalse() + assertThat(library.isJarDirectory(jarDirSrc.url, OrderRootType.SOURCES)).isTrue() + assertThat(library.isJarDirectory(jarDirRec.url)).isTrue() + assertThat(library.isJarDirectory(jarDirSrcRec.url, OrderRootType.SOURCES)).isTrue() + assertThat(library.getFiles(OrderRootType.CLASSES)).isEmpty() + + fun VirtualFile.toJarRoot() = JarFileSystem.getInstance().getJarRootForLocalFile(this) + val classesRoot = projectModel.baseProjectDir.newVirtualFile("jarDir/a.jar").toJarRoot() + projectModel.baseProjectDir.newVirtualFile("jarDir/subDir/b.jar") + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot) + val classesRootRec1 = projectModel.baseProjectDir.newVirtualFile("jarDirRec/a.jar").toJarRoot() + val classesRootRec2 = projectModel.baseProjectDir.newVirtualFile("jarDirRec/subDir/a.jar").toJarRoot() + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(classesRoot, classesRootRec1, classesRootRec2) + checkConsistency(library) + + edit(library) { + it.removeRoot(jarDir.url, OrderRootType.CLASSES) + it.removeRoot(jarDirRec.url, OrderRootType.CLASSES) + assertThat(it.isChanged) + } + assertThat(library.getUrls(OrderRootType.CLASSES)).isEmpty() + } + + @Test + fun `add remove excluded root`() { + val classesRoot = projectModel.baseProjectDir.newVirtualDirectory("classes") + val excludedRoot = projectModel.baseProjectDir.newVirtualDirectory("classes/exc") + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(classesRoot, OrderRootType.CLASSES) + it.addExcludedRoot(excludedRoot.url) + assertThat(it.excludedRootUrls).containsExactly(excludedRoot.url) + } + assertThat(library.excludedRoots).containsExactly(excludedRoot) + + edit(library) { + it.removeExcludedRoot(excludedRoot.url) + assertThat(it.isChanged) + } + assertThat(library.excludedRoots).isEmpty() + } + + @Test + fun `remove excluded root when parent is removed`() { + val classesRoot = projectModel.baseProjectDir.newVirtualDirectory("classes") + val excludedRoot = projectModel.baseProjectDir.newVirtualDirectory("classes/exc") + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(classesRoot, OrderRootType.CLASSES) + it.addExcludedRoot(excludedRoot.url) + } + assertThat(library.excludedRoots).containsExactly(excludedRoot) + + edit(library) { + it.removeRoot(classesRoot.url, OrderRootType.CLASSES) + } + assertThat(library.excludedRoots).isEmpty() + } + + @Test + fun rename() { + val library = projectModel.addProjectLevelLibrary("a") + edit(library) { + it.name = "b" + assertThat(it.isChanged).isTrue() + assertThat(it.name).isEqualTo("b") + } + assertThat(library.name).isEqualTo("b") + } + + @Test + fun `move roots up and down`() { + val root1 = projectModel.baseProjectDir.newVirtualDirectory("root1") + val src = projectModel.baseProjectDir.newVirtualDirectory("src") + val root2 = projectModel.baseProjectDir.newVirtualDirectory("root2") + val library = projectModel.addProjectLevelLibrary("a") { + it.addRoot(root1, OrderRootType.CLASSES) + it.addRoot(src, OrderRootType.SOURCES) + it.addRoot(root2, OrderRootType.CLASSES) + assertThat(it.getFiles(OrderRootType.CLASSES)).containsExactly(root1, root2) + it.moveRootDown(root1.url, OrderRootType.CLASSES) + assertThat(it.getFiles(OrderRootType.CLASSES)).containsExactly(root2, root1) + } + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(root2, root1) + + edit(library) { + it.moveRootUp(root2.url, OrderRootType.CLASSES) + assertThat(it.isChanged).isFalse() + assertThat(it.getFiles(OrderRootType.CLASSES)).containsExactly(root2, root1) + it.moveRootUp(root1.url, OrderRootType.CLASSES) + assertThat(it.isChanged).isTrue() + assertThat(it.getFiles(OrderRootType.CLASSES)).containsExactly(root1, root2) + } + + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(root1, root2) + } + + private fun checkConsistency(library: LibraryEx) { + assertThat(library.rootProvider.getFiles(OrderRootType.CLASSES)).containsExactly(*library.getFiles(OrderRootType.CLASSES)) + assertThat(library.rootProvider.getFiles(OrderRootType.SOURCES)).containsExactly(*library.getFiles(OrderRootType.SOURCES)) + assertThat(library.rootProvider.getUrls(OrderRootType.CLASSES)).containsExactly(*library.getUrls(OrderRootType.CLASSES)) + assertThat(library.rootProvider.getUrls(OrderRootType.SOURCES)).containsExactly(*library.getUrls(OrderRootType.SOURCES)) + if (library.getUrls(OrderRootType.CLASSES).none { library.isJarDirectory(it) }) { + val classesRoots = library.getUrls(OrderRootType.CLASSES).mapNotNull { VirtualFileManager.getInstance().findFileByUrl(it) } + assertThat(library.getFiles(OrderRootType.CLASSES)).containsExactly(*classesRoots.toTypedArray()) + } + if (library.getUrls(OrderRootType.SOURCES).none { library.isJarDirectory(it, OrderRootType.SOURCES) }) { + val sourcesRoots = library.getUrls(OrderRootType.SOURCES).mapNotNull { VirtualFileManager.getInstance().findFileByUrl(it) } + assertThat(library.getFiles(OrderRootType.SOURCES)).containsExactly(*sourcesRoots.toTypedArray()) + } + val excludedRoots = library.excludedRootUrls.mapNotNull { VirtualFileManager.getInstance().findFileByUrl(it) } + assertThat(library.excludedRoots).containsExactly(*excludedRoots.toTypedArray()) + } + + private inline fun edit(library: LibraryEx, action: (LibraryEx.ModifiableModelEx) -> Unit) { + checkConsistency(library) + val model = library.modifiableModel + action(model) + runWriteActionAndWait { model.commit() } + checkConsistency(library) + } +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/MockCustomLibraryTableDescription.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/MockCustomLibraryTableDescription.kt new file mode 100644 index 000000000000..fc8c51ca964d --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/MockCustomLibraryTableDescription.kt @@ -0,0 +1,19 @@ +// 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.roots.libraries.CustomLibraryTableDescription +import com.intellij.openapi.roots.libraries.LibraryTablePresentation + +class MockCustomLibraryTableDescription : 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" + } +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleLevelLibrariesInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleLevelLibrariesInRootModelTest.kt index b95570738453..79e1d588294b 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleLevelLibrariesInRootModelTest.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleLevelLibrariesInRootModelTest.kt @@ -37,7 +37,7 @@ class ModuleLevelLibrariesInRootModelTest { fun `add edit remove unnamed module library`() { run { val model = createModifiableModel(module) - val library = model.moduleLibraryTable.createLibrary() + val library = model.moduleLibraryTable.createLibrary() as LibraryEx assertThat(model.moduleLibraryTable.libraries.single()).isEqualTo(library) val libraryEntry = dropModuleSourceEntry(model, 1).single() as LibraryOrderEntry assertThat(libraryEntry.isModuleLevel).isTrue() @@ -47,7 +47,8 @@ class ModuleLevelLibrariesInRootModelTest { assertThat(libraryEntry.isExported).isFalse() assertThat(libraryEntry.libraryLevel).isEqualTo(LibraryTableImplUtil.MODULE_LEVEL) assertThat(model.findLibraryOrderEntry(library)).isEqualTo(libraryEntry) - assertThat((library as LibraryEx).isDisposed).isFalse() + assertThat(library.isDisposed).isFalse() + assertThat(library.module).isEqualTo(module) val committed = commitModifiableRootModel(model) val committedEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry @@ -58,6 +59,7 @@ class ModuleLevelLibrariesInRootModelTest { assertThat(committedEntry.library).isEqualTo(library) assertThat(committedEntry.libraryLevel).isEqualTo(LibraryTableImplUtil.MODULE_LEVEL) assertThat(library.isDisposed).isTrue() + assertThat((committedEntry.library as LibraryEx).module).isEqualTo(module) assertThat((committedEntry.library as LibraryEx).isDisposed).isFalse() } diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/MultipleModuleRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/MultipleModuleRootModelTest.kt new file mode 100644 index 000000000000..f9813579dedd --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/MultipleModuleRootModelTest.kt @@ -0,0 +1,81 @@ +// 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.roots.impl.ModifiableModelCommitter +import com.intellij.testFramework.ApplicationRule +import com.intellij.testFramework.rules.ProjectModelRule +import org.assertj.core.api.Assertions.assertThat +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test + +class MultipleModuleRootModelTest { + companion object { + @JvmField + @ClassRule + val appRule = ApplicationRule() + } + + @Rule + @JvmField + val projectModel = ProjectModelRule() + + @Test + fun `commit root model before committing module`() { + val library = projectModel.addProjectLevelLibrary("lib") + val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val module = projectModel.createModule("a", moduleModel) + val model = createModifiableModel(module) + model.addLibraryEntry(library) + val committed = commitModifiableRootModel(model) + val libraryEntry = dropModuleSourceEntry(committed, 1).single() as LibraryOrderEntry + assertThat(libraryEntry.library).isEqualTo(library) + runWriteActionAndWait { moduleModel.commit() } + val libraryEntryForCommitted = dropModuleSourceEntry(ModuleRootManager.getInstance(module), 1).single() as LibraryOrderEntry + assertThat(libraryEntryForCommitted.library).isEqualTo(library) + } + + @Test + fun `commit root model and dispose module`() { + val library = projectModel.addProjectLevelLibrary("lib") + val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val module = projectModel.createModule("a", moduleModel) + val model = createModifiableModel(module) + model.addLibraryEntry(library) + commitModifiableRootModel(model) + runWriteActionAndWait { moduleModel.dispose() } + assertThat(projectModel.moduleManager.modules).isEmpty() + } + + @Test + fun `create two modules with dependency between them`() { + val moduleManager = projectModel.moduleManager + val moduleModel = runReadAction { moduleManager.modifiableModel } + val a = projectModel.createModule("a", moduleModel) + val b = projectModel.createModule("b", moduleModel) + val model = createModifiableModel(a) + model.addModuleOrderEntry(b) + runWriteActionAndWait { ModifiableModelCommitter.multiCommit(listOf(model), moduleModel) } + assertThat(moduleManager.findModuleByName("a")).isEqualTo(a) + assertThat(ModuleRootManager.getInstance(a).dependencies.single()).isEqualTo(b) + } + + @Test + fun `create two modules with circular dependency between them`() { + val moduleManager = projectModel.moduleManager + val moduleModel = runReadAction { moduleManager.modifiableModel } + val a = projectModel.createModule("a", moduleModel) + val b = projectModel.createModule("b", moduleModel) + val modelA = createModifiableModel(a) + modelA.addModuleOrderEntry(b) + val modelB = createModifiableModel(b) + modelB.addModuleOrderEntry(a) + runWriteActionAndWait { ModifiableModelCommitter.multiCommit(listOf(modelA, modelB), moduleModel) } + assertThat(moduleManager.findModuleByName("a")).isEqualTo(a) + assertThat(moduleManager.findModuleByName("b")).isEqualTo(b) + assertThat(ModuleRootManager.getInstance(a).dependencies.single()).isEqualTo(b) + assertThat(ModuleRootManager.getInstance(b).dependencies.single()).isEqualTo(a) + } +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ProjectLevelLibrariesInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ProjectLevelLibrariesInRootModelTest.kt deleted file mode 100644 index 34128b5cd0fe..000000000000 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/ProjectLevelLibrariesInRootModelTest.kt +++ /dev/null @@ -1,12 +0,0 @@ -// 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.roots.libraries.Library -import com.intellij.openapi.roots.libraries.LibraryTable - -class ProjectLevelLibrariesInRootModelTest : LibrariesFromLibraryTableInRootModelTestCase() { - override val libraryTable: LibraryTable - get() = projectModel.projectLibraryTable - - override fun createLibrary(name: String): Library = projectModel.addProjectLevelLibrary(name) -} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/librariesInRootModelTests.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/librariesInRootModelTests.kt new file mode 100644 index 000000000000..61e0c4130b94 --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/librariesInRootModelTests.kt @@ -0,0 +1,47 @@ +// 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.impl.libraries.LibraryEx +import com.intellij.openapi.roots.libraries.CustomLibraryTableDescription +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.roots.libraries.LibraryTable +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar +import com.intellij.testFramework.DisposableRule +import org.junit.Before +import org.junit.Rule + +class ProjectLevelLibrariesInRootModelTest : LibrariesFromLibraryTableInRootModelTestCase() { + override val libraryTable: LibraryTable + get() = projectModel.projectLibraryTable + + override fun createLibrary(name: String): Library = projectModel.addProjectLevelLibrary(name) +} + +class ApplicationLevelLibrariesInRootModelTest : LibrariesFromLibraryTableInRootModelTestCase() { + override val libraryTable: LibraryTable + get() = LibraryTablesRegistrar.getInstance().libraryTable + + override fun createLibrary(name: String): Library = projectModel.addApplicationLevelLibrary(name) + + override fun createLibrary(name: String, model: LibraryTable.ModifiableModel): LibraryEx { + return projectModel.createLibraryAndDisposeOnTearDown(name, model) + } +} + +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( + MockCustomLibraryTableDescription(), 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/libraryTableTests.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/libraryTableTests.kt new file mode 100644 index 000000000000..5947733ca720 --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/libraryTableTests.kt @@ -0,0 +1,46 @@ +// 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.impl.libraries.LibraryEx +import com.intellij.openapi.roots.libraries.CustomLibraryTableDescription +import com.intellij.openapi.roots.libraries.LibraryTable +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar +import org.junit.Before + +class ProjectLibraryTableTest : LibraryTableTestCase() { + override val libraryTable: LibraryTable + get() = projectModel.projectLibraryTable + + override fun createLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit): LibraryEx { + return projectModel.addProjectLevelLibrary(name, setup) + } +} + +class ApplicationLibraryTableTest : LibraryTableTestCase() { + override val libraryTable: LibraryTable + get() = LibraryTablesRegistrar.getInstance().libraryTable + + override fun createLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit): LibraryEx { + return projectModel.addApplicationLevelLibrary(name, setup) + } + + override fun createLibrary(name: String, model: LibraryTable.ModifiableModel): LibraryEx { + return projectModel.createLibraryAndDisposeOnTearDown(name, model) + } +} + +class CustomLibraryTableTest : LibraryTableTestCase() { + override val libraryTable: LibraryTable + get() = LibraryTablesRegistrar.getInstance().getCustomLibraryTableByLevel("mock")!! + + @Before + fun registerCustomLibraryTable() { + ExtensionPointName.create("com.intellij.customLibraryTable").point.registerExtension( + MockCustomLibraryTableDescription(), disposableRule.disposable) + } + + override fun createLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit): LibraryEx { + return projectModel.addLibrary(name, libraryTable) + } +} diff --git a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt index e2e1577fdba5..45aff1787736 100644 --- a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt +++ b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt @@ -13,6 +13,7 @@ import com.intellij.openapi.projectRoots.SdkTypeId import com.intellij.openapi.projectRoots.SimpleJavaSdkType import com.intellij.openapi.rd.attach import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.roots.impl.libraries.LibraryEx import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.LibraryTable import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar @@ -71,13 +72,13 @@ class ProjectModelRule : TestRule { return sdk } - fun addProjectLevelLibrary(name: String, setup: (Library.ModifiableModel) -> Unit = {}): Library { + fun addProjectLevelLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit = {}): LibraryEx { return addLibrary(name, projectLibraryTable, setup) } - fun addLibrary(name: String, libraryTable: LibraryTable, setup: (Library.ModifiableModel) -> Unit = {}): Library { + fun addLibrary(name: String, libraryTable: LibraryTable, setup: (LibraryEx.ModifiableModelEx) -> Unit = {}): LibraryEx { val model = libraryTable.modifiableModel - val library = model.createLibrary(name) + val library = model.createLibrary(name) as LibraryEx val libraryModel = library.modifiableModel setup(libraryModel) runWriteActionAndWait { @@ -87,19 +88,35 @@ class ProjectModelRule : TestRule { return library } - fun addApplicationLevelLibrary(name: String): Library { + fun addApplicationLevelLibrary(name: String, setup: (LibraryEx.ModifiableModelEx) -> Unit = {}): LibraryEx { val libraryTable = LibraryTablesRegistrar.getInstance().libraryTable - val library = addLibrary(name, libraryTable) {} + val library = addLibrary(name, libraryTable, setup) + disposeOnTearDown(library) + return library + } + + private fun disposeOnTearDown(library: LibraryEx) { disposableRule.disposable.attach { runWriteActionAndWait { - if (libraryTable.getLibraryByName(name) == library) { - libraryTable.removeLibrary(library) + if (!library.isDisposed && library.table.getLibraryByName(library.name!!) == library) { + library.table.removeLibrary(library) } } } + } + + fun createLibraryAndDisposeOnTearDown(name: String, model: LibraryTable.ModifiableModel): LibraryEx { + val library = model.createLibrary(name) as LibraryEx + disposeOnTearDown(library) return library } + fun renameLibrary(library: Library, newName: String) { + val model = library.modifiableModel + model.name = newName + runWriteActionAndWait { model.commit() } + } + val sdkType: SdkTypeId get() = SimpleJavaSdkType.getInstance() diff --git a/platform/testFramework/src/com/intellij/testFramework/rules/TempDirectory.kt b/platform/testFramework/src/com/intellij/testFramework/rules/TempDirectory.kt index ed855643ee7e..db31caef9ea9 100644 --- a/platform/testFramework/src/com/intellij/testFramework/rules/TempDirectory.kt +++ b/platform/testFramework/src/com/intellij/testFramework/rules/TempDirectory.kt @@ -103,6 +103,15 @@ class TempDirectory : ExternalResource() { return VfsTestUtil.createDir(virtualFileRoot, relativePath) } + /** + * Creates a new virtual file with the given relative path from the root temp directory. Throws an exception if such a file already exists. + */ + fun newVirtualFile(relativePath: String, content: String = ""): VirtualFile { + val existing = virtualFileRoot.findFileByRelativePath(relativePath) + require(existing == null) { "Already exists: ${existing!!.path}"} + return VfsTestUtil.createFile(virtualFileRoot, relativePath, content) + } + @Deprecated("use newDirectory(relativePath) instead", ReplaceWith("newDirectory(relativePath)")) fun newFolder(relativePath: String): File { return newDirectory(relativePath)