[TestFramework] new: added the module and content root assertions util

GitOrigin-RevId: 4097714e3da5116ea6190e84c14c3113eb405bf4
This commit is contained in:
Sergei Vorobyov
2024-05-08 16:13:10 +02:00
committed by intellij-monorepo-bot
parent e3e8f50867
commit 4bfebbd18f
6 changed files with 315 additions and 37 deletions

View File

@@ -28,7 +28,6 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
@@ -41,11 +40,10 @@ import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiElement;
import com.intellij.testFramework.IndexingTestUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.utils.module.ModuleAssertions;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CommonProcessors;
import com.intellij.util.containers.ContainerUtil;
import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -56,6 +54,7 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
@@ -67,44 +66,22 @@ import static com.intellij.testFramework.EdtTestUtil.runInEdtAndWait;
* @author Vladislav.Soroka
*/
public abstract class ExternalSystemImportingTestCase extends ExternalSystemTestCase {
protected void assertModulesContains(@NotNull Project project, String... expectedNames) {
Module[] actual = ModuleManager.getInstance(project).getModules();
List<String> actualNames = new ArrayList<>();
for (Module m : actual) {
actualNames.add(m.getName());
}
assertContain(actualNames, expectedNames);
}
protected void assertModulesContains(String... expectedNames) {
assertModulesContains(myProject, expectedNames);
ModuleAssertions.assertModulesContains(myProject, expectedNames);
}
protected void assertModules(String... expectedNames) {
Module[] actualModules = ModuleManager.getInstance(myProject).getModules();
Assertions.assertThat(actualModules)
.extracting("name")
.containsExactlyInAnyOrder(expectedNames);
ModuleAssertions.assertModules(myProject, expectedNames);
}
protected void assertModules(List<String> expectedNames) {
assertModules(ArrayUtil.toStringArray(expectedNames));
ModuleAssertions.assertModules(myProject, expectedNames);
}
protected void assertContentRoots(String moduleName, String... expectedRoots) {
List<String> actual = new ArrayList<>();
for (ContentEntry e : getContentRoots(moduleName)) {
actual.add(e.getUrl());
}
for (int i = 0; i < expectedRoots.length; i++) {
expectedRoots[i] = VfsUtilCore.pathToUrl(expectedRoots[i]);
}
assertUnorderedPathsAreEqual(actual, Arrays.asList(expectedRoots));
var expectedRootPaths = ContainerUtil.map(expectedRoots, it -> Path.of(it));
ModuleAssertions.assertContentRoots(myProject, moduleName, expectedRootPaths);
}
protected void assertSources(String moduleName, String... expectedSources) {

View File

@@ -83,5 +83,6 @@
<orderEntry type="module" module-name="intellij.platform.backend.workspace" />
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
<orderEntry type="library" scope="TEST" name="assertJ" level="project" />
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
</component>
</module>

View File

@@ -0,0 +1,69 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:ApiStatus.Internal
package com.intellij.testFramework.utils.module
import org.jetbrains.annotations.ApiStatus
import org.opentest4j.AssertionFailedError
fun <T> assertEqualsUnordered(expected: Collection<T>, actual: Collection<T>) {
val expectedSet = expected.toSet()
val actualSet = actual.toSet()
val notFound = expectedSet.minus(actualSet)
val notExpected = actualSet.minus(expectedSet)
if (notExpected.isNotEmpty() && notFound.isNotEmpty()) {
val message = """|
|Expecting actual:
| $actual
|to contain exactly in any order:
| $expected
|elements not found:
| $notFound
|and elements not expected:
| $notExpected
""".trimMargin()
throw AssertionFailedError(message, expected, actual)
}
if (notFound.isNotEmpty()) {
val message = """|
|Expecting actual:
| $actual
|to contain exactly in any order:
| $expected
|but could not find the following elements:
| $notFound
""".trimMargin()
throw AssertionFailedError(message, expected, actual)
}
if (notExpected.isNotEmpty()) {
val message = """|
|Expecting actual:
| $actual
|to contain exactly in any order:
| $expected
|but the following elements were unexpected:
| $notExpected
""".trimMargin()
throw AssertionFailedError(message, expected, actual)
}
}
fun <T> assertContains(expected: Collection<T>, actual: Collection<T>) {
val expectedSet = expected.toSet()
val actualSet = actual.toSet()
val notFound = expectedSet.minus(actualSet)
if (notFound.isNotEmpty()) {
val message = """|
|Expecting actual:
| $actual
|to contain in any order:
| $expected
|but could not find the following elements:
| $notFound
""".trimMargin()
throw AssertionFailedError(message, expected, actual)
}
}

View File

@@ -1,17 +1,103 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:JvmName("ModuleAssertions")
package com.intellij.testFramework.utils.module
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.modules
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.ModuleEntity
import com.intellij.platform.workspace.jps.entities.ModuleId
import com.intellij.platform.workspace.storage.EntityStorage
import com.intellij.platform.workspace.storage.entities
import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
import org.junit.jupiter.api.Assertions
import java.nio.file.Path
fun assertModules(project: Project, vararg expectedNames: String) {
assertModules(project, expectedNames.asIterable())
assertModules(project, expectedNames.asList())
}
fun assertModules(project: Project, expectedNames: Iterable<String>) {
val actualNames = project.modules.map { it.name }
Assertions.assertEquals(expectedNames.toSet(), actualNames.toSet())
fun assertModules(project: Project, expectedNames: List<String>) {
val storage = project.workspaceModel.currentSnapshot
assertModules(storage, expectedNames)
}
fun assertModules(storage: EntityStorage, vararg expectedNames: String) {
assertModules(storage, expectedNames.asList())
}
fun assertModules(storage: EntityStorage, expectedNames: List<String>) {
val actualNames = storage.entities<ModuleEntity>().map { it.name }.toList()
assertEqualsUnordered(expectedNames, actualNames)
}
fun assertModulesContains(project: Project, vararg expectedNames: String) {
assertModulesContains(project, expectedNames.asList())
}
fun assertModulesContains(project: Project, expectedNames: List<String>) {
val storage = project.workspaceModel.currentSnapshot
assertModulesContains(storage, expectedNames)
}
fun assertModulesContains(storage: EntityStorage, vararg expectedNames: String) {
assertModulesContains(storage, expectedNames.asList())
}
fun assertModulesContains(storage: EntityStorage, expectedNames: List<String>) {
val actualNames = storage.entities<ModuleEntity>().map { it.name }.toList()
assertContains(expectedNames, actualNames)
}
fun assertContentRoots(module: Module, vararg expectedRoots: Path) {
assertContentRoots(module, expectedRoots.asList())
}
fun assertContentRoots(module: Module, expectedRoots: List<Path>) {
assertContentRoots(module.project, module.name, expectedRoots)
}
fun assertContentRoots(project: Project, moduleName: String, vararg expectedRoots: Path) {
assertContentRoots(project, moduleName, expectedRoots.asList())
}
fun assertContentRoots(project: Project, moduleName: String, expectedRoots: List<Path>) {
val workspaceModel = project.workspaceModel
val storage = workspaceModel.currentSnapshot
val virtualFileUrlManager = workspaceModel.getVirtualFileUrlManager()
assertContentRoots(virtualFileUrlManager, storage, moduleName, expectedRoots)
}
fun assertContentRoots(virtualFileUrlManager: VirtualFileUrlManager, storage: EntityStorage, moduleName: String, vararg expectedRoots: Path) {
assertContentRoots(virtualFileUrlManager, storage, moduleName, expectedRoots.asList())
}
fun assertContentRoots(virtualFileUrlManager: VirtualFileUrlManager, storage: EntityStorage, moduleName: String, expectedRoots: List<Path>) {
val moduleId = ModuleId(moduleName)
val moduleEntity = storage.resolve(moduleId)
Assertions.assertNotNull(moduleEntity) {
"The module '$moduleName' doesn't exist"
}
assertContentRoots(virtualFileUrlManager, moduleEntity!!, expectedRoots)
}
fun assertContentRoots(virtualFileUrlManager: VirtualFileUrlManager, moduleEntity: ModuleEntity, vararg expectedRoots: Path) {
assertContentRoots(virtualFileUrlManager, moduleEntity, expectedRoots.asList())
}
fun assertContentRoots(virtualFileUrlManager: VirtualFileUrlManager, moduleEntity: ModuleEntity, expectedRoots: List<Path>) {
val expectedRootUrls = expectedRoots.map { it.normalize().toVirtualFileUrl(virtualFileUrlManager) }
assertContentRoots(moduleEntity, expectedRootUrls)
}
fun assertContentRoots(moduleEntity: ModuleEntity, vararg expectedRoots: VirtualFileUrl) {
assertContentRoots(moduleEntity, expectedRoots.asList())
}
fun assertContentRoots(moduleEntity: ModuleEntity, expectedRoots: List<VirtualFileUrl>) {
val actualRoots = moduleEntity.contentRoots.map { it.url }
assertEqualsUnordered(expectedRoots, actualRoots)
}

View File

@@ -0,0 +1,85 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.testFramework.utils.module
import com.intellij.testFramework.useProjectAsync
import com.intellij.testFramework.utils.io.createDirectory
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
class ModuleAssertionTest : ModuleAssertionTestCase() {
@Test
fun `test ModuleAssertions#assertModules`() {
runBlocking {
val projectRoot = testDirectory.createDirectory("project")
val project = generateProject(projectRoot) {
addModuleEntity("project", ".")
addModuleEntity("project.module1", "module1")
addModuleEntity("project.module2", "module2")
}
project.useProjectAsync {
assertModules(project, "project", "project.module1", "project.module2")
assertModules(project, "project", "project.module2", "project.module1")
Assertions.assertThrows(AssertionError::class.java) {
assertModules(project, "project.module1", "project.module2")
}
Assertions.assertThrows(AssertionError::class.java) {
assertModules(project, "project", "module1", "module2")
}
Assertions.assertThrows(AssertionError::class.java) {
assertModules(project, "project", "other-module")
}
}
}
}
@Test
fun `test ModuleAssertions#assertModulesContains`() {
runBlocking {
val projectRoot = testDirectory.createDirectory("project")
val project = generateProject(projectRoot) {
addModuleEntity("project", ".")
addModuleEntity("project.module1", "module1")
addModuleEntity("project.module2", "module2")
}
project.useProjectAsync {
assertModulesContains(project, "project", "project.module1", "project.module2")
assertModulesContains(project, "project", "project.module2", "project.module1")
assertModulesContains(project, "project.module1", "project.module2")
Assertions.assertThrows(AssertionError::class.java) {
assertModulesContains(project, "project", "module1", "module2")
}
Assertions.assertThrows(AssertionError::class.java) {
assertModulesContains(project, "project", "other-module")
}
}
}
}
@Test
fun `test ModuleAssertions#assertContentRoots`() {
runBlocking {
val projectRoot = testDirectory.createDirectory("project")
val project = generateProject(projectRoot) {
addModuleEntity("project", ".")
addModuleEntity("project.module1", "module1")
addModuleEntity("project.module2", "module2")
}
project.useProjectAsync {
assertContentRoots(project, "project", projectRoot)
assertContentRoots(project, "project.module1", projectRoot.resolve("module1"))
assertContentRoots(project, "project.module2", projectRoot.resolve("module2"))
Assertions.assertThrows(AssertionError::class.java) {
assertContentRoots(project, "module1", projectRoot.resolve("module1"))
}
Assertions.assertThrows(AssertionError::class.java) {
assertContentRoots(project, "project", projectRoot, projectRoot.resolve("other-root"))
}
Assertions.assertThrows(AssertionError::class.java) {
assertContentRoots(project, "other-module", projectRoot.resolve("other-module"))
}
}
}
}
}

View File

@@ -0,0 +1,60 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.testFramework.utils.module
import com.intellij.ide.impl.OpenProjectTask
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.ContentRootEntity
import com.intellij.platform.workspace.jps.entities.ModuleEntity
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
import com.intellij.testFramework.closeOpenedProjectsIfFailAsync
import com.intellij.testFramework.junit5.TestApplication
import com.intellij.testFramework.withProjectAsync
import com.intellij.workspaceModel.ide.NonPersistentEntitySource
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path
import kotlin.io.path.name
@TestApplication
abstract class ModuleAssertionTestCase {
@TempDir
lateinit var testDirectory: Path
suspend fun generateProject(projectRoot: Path, configure: ProjectConfigurator.() -> Unit): Project {
val projectManager = ProjectManagerEx.getInstanceEx()
val project = closeOpenedProjectsIfFailAsync {
projectManager.newProjectAsync(projectRoot, OpenProjectTask {
isNewProject = true
runConfigurators = true
projectName = projectRoot.name
})
}
project.withProjectAsync {
val virtualFileUrlManager = project.workspaceModel.getVirtualFileUrlManager()
project.workspaceModel.update("test project initialisation") { storage ->
val projectConfigurator = ProjectConfigurator(storage, virtualFileUrlManager, projectRoot)
projectConfigurator.configure()
}
}
return project
}
class ProjectConfigurator(
private val storage: MutableEntityStorage,
private val virtualFileUrlManager: VirtualFileUrlManager,
private val projectRoot: Path
) {
fun addModuleEntity(moduleName: String, relativePath: String) {
val contentRootPath = projectRoot.resolve(relativePath).normalize()
val contentRoot = contentRootPath.toVirtualFileUrl(virtualFileUrlManager)
storage addEntity (ContentRootEntity(contentRoot, emptyList(), NonPersistentEntitySource) {
module = ModuleEntity(moduleName, emptyList(), NonPersistentEntitySource)
})
}
}
}