mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-339 refactor multiverseProjectFixture
GitOrigin-RevId: 1e419998ac8352b209b10e88c73a2cf742acf67b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bf6b033b3a
commit
a15ecb51c5
Generated
+1
@@ -882,6 +882,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml" filepath="$PROJECT_DIR$/platform/testFramework/junit5/eel/intellij.platform.testFramework.junit5.eel.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/junit5/highlighting/intellij.platform.testFramework.junit5.highlighting.iml" filepath="$PROJECT_DIR$/platform/testFramework/junit5/highlighting/intellij.platform.testFramework.junit5.highlighting.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/junit5.jimfs/intellij.platform.testFramework.junit5.jimfs.iml" filepath="$PROJECT_DIR$/platform/testFramework/junit5.jimfs/intellij.platform.testFramework.junit5.jimfs.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/junit5/projectStructure/intellij.platform.testFramework.junit5.projectStructure.iml" filepath="$PROJECT_DIR$/platform/testFramework/junit5/projectStructure/intellij.platform.testFramework.junit5.projectStructure.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/teamCity/intellij.platform.testFramework.teamCity.iml" filepath="$PROJECT_DIR$/platform/testFramework/teamCity/intellij.platform.testFramework.teamCity.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/ui/intellij.platform.testFramework.ui.iml" filepath="$PROJECT_DIR$/platform/testFramework/ui/intellij.platform.testFramework.ui.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/testRunner/intellij.platform.testRunner.iml" filepath="$PROJECT_DIR$/platform/testRunner/intellij.platform.testRunner.iml" />
|
||||
|
||||
@@ -101,5 +101,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.searchEverywhere.testFramework" />
|
||||
<orderEntry type="module" module-name="intellij.java.codeserver.highlighting" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.codeserver.core" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5.projectStructure" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
+9
-7
@@ -1,24 +1,26 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInsight.codeVision
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.JavaInheritorsCodeVisionProvider
|
||||
import com.intellij.codeInsight.daemon.impl.JavaReferencesCodeVisionProvider
|
||||
import com.intellij.codeInsight.multiverse.*
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.codeInsight.multiverse.CodeInsightContext
|
||||
import com.intellij.codeInsight.multiverse.EditorContextManager
|
||||
import com.intellij.codeInsight.multiverse.ProjectModelContextBridge
|
||||
import com.intellij.codeInsight.multiverse.SingleEditorContext
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.writeAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.withSharedSourceEnabled
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.impl.file.impl.sharedSourceRootFixture
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.fixture.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.intellij.psi.impl.file.impl.withSharedSourceEnabled
|
||||
import com.intellij.psi.impl.file.impl.sharedSourceRootFixture
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
||||
|
||||
@TestApplication
|
||||
internal class JavaMultiverseCodeVisionProviderTest {
|
||||
|
||||
|
||||
@@ -59,5 +59,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5.eel" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5.projectStructure" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.module.impl.scopes
|
||||
|
||||
import com.intellij.codeInsight.multiverse.CodeInsightContext
|
||||
@@ -6,9 +6,9 @@ import com.intellij.codeInsight.multiverse.anyContext
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.withSharedSourceEnabled
|
||||
import com.intellij.psi.impl.file.impl.moduleContext
|
||||
import com.intellij.psi.impl.file.impl.sharedSourceRootFixture
|
||||
import com.intellij.psi.impl.file.impl.withSharedSourceEnabled
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.contains
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.impl.file.impl
|
||||
|
||||
import com.intellij.codeInsight.multiverse.*
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.withSharedSourceEnabled
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
@@ -126,11 +126,6 @@ private fun CodeInsightContext.asText() = when (this) {
|
||||
else -> this.toString()
|
||||
}
|
||||
|
||||
fun TestFixture<Project>.withSharedSourceEnabled(): TestFixture<Project> = testFixture("shared-source-enabling-fixture") {
|
||||
MultiverseTestEnabler.enableSharedSourcesForTheNextProject()
|
||||
initialized(this@withSharedSourceEnabled.init()) {}
|
||||
}
|
||||
|
||||
fun sharedSourceRootFixture(vararg moduleFixtures: TestFixture<Module>): TestFixture<PsiDirectory> = testFixture("shared-source-root-fixture") {
|
||||
require(moduleFixtures.isNotEmpty())
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
|
||||
<orderEntry type="library" name="kotlin-test" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.core.impl" />
|
||||
</component>
|
||||
</module>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
interface ContentRootBuilder : ProjectBuilder {
|
||||
fun sourceRoot(
|
||||
name: String,
|
||||
sourceRootId: String? = null,
|
||||
init: DirectoryBuilder.() -> Unit,
|
||||
)
|
||||
|
||||
fun sharedSourceRoot(sourceRootId: String)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
interface DirectoryBuilder {
|
||||
fun dir(name: String, init: DirectoryBuilder.() -> Unit)
|
||||
|
||||
fun file(fileName: String, content: String)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
interface ModuleBuilder : ProjectBuilder {
|
||||
fun contentRoot(
|
||||
name: String,
|
||||
init: ContentRootBuilder.() -> Unit,
|
||||
)
|
||||
|
||||
fun sharedSourceRoot(sourceRootId: String)
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
interface ProjectBuilder : DirectoryBuilder {
|
||||
fun module(moduleName: String, init: ModuleBuilder.() -> Unit)
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
import com.intellij.codeInsight.multiverse.MultiverseTestEnabler
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl.MultiverseFixtureInitializer
|
||||
import com.intellij.testFramework.junit5.fixture.TestFixture
|
||||
import com.intellij.testFramework.junit5.fixture.testFixture
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
/**
|
||||
* This fixture allows setting up the project structure via a simple DSL
|
||||
*/
|
||||
@TestOnly
|
||||
fun multiverseProjectFixture(withSharedSourceEnabled: Boolean = true, init: ProjectBuilder.() -> Unit): TestFixture<Project> {
|
||||
val fixture = testFixture("multiverse-project-fixture") {
|
||||
val project = with(MultiverseFixtureInitializer(init)) {
|
||||
initializeProjectModel()
|
||||
}
|
||||
|
||||
initialized(project) { /* Nothing to dispose of */ }
|
||||
}
|
||||
return if (withSharedSourceEnabled) fixture.withSharedSourceEnabled() else fixture
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables Shared Source support in the given project.
|
||||
*/
|
||||
@TestOnly
|
||||
fun TestFixture<Project>.withSharedSourceEnabled(): TestFixture<Project> = testFixture("shared-source-enabling-fixture") {
|
||||
MultiverseTestEnabler.enableSharedSourcesForTheNextProject()
|
||||
initialized(this@withSharedSourceEnabled.init()) {}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ContentRootBuilder
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.DirectoryBuilder
|
||||
|
||||
internal class ContentRootBuilderImpl(
|
||||
path: String,
|
||||
projectStructure: ProjectStructure,
|
||||
) : DirectoryBuilderBase(path, projectStructure), ContentRootBuilder {
|
||||
private val _sourceRoots: MutableList<SourceRootBuilderImpl> = mutableListOf()
|
||||
|
||||
val sourceRoots: List<SourceRootBuilderImpl> get() = _sourceRoots
|
||||
|
||||
fun addSourceRoot(sourceRoot: SourceRootBuilderImpl) {
|
||||
_sourceRoots.add(sourceRoot)
|
||||
}
|
||||
|
||||
override fun sourceRoot(
|
||||
name: String,
|
||||
sourceRootId: String?,
|
||||
init: DirectoryBuilder.() -> Unit,
|
||||
) {
|
||||
val sourceRootPath = "$path/$name"
|
||||
val sourceRootBuilder = SourceRootBuilderImpl(name, sourceRootPath, projectStructure).apply(init)
|
||||
_sourceRoots.add(sourceRootBuilder)
|
||||
|
||||
if (sourceRootId != null) {
|
||||
projectStructure.addSourceRoot(sourceRootId, sourceRootBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sharedSourceRoot(sourceRootId: String) {
|
||||
val sharedSourceRootBuilder = projectStructure.findSourceRoot(sourceRootId)
|
||||
?: throw IllegalArgumentException("Source root ID '$sourceRootId' does not exist in the registry!")
|
||||
|
||||
_sourceRoots.add(sharedSourceRootBuilder)
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.DirectoryBuilder
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ModuleBuilder
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ProjectBuilder
|
||||
|
||||
internal open class DirectoryBuilderBase(
|
||||
override val path: String,
|
||||
protected val projectStructure: ProjectStructure,
|
||||
) : DirectoryContainer, ProjectBuilder {
|
||||
private val _directories: MutableList<DirectoryBuilderImpl> = mutableListOf()
|
||||
private val _nestedModules: MutableList<ModuleBuilderImpl> = mutableListOf()
|
||||
private val _files: MutableList<FileBuilderImpl> = mutableListOf()
|
||||
|
||||
override val directories: List<DirectoryBuilderImpl> get() = _directories
|
||||
override val modules: List<ModuleBuilderImpl> get() = _nestedModules
|
||||
override val files: List<FileBuilderImpl> get() = _files
|
||||
|
||||
override fun file(fileName: String, content: String) {
|
||||
_files.add(FileBuilderImpl(fileName, content))
|
||||
}
|
||||
|
||||
override fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directoryPath = subPath(name)
|
||||
val directory = DirectoryBuilderImpl(name, directoryPath, projectStructure)
|
||||
directory.init()
|
||||
_directories.add(directory)
|
||||
}
|
||||
|
||||
override fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val nestedModulePath = subPath(moduleName)
|
||||
val nestedModule = ModuleBuilderImpl(moduleName, nestedModulePath, projectStructure).apply(init)
|
||||
_nestedModules.add(nestedModule)
|
||||
}
|
||||
|
||||
private fun subPath(name: String): String {
|
||||
if (path.isEmpty()) return name
|
||||
return "$path/$name"
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
internal class DirectoryBuilderImpl(
|
||||
val name: String,
|
||||
path: String,
|
||||
projectStructure: ProjectStructure,
|
||||
) : DirectoryBuilderBase(path, projectStructure)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
internal interface DirectoryContainer {
|
||||
val path: String
|
||||
|
||||
val directories: List<DirectoryBuilderImpl>
|
||||
|
||||
val files: List<FileBuilderImpl>
|
||||
|
||||
val modules: List<ModuleBuilderImpl>
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
internal class FileBuilderImpl(
|
||||
val name: String,
|
||||
val content: String,
|
||||
)
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ContentRootBuilder
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ModuleBuilder
|
||||
|
||||
internal class ModuleBuilderImpl(
|
||||
val moduleName: String,
|
||||
path: String,
|
||||
projectStructure: ProjectStructure,
|
||||
) : DirectoryBuilderBase(path, projectStructure), ModuleBuilder {
|
||||
|
||||
private val _contentRoots: MutableList<ContentRootBuilderImpl> = mutableListOf()
|
||||
|
||||
val contentRoots: List<ContentRootBuilderImpl> get() = _contentRoots
|
||||
|
||||
override fun contentRoot(name: String, init: ContentRootBuilder.() -> Unit) {
|
||||
val contentRootPath = "$path/$name"
|
||||
val contentRootBuilder = ContentRootBuilderImpl(contentRootPath, projectStructure)
|
||||
_contentRoots.add(contentRootBuilder)
|
||||
contentRootBuilder.init()
|
||||
}
|
||||
|
||||
override fun sharedSourceRoot(sourceRootId: String) {
|
||||
val originalSourceRootBuilder = projectStructure.findSourceRoot(sourceRootId)
|
||||
?: throw IllegalArgumentException("Source root ID '$sourceRootId' does not exist in the registry!")
|
||||
|
||||
val contentRoot = ContentRootBuilderImpl(
|
||||
path = originalSourceRootBuilder.path,
|
||||
projectStructure = projectStructure,
|
||||
)
|
||||
_contentRoots.add(contentRoot)
|
||||
|
||||
val newSourceRoot = SourceRootBuilderImpl(name = originalSourceRootBuilder.name,
|
||||
path = originalSourceRootBuilder.path,
|
||||
projectStructure = projectStructure,
|
||||
isExisting = true)
|
||||
contentRoot.addSourceRoot(newSourceRoot)
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.testFramework.junit5.projectStructure.fixture.ProjectBuilder
|
||||
import com.intellij.testFramework.junit5.fixture.TestFixture
|
||||
import com.intellij.testFramework.junit5.fixture.TestFixtureInitializer
|
||||
import com.intellij.testFramework.junit5.fixture.moduleFixture
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
@TestOnly
|
||||
internal class MultiverseFixtureInitializer(
|
||||
private val init: ProjectBuilder.() -> Unit,
|
||||
) {
|
||||
private lateinit var projectFixture: TestFixture<Project>
|
||||
private lateinit var projectRootPath: Path
|
||||
private val structure = ProjectStructure()
|
||||
|
||||
suspend fun TestFixtureInitializer.R<Project>.initializeProjectModel(): Project {
|
||||
projectFixture = projectFixture()
|
||||
val project = projectFixture.init()
|
||||
|
||||
projectRootPath = project.basePath?.let { Path(it) } ?: error("Project base path is not available")
|
||||
|
||||
val projectRootAsFixture = dirFixture(projectRootPath)
|
||||
projectRootAsFixture.init()
|
||||
|
||||
val builder = DirectoryBuilderBase("", structure)
|
||||
builder.init()
|
||||
|
||||
initializeChildren(builder, projectRootAsFixture)
|
||||
|
||||
return project
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeModule(
|
||||
module: ModuleBuilderImpl
|
||||
) {
|
||||
val modulePath = module.path.resolvePath()
|
||||
val modulePathFixture = dirFixture(modulePath)
|
||||
val moduleFixture = projectFixture.moduleFixture(modulePathFixture)
|
||||
moduleFixture.init()
|
||||
|
||||
module.contentRoots.forEach { contentRoot ->
|
||||
initializeContentRoot(contentRoot, moduleFixture)
|
||||
}
|
||||
|
||||
initializeChildren(module, modulePathFixture)
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeContentRoot(
|
||||
contentRoot: ContentRootBuilderImpl,
|
||||
moduleFixture: TestFixture<Module>,
|
||||
) {
|
||||
val contentRootPath = contentRoot.path.resolvePath()
|
||||
val contentRootFixture = moduleFixture.customContentRootFixture(dirFixture(contentRootPath))
|
||||
contentRootFixture.init()
|
||||
|
||||
contentRoot.sourceRoots.forEach { sourceRoot ->
|
||||
initializeSourceRoot(moduleFixture, contentRootFixture, sourceRoot)
|
||||
}
|
||||
|
||||
initializeChildren(contentRoot, contentRootFixture)
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeSourceRoot(
|
||||
moduleFixture: TestFixture<Module>,
|
||||
contentRootFixture: TestFixture<Path>,
|
||||
sourceRoot: SourceRootBuilderImpl,
|
||||
) {
|
||||
val pathFixture = dirFixture(sourceRoot.path.resolvePath())
|
||||
val sourceRootFixture = moduleFixture.customSourceRootFixture(pathFixture, contentRootFixture)
|
||||
sourceRootFixture.init()
|
||||
|
||||
if (!sourceRoot.isExisting) {
|
||||
initializeChildren(sourceRoot, sourceRootFixture)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeChildren(
|
||||
container: DirectoryContainer,
|
||||
containerFixture: TestFixture<Path>,
|
||||
) {
|
||||
container.modules.forEach { nestedModule ->
|
||||
initializeModule(nestedModule)
|
||||
}
|
||||
|
||||
container.files.forEach { file ->
|
||||
containerFixture.fileFixture(file.name, file.content).init()
|
||||
}
|
||||
|
||||
container.directories.forEach { directory ->
|
||||
val directoryFixture = containerFixture.subDirFixture(directory.name)
|
||||
directoryFixture.init()
|
||||
initializeChildren(directory, directoryFixture)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.resolvePath(): Path = projectRootPath.resolve(this)
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
internal class ProjectStructure {
|
||||
private val sourceRoots: MutableMap<String, SourceRootBuilderImpl> = mutableMapOf()
|
||||
|
||||
fun findSourceRoot(sourceRootId: String): SourceRootBuilderImpl? =
|
||||
sourceRoots[sourceRootId]
|
||||
|
||||
fun addSourceRoot(sourceRootId: String, sourceRootBuilder: SourceRootBuilderImpl) {
|
||||
if (sourceRoots.containsKey(sourceRootId)) {
|
||||
throw IllegalArgumentException("Source root ID '$sourceRootId' already exists in the registry!")
|
||||
}
|
||||
sourceRoots[sourceRootId] = sourceRootBuilder
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
internal class SourceRootBuilderImpl(
|
||||
val name: String,
|
||||
path: String,
|
||||
projectStructure: ProjectStructure,
|
||||
val isExisting: Boolean = false,
|
||||
) : DirectoryBuilderBase(path, projectStructure)
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture.impl
|
||||
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.testFramework.junit5.fixture.TestFixture
|
||||
import com.intellij.testFramework.junit5.fixture.testFixture
|
||||
import com.intellij.util.io.createDirectories
|
||||
import com.intellij.util.io.delete
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.jps.model.java.JavaResourceRootType
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
@TestOnly
|
||||
internal fun TestFixture<Module>.customContentRootFixture(
|
||||
pathFixture: TestFixture<Path>,
|
||||
): TestFixture<Path> = testFixture("customContentRootFixture") {
|
||||
val module = this@customContentRootFixture.init()
|
||||
val path = pathFixture.init()
|
||||
val dir = VfsUtil.findFile(path, true) ?: error("Failed to find VFS file for path: $path")
|
||||
edtWriteAction {
|
||||
ModuleRootModificationUtil.updateModel(module) { model ->
|
||||
model.addContentEntry(dir)
|
||||
}
|
||||
}
|
||||
initialized(path) {}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
internal fun TestFixture<Module>.customSourceRootFixture(
|
||||
pathFixture: TestFixture<Path>,
|
||||
contentRootFixture: TestFixture<Path>,
|
||||
isTestSource: Boolean = false,
|
||||
isResource: Boolean = false,
|
||||
): TestFixture<Path> = testFixture("customSourceRootFixture") {
|
||||
val path = pathFixture.init()
|
||||
val module = this@customSourceRootFixture.init()
|
||||
val contentRootPath = contentRootFixture.init()
|
||||
edtWriteAction {
|
||||
val dir = VfsUtil.findFile(path, true) ?: error("Failed to find VFS file for path: $path")
|
||||
ModuleRootModificationUtil.updateModel(module) { model ->
|
||||
val contentEntry = model.contentEntries
|
||||
.find { it.file?.toNioPath() == contentRootPath }
|
||||
?: error("Content entry with path '$path' was not found in module ${module.name}.")
|
||||
val type = getSourceRootType(isTestSource, isResource)
|
||||
contentEntry.addSourceFolder(dir, type)
|
||||
}
|
||||
}
|
||||
initialized(path) {}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
internal fun dirFixture(dir: Path): TestFixture<Path> = testFixture("dirFixture") {
|
||||
val tempDir = withContext(Dispatchers.IO) {
|
||||
if (!dir.exists()) {
|
||||
dir.createDirectories()
|
||||
}
|
||||
dir
|
||||
}
|
||||
initialized(tempDir) {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (tempDir.exists()) {
|
||||
tempDir.delete(recursively = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
internal fun TestFixture<Path>.subDirFixture(name: String): TestFixture<Path> = testFixture("subDirFixture") {
|
||||
val path = this@subDirFixture.init().resolve(name)
|
||||
val result = dirFixture(path).init()
|
||||
initialized(result) {}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
internal fun TestFixture<Path>.fileFixture(fileName: String, content: CharSequence): TestFixture<Path> = testFixture("fileFixture") {
|
||||
val file = withContext(Dispatchers.IO) {
|
||||
val dir = this@fileFixture.init()
|
||||
if (!dir.exists()) {
|
||||
dir.createDirectories()
|
||||
}
|
||||
val file = dir.resolve(fileName)
|
||||
file.writeText(content)
|
||||
file
|
||||
}
|
||||
initialized(file) {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (file.exists()) {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSourceRootType(isTestSource: Boolean, isResource: Boolean): JpsModuleSourceRootType<*> = when {
|
||||
isTestSource && isResource -> JavaResourceRootType.TEST_RESOURCE
|
||||
!isTestSource && isResource -> JavaResourceRootType.RESOURCE
|
||||
isTestSource && !isResource -> JavaSourceRootType.TEST_SOURCE
|
||||
else -> JavaSourceRootType.SOURCE
|
||||
}
|
||||
+27
-44
@@ -1,5 +1,5 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.testFramework.junit5.showcase
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
@@ -7,15 +7,16 @@ import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.junit5.fixture.multiverseProjectFixture
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@TestApplication
|
||||
class JUnit5MultiverseFixtureTest {
|
||||
companion object {
|
||||
val multiverseFixture = multiverseProjectFixture("test-multiverse-project") {
|
||||
val multiverseFixture = multiverseProjectFixture {
|
||||
module("module1") {
|
||||
contentRoot("module1PrimaryContent") {
|
||||
sourceRoot("source1", sourceRootId = "source1ID") {
|
||||
@@ -112,12 +113,6 @@ class JUnit5MultiverseFixtureTest {
|
||||
}
|
||||
|
||||
module("nestedModule3") {
|
||||
contentRoot("nestedModule3ContentRoot") {
|
||||
sharedSourceRoot("source1ID")
|
||||
}
|
||||
}
|
||||
|
||||
sharedContentRoot("module1PrimaryContent", "module1") {
|
||||
sharedSourceRoot("source1ID")
|
||||
}
|
||||
|
||||
@@ -181,9 +176,6 @@ class JUnit5MultiverseFixtureTest {
|
||||
val module2 = moduleManager.modules.find { it.name == "module2" } ?: error("Module2 not found")
|
||||
val sourceRoots = module2.rootManager.sourceRoots
|
||||
|
||||
val sharedSourceRoot = sourceRoots.find { it.path.contains("source1") }
|
||||
assertNotNull(sharedSourceRoot) { "Shared Source Root 'source1' should exist in module2" }
|
||||
|
||||
val uniqueSourceRoot = sourceRoots.find { it.path.contains("source2") }
|
||||
assertNotNull(uniqueSourceRoot) { "Unique Source Root 'source2' should exist in module2" }
|
||||
}
|
||||
@@ -207,15 +199,15 @@ class JUnit5MultiverseFixtureTest {
|
||||
val module1 = moduleManager.modules.find { it.name == "module1" }
|
||||
assertNotNull(module1, "Module1 should exist")
|
||||
|
||||
val module1SourceRoots = module1!!.rootManager.sourceRoots
|
||||
val module1SourceRoots = module1.rootManager.sourceRoots
|
||||
val module1Dir1 = module1SourceRoots.flatMap { it.children.toList() }
|
||||
.find { it.name == "dir1" }
|
||||
assertNotNull(module1Dir1, "Directory dir1 should exist in module1")
|
||||
|
||||
val module1File1 = module1Dir1!!.findChild("file1.java")
|
||||
val module1File1 = module1Dir1.findChild("file1.java")
|
||||
assertNotNull(module1File1, "File file1.java should exist in dir1 of module1")
|
||||
|
||||
val file1Content = module1File1!!.contentsToByteArray().decodeToString()
|
||||
val file1Content = module1File1.contentsToByteArray().decodeToString()
|
||||
assert(file1Content.contains("public class A1")) {
|
||||
"File file1.java content does not match expected content"
|
||||
}
|
||||
@@ -228,7 +220,7 @@ class JUnit5MultiverseFixtureTest {
|
||||
|
||||
val module1 = moduleManager.modules.find { it.name == "module1" }
|
||||
assertNotNull(module1, "Module1 should exist")
|
||||
val module1ContentRoots = module1!!.rootManager.contentRoots
|
||||
val module1ContentRoots = module1.rootManager.contentRoots
|
||||
assert(module1ContentRoots.size == 1) {
|
||||
"Expected only 1 content root for module1, but found: ${module1ContentRoots.size}"
|
||||
}
|
||||
@@ -241,23 +233,14 @@ class JUnit5MultiverseFixtureTest {
|
||||
val module2 = moduleManager.modules.find { it.name == "module2" }
|
||||
assertNotNull(module2, "Module2 should exist")
|
||||
|
||||
val module2SourceRoots = module2!!.rootManager.sourceRoots.map { it.toNioPath().toFile() }
|
||||
|
||||
val sharedSource1 = module2SourceRoots.find { it.name == "source1" }
|
||||
assertNotNull(sharedSource1, "Shared Source Root 'source1' (source1ID) should exist in module2")
|
||||
val module2SourceRoots = module2.rootManager.sourceRoots.map { it.toNioPath().toFile() }
|
||||
|
||||
val sharedSource2 = module2SourceRoots.find { it.name == "source2" }
|
||||
assertNotNull(sharedSource2, "Shared Source Root 'source2' (source2ID) should exist in module2")
|
||||
|
||||
val file1InSource1 = sharedSource1!!.walkTopDown().find { it.name == "file1.java" }
|
||||
assertNotNull(file1InSource1, "File 'file1.java' should exist in shared source1 (source1ID)")
|
||||
assert(file1InSource1!!.readText().contains("public class A1")) {
|
||||
"File 'file1.java' content does not match expected content in shared source1"
|
||||
}
|
||||
|
||||
val file3InSource2 = sharedSource2!!.walkTopDown().find { it.name == "file3.txt" }
|
||||
val file3InSource2 = sharedSource2.walkTopDown().find { it.name == "file3.txt" }
|
||||
assertNotNull(file3InSource2, "File 'file3.txt' should exist in shared source2 (source2ID)")
|
||||
assert(file3InSource2!!.readText().contains("Key=Value")) {
|
||||
assert(file3InSource2.readText().contains("Key=Value")) {
|
||||
"File 'file3.txt' content does not match expected content in shared source2"
|
||||
}
|
||||
}
|
||||
@@ -287,19 +270,19 @@ class JUnit5MultiverseFixtureTest {
|
||||
val nestedModule1 = moduleManager.modules.find { it.name == "nestedModule1" }
|
||||
assertNotNull(nestedModule1, "'nestedModule1' should exist")
|
||||
|
||||
val nestedContentRoot1 = nestedModule1!!.rootManager.contentRoots.find { it.name == "nestedContentRoot1" }
|
||||
val nestedContentRoot1 = nestedModule1.rootManager.contentRoots.find { it.name == "nestedContentRoot1" }
|
||||
assertNotNull(nestedContentRoot1, "'nestedContentRoot1' should be the content root for nestedModule1")
|
||||
|
||||
val nestedSourceRoot1 = nestedModule1.rootManager.sourceRoots.find { it.name == "nestedSourceRoot1" }
|
||||
assertNotNull(nestedSourceRoot1, "'nestedSourceRoot1' should exist in nestedModule1")
|
||||
|
||||
val nestedDir = nestedSourceRoot1!!.children.find { it.name == "nestedDir" }
|
||||
val nestedDir = nestedSourceRoot1.children.find { it.name == "nestedDir" }
|
||||
assertNotNull(nestedDir, "'nestedDir' should exist in nestedModule1's source root")
|
||||
|
||||
val nestedFile = nestedDir!!.findChild("nestedFile.java")
|
||||
val nestedFile = nestedDir.findChild("nestedFile.java")
|
||||
assertNotNull(nestedFile, "'nestedFile.java' should exist in 'nestedDir'")
|
||||
|
||||
val nestedFileContent = nestedFile!!.contentsToByteArray().decodeToString()
|
||||
val nestedFileContent = nestedFile.contentsToByteArray().decodeToString()
|
||||
assert(nestedFileContent.contains("public class NestedClass")) {
|
||||
"File 'nestedFile.java' content does not match expected content in nestedModule1"
|
||||
}
|
||||
@@ -307,19 +290,19 @@ class JUnit5MultiverseFixtureTest {
|
||||
val nestedModule2 = moduleManager.modules.find { it.name == "nestedModule2" }
|
||||
assertNotNull(nestedModule2, "'nestedModule2' should exist")
|
||||
|
||||
val nestedContentRoot2 = nestedModule2!!.rootManager.contentRoots.find { it.name == "nestedModuleContent" }
|
||||
val nestedContentRoot2 = nestedModule2.rootManager.contentRoots.find { it.name == "nestedModuleContent" }
|
||||
assertNotNull(nestedContentRoot2, "'nestedModuleContent' should be the content root for nestedModule2")
|
||||
|
||||
val nestedSourceRoot2 = nestedModule2.rootManager.sourceRoots.find { it.name == "nestedSourceInContent" }
|
||||
assertNotNull(nestedSourceRoot2, "'nestedSourceInContent' should exist in nestedModule2")
|
||||
|
||||
val docsDir = nestedSourceRoot2!!.children.find { it.name == "docs" }
|
||||
val docsDir = nestedSourceRoot2.children.find { it.name == "docs" }
|
||||
assertNotNull(docsDir, "'docs' directory should exist in nestedModule2's nested source root")
|
||||
|
||||
val readmeFile = docsDir!!.findChild("README.md")
|
||||
val readmeFile = docsDir.findChild("README.md")
|
||||
assertNotNull(readmeFile, "'README.md' should exist in 'docs'")
|
||||
|
||||
val readmeContent = readmeFile!!.contentsToByteArray().decodeToString()
|
||||
val readmeContent = readmeFile.contentsToByteArray().decodeToString()
|
||||
assert(readmeContent.contains("# Documentation")) {
|
||||
"File 'README.md' content does not match expected content in nestedModule2"
|
||||
}
|
||||
@@ -333,17 +316,17 @@ class JUnit5MultiverseFixtureTest {
|
||||
val nestedModule3 = moduleManager.modules.find { it.name == "nestedModule3" }
|
||||
assertNotNull(nestedModule3, "'nestedModule3' should exist in module2")
|
||||
|
||||
val nestedModule3SourceRoots = nestedModule3!!.rootManager.sourceRoots
|
||||
val nestedModule3SourceRoots = nestedModule3.rootManager.sourceRoots
|
||||
val sharedSource1InNestedModule3 = nestedModule3SourceRoots.find { it.name == "source1" }
|
||||
assertNotNull(sharedSource1InNestedModule3, "'source1' should be accessible in nestedModule3 from module1")
|
||||
|
||||
val source1Dir = sharedSource1InNestedModule3!!.children.toList()
|
||||
val source1Dir = sharedSource1InNestedModule3.children
|
||||
val sharedDir1 = source1Dir.find { it.name == "dir1" }
|
||||
assertNotNull(sharedDir1, "'dir1' should exist in the shared source1 of nestedModule3")
|
||||
|
||||
val sharedFile1 = sharedDir1!!.findChild("file1.java")
|
||||
val sharedFile1 = sharedDir1.findChild("file1.java")
|
||||
assertNotNull(sharedFile1, "'file1.java' should exist in the shared source1 in nestedModule3")
|
||||
val file1Content = sharedFile1!!.contentsToByteArray().decodeToString()
|
||||
val file1Content = sharedFile1.contentsToByteArray().decodeToString()
|
||||
assert(file1Content.contains("public class A1")) {
|
||||
"File 'file1.java' content in shared source1 does not match expected content"
|
||||
}
|
||||
@@ -351,9 +334,9 @@ class JUnit5MultiverseFixtureTest {
|
||||
val sharedDir2 = source1Dir.find { it.name == "dir2" }
|
||||
assertNotNull(sharedDir2, "'dir2' should exist in the shared source1 of nestedModule3")
|
||||
|
||||
val sharedFile2 = sharedDir2!!.findChild("file2.java")
|
||||
val sharedFile2 = sharedDir2.findChild("file2.java")
|
||||
assertNotNull(sharedFile2, "'file2.java' should exist in the shared source1 in nestedModule3")
|
||||
val file2Content = sharedFile2!!.contentsToByteArray().decodeToString()
|
||||
val file2Content = sharedFile2.contentsToByteArray().decodeToString()
|
||||
assert(file2Content.contains("public class A2")) {
|
||||
"File 'file2.java' content in shared source1 does not match expected content"
|
||||
}
|
||||
@@ -369,7 +352,7 @@ class JUnit5MultiverseFixtureTest {
|
||||
private fun assertFileExist(path: String) {
|
||||
val project = multiverseFixture.get()
|
||||
val basePath = project.basePath!!
|
||||
val file = VfsUtil.findFile(Path("$basePath/$path"), false)
|
||||
val file = VfsUtil.findFile(Path("$basePath/$path"), true)
|
||||
assertNotNull(file, path)
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@TestApplication
|
||||
internal class MultiverseFixtureTest {
|
||||
companion object {
|
||||
val projectFixture = multiverseProjectFixture {
|
||||
module("a") {
|
||||
contentRoot("root") {
|
||||
sourceRoot("src", "shared") {
|
||||
file("A.java", "class A {}")
|
||||
}
|
||||
}
|
||||
}
|
||||
module("b") {
|
||||
sharedSourceRoot("shared")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `assert project structure`() = timeoutRunBlocking {
|
||||
readAction {
|
||||
val project = projectFixture.get()
|
||||
val moduleManager = ModuleManager.getInstance(project)
|
||||
val modules = moduleManager.modules
|
||||
val sourceRoots = modules.map { module ->
|
||||
module.rootManager.sourceRoots.single()
|
||||
}.distinct()
|
||||
|
||||
assertEquals(1, sourceRoots.size) { sourceRoots.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.testFramework.junit5.projectStructure.fixture
|
||||
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@TestApplication
|
||||
internal class SimpleProjectTest {
|
||||
val projectFixture = multiverseProjectFixture {
|
||||
module("a") {
|
||||
contentRoot("root") {
|
||||
sourceRoot("src", "shared") {
|
||||
file("A.java", "class A {}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `assert project structure`() = timeoutRunBlocking {
|
||||
readAction {
|
||||
val project = projectFixture.get()
|
||||
val moduleManager = ModuleManager.getInstance(project)
|
||||
val modules = moduleManager.modules
|
||||
assertEquals(1, modules.size, modules.toString())
|
||||
|
||||
val sourceRoots = modules.single().rootManager.sourceRoots
|
||||
assertEquals(1, sourceRoots.size, sourceRoots.toString())
|
||||
|
||||
val sourceRoot = sourceRoots.single()
|
||||
val path = sourceRoot.path
|
||||
assert(path.endsWith("a/root/src")) { path }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,508 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.testFramework.junit5.fixture
|
||||
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.util.io.toCanonicalPath
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.util.io.createDirectories
|
||||
import com.intellij.util.io.delete
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
|
||||
@TestOnly
|
||||
fun multiverseProjectFixture(name: String, init: MultiverseProjectBuilder.() -> Unit): TestFixture<Project> {
|
||||
val builder = MultiverseProjectBuilder(name)
|
||||
builder.init()
|
||||
return buildMultiverseFixture(builder)
|
||||
}
|
||||
|
||||
class MultiverseProjectBuilder(val name: String) {
|
||||
private val directories: MutableList<DirectoryBuilder> = mutableListOf()
|
||||
private val modules: MutableList<ModuleBuilder> = mutableListOf()
|
||||
private val sourceRootRegistry: MutableMap<String, SourceRootBuilder> = mutableMapOf()
|
||||
private val contentRoots: MutableMap<String, MutableMap<String, ContentRootBuilder>> = mutableMapOf()
|
||||
|
||||
fun getModules(): List<ModuleBuilder> = modules
|
||||
fun getContentRoot(name: String): Map<String, ContentRootBuilder>? = contentRoots[name]
|
||||
|
||||
fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directory = DirectoryBuilder(name, path = name)
|
||||
directory.init()
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val moduleBuilder = ModuleBuilder(moduleName, modulePath = moduleName)
|
||||
moduleBuilder.init()
|
||||
modules.add(moduleBuilder)
|
||||
}
|
||||
|
||||
inner class ModuleBuilder(val moduleName: String, private val modulePath: String) : DirectoryContainer, ModuleContainer {
|
||||
private val directories: MutableList<DirectoryBuilder> = mutableListOf()
|
||||
private val files: MutableList<FileBuilder> = mutableListOf()
|
||||
private val nestedModules: MutableList<ModuleBuilder> = mutableListOf()
|
||||
|
||||
override fun getDirectories(): List<DirectoryBuilder> = directories
|
||||
override fun getFiles(): List<FileBuilder> = files
|
||||
|
||||
override fun getNestedModules(): List<ModuleBuilder> = nestedModules
|
||||
fun getPath(): String = modulePath
|
||||
|
||||
fun contentRoot(name: String, init: ContentRootBuilder.() -> Unit) {
|
||||
val contentRootPath = "$modulePath/$name"
|
||||
val moduleMap = contentRoots.getOrPut(moduleName) { mutableMapOf() }
|
||||
val contentRootBuilder = moduleMap[name]
|
||||
?: ContentRootBuilder(name, contentRootPath).also { moduleMap[name] = it }
|
||||
contentRootBuilder.init()
|
||||
}
|
||||
|
||||
fun sharedContentRoot(contentRootName: String, sourceModuleName: String, sharedSourceRootInit: ContentRootBuilder.() -> Unit = {}) {
|
||||
val sourceContentMap = contentRoots[sourceModuleName]
|
||||
?: throw IllegalArgumentException("Module '$sourceModuleName' has no content roots registered!")
|
||||
|
||||
val sourceContentRoot = sourceContentMap[contentRootName]
|
||||
?: throw IllegalArgumentException("Content root '$contentRootName' does not exist in module '$sourceModuleName'.")
|
||||
|
||||
val moduleMap = contentRoots.getOrPut(moduleName) { mutableMapOf() }
|
||||
moduleMap[contentRootName] = ContentRootBuilder(
|
||||
name = sourceContentRoot.name,
|
||||
path = sourceContentRoot.getContentRootPath(),
|
||||
isExisting = true
|
||||
).apply(sharedSourceRootInit)
|
||||
}
|
||||
|
||||
fun sharedSourceRoot(sourceRootId: String) {
|
||||
val sharedSourceRootBuilder = sourceRootRegistry[sourceRootId]
|
||||
?: throw IllegalArgumentException("Source root ID '$sourceRootId' does not exist in the registry!")
|
||||
|
||||
val contentRootName = sharedSourceRootBuilder.name
|
||||
val moduleMap = contentRoots.getOrPut(moduleName) { mutableMapOf() }
|
||||
val existingContentRoot = moduleMap[contentRootName]
|
||||
|
||||
val contentRoot = existingContentRoot ?: ContentRootBuilder(
|
||||
name = contentRootName,
|
||||
path = sharedSourceRootBuilder.getSourceRootPath() ?: "",
|
||||
isExisting = true
|
||||
).also { moduleMap[contentRootName] = it }
|
||||
|
||||
contentRoot.addSourceRoot(sharedSourceRootBuilder)
|
||||
}
|
||||
|
||||
override fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directoryPath = "$modulePath/$name"
|
||||
val directory = DirectoryBuilder(name, directoryPath)
|
||||
directory.init()
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
override fun file(fileName: String, content: String) {
|
||||
files.add(FileBuilder(fileName, content, "$modulePath/$fileName"))
|
||||
}
|
||||
|
||||
override fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val nestedModulePath = "$modulePath/$moduleName"
|
||||
val nestedModule = ModuleBuilder(moduleName, nestedModulePath).apply(init)
|
||||
nestedModules.add(nestedModule)
|
||||
}
|
||||
}
|
||||
|
||||
inner class ContentRootBuilder(
|
||||
val name: String,
|
||||
private val path: String,
|
||||
val isExisting: Boolean = false,
|
||||
) : DirectoryContainer, ModuleContainer {
|
||||
private val directories: MutableList<DirectoryBuilder> = mutableListOf()
|
||||
private val files: MutableList<FileBuilder> = mutableListOf()
|
||||
private val nestedModules: MutableList<ModuleBuilder> = mutableListOf()
|
||||
private val sourceRoots: MutableList<SourceRootBuilder> = mutableListOf()
|
||||
|
||||
override fun getDirectories(): List<DirectoryBuilder> = directories
|
||||
override fun getFiles(): List<FileBuilder> = files
|
||||
override fun getNestedModules(): List<ModuleBuilder> = nestedModules
|
||||
fun getSourceRoots(): List<SourceRootBuilder> = sourceRoots
|
||||
fun addSourceRoot(sourceRoot: SourceRootBuilder) {
|
||||
if (sourceRoots.none { it.name == sourceRoot.name }) {
|
||||
sourceRoots.add(sourceRoot)
|
||||
}
|
||||
}
|
||||
|
||||
fun sourceRoot(name: String, sourceRootId: String? = null, init: SourceRootBuilder.() -> Unit) {
|
||||
val sourceRootPath = "$path/$name"
|
||||
val sourceRootBuilder = SourceRootBuilder(name, sourceRootPath).apply(init)
|
||||
sourceRoots.add(sourceRootBuilder)
|
||||
|
||||
sourceRootId?.let { id ->
|
||||
if (!sourceRootRegistry.containsKey(id)) {
|
||||
sourceRootRegistry[id] = sourceRootBuilder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun sharedSourceRoot(sourceRootId: String) {
|
||||
val sharedSourceRootBuilder = sourceRootRegistry[sourceRootId]
|
||||
?: throw IllegalArgumentException("Source root ID '$sourceRootId' does not exist in the registry!")
|
||||
|
||||
if (sourceRoots.none { it.name == sharedSourceRootBuilder.name }) {
|
||||
sourceRoots.add(sharedSourceRootBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directoryPath = "$path/$name"
|
||||
val directory = DirectoryBuilder(name, directoryPath)
|
||||
directory.init()
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
override fun file(fileName: String, content: String) {
|
||||
files.add(FileBuilder(fileName, content, "$path/$fileName"))
|
||||
}
|
||||
|
||||
override fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val nestedModulePath = "$path/$moduleName"
|
||||
val nestedModule = ModuleBuilder(moduleName, nestedModulePath).apply(init)
|
||||
nestedModules.add(nestedModule)
|
||||
}
|
||||
|
||||
fun getContentRootPath(): String = path
|
||||
}
|
||||
|
||||
inner class SourceRootBuilder(
|
||||
val name: String,
|
||||
private val path: String? = null,
|
||||
val isExisting: Boolean = false,
|
||||
) : DirectoryContainer, ModuleContainer {
|
||||
private val directories: MutableList<DirectoryBuilder> = mutableListOf()
|
||||
private val nestedModules: MutableList<ModuleBuilder> = mutableListOf()
|
||||
private val files: MutableList<FileBuilder> = mutableListOf()
|
||||
|
||||
override fun getDirectories(): List<DirectoryBuilder> = directories
|
||||
override fun getNestedModules(): List<ModuleBuilder> = nestedModules
|
||||
override fun getFiles(): List<FileBuilder> = files
|
||||
|
||||
override fun file(fileName: String, content: String) {
|
||||
files.add(FileBuilder(fileName, content, "$path/$fileName"))
|
||||
}
|
||||
|
||||
override fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directoryPath = "$path/$name"
|
||||
val directory = DirectoryBuilder(name, directoryPath)
|
||||
directory.init()
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
override fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val nestedModulePath = "$path/$moduleName"
|
||||
val nestedModule = ModuleBuilder(moduleName, nestedModulePath).apply(init)
|
||||
nestedModules.add(nestedModule)
|
||||
}
|
||||
|
||||
fun getSourceRootPath(): String? = path
|
||||
}
|
||||
|
||||
inner class DirectoryBuilder(val name: String, private val path: String) : DirectoryContainer, ModuleContainer {
|
||||
private val directories: MutableList<DirectoryBuilder> = mutableListOf()
|
||||
private val nestedModules: MutableList<ModuleBuilder> = mutableListOf()
|
||||
private val files: MutableList<FileBuilder> = mutableListOf()
|
||||
|
||||
override fun getDirectories(): List<DirectoryBuilder> = directories
|
||||
override fun getNestedModules(): List<ModuleBuilder> = nestedModules
|
||||
override fun getFiles(): List<FileBuilder> = files
|
||||
|
||||
override fun file(fileName: String, content: String) {
|
||||
files.add(FileBuilder(fileName, content, "$path/$fileName"))
|
||||
}
|
||||
|
||||
override fun dir(name: String, init: DirectoryBuilder.() -> Unit) {
|
||||
val directoryPath = "$path/$name"
|
||||
val directory = DirectoryBuilder(name, directoryPath)
|
||||
directory.init()
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
override fun module(moduleName: String, init: ModuleBuilder.() -> Unit) {
|
||||
val nestedModulePath = "$path/$moduleName"
|
||||
val nestedModule = ModuleBuilder(moduleName, nestedModulePath).apply(init)
|
||||
nestedModules.add(nestedModule)
|
||||
}
|
||||
}
|
||||
|
||||
inner class FileBuilder(private val name: String, private val content: String, private val path: String) {
|
||||
fun getFileName(): String = name
|
||||
fun getFilePath(): String = path
|
||||
fun getFileContent(): String = content
|
||||
}
|
||||
|
||||
interface DirectoryContainer {
|
||||
fun getDirectories(): List<DirectoryBuilder>
|
||||
fun getFiles(): List<FileBuilder>
|
||||
fun dir(name: String, init: DirectoryBuilder.() -> Unit)
|
||||
fun file(fileName: String, content: String)
|
||||
}
|
||||
|
||||
interface ModuleContainer {
|
||||
fun getNestedModules(): List<ModuleBuilder>
|
||||
fun module(moduleName: String, init: ModuleBuilder.() -> Unit)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getPsiDirectoryFromVfs(psiManager: PsiManager, directoryVfs: VirtualFile): PsiDirectory {
|
||||
return readAction {
|
||||
psiManager.findDirectory(directoryVfs)
|
||||
?: error("Failed to find PsiDirectory for VirtualFile: $directoryVfs")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createDirectory(targetPath: Path): VirtualFile {
|
||||
return edtWriteAction {
|
||||
VfsUtil.createDirectories(targetPath.toCanonicalPath())
|
||||
?: error("Failed to create directory at path: $targetPath")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun deleteDirectorySafely(psiDirectory: PsiDirectory, targetPath: Path, project: Project) {
|
||||
edtWriteAction {
|
||||
if (!psiDirectory.isValid) {
|
||||
val resolvedVfsDirectory = LocalFileSystem.getInstance().findFileByPath(targetPath.toString())
|
||||
resolvedVfsDirectory?.delete(project)
|
||||
}
|
||||
else {
|
||||
psiDirectory.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private fun <T> TestFixture<T>.customDirectoryFixture(
|
||||
root: Path,
|
||||
dirName: String,
|
||||
getProject: (T) -> Project,
|
||||
onDirectoryCreated: (VirtualFile, T) -> Unit,
|
||||
): TestFixture<PsiDirectory> = testFixture {
|
||||
val targetPath = root.resolve(dirName).toAbsolutePath()
|
||||
val parent = this@customDirectoryFixture.init()
|
||||
|
||||
val parentPath = targetPath.parent
|
||||
if (parentPath != null && !Files.exists(parentPath)) {
|
||||
createDirectory(parentPath)
|
||||
}
|
||||
|
||||
val directoryVfs = createDirectory(targetPath)
|
||||
|
||||
onDirectoryCreated(directoryVfs, parent)
|
||||
|
||||
val psiDirectory = getPsiDirectoryFromVfs(PsiManager.getInstance(getProject(parent)), directoryVfs)
|
||||
|
||||
initialized(psiDirectory) {
|
||||
deleteDirectorySafely(psiDirectory, targetPath, getProject(parent))
|
||||
}
|
||||
}
|
||||
|
||||
private val getProjectFromModule: (Module) -> Project = { it.project }
|
||||
private val getProjectFromPsiDirectory: (PsiDirectory) -> Project = { it.project }
|
||||
|
||||
@TestOnly
|
||||
private fun TestFixture<PsiDirectory>.customPsiDirectoryFixture(
|
||||
root: Path,
|
||||
dirName: String,
|
||||
): TestFixture<PsiDirectory> = customDirectoryFixture(root, dirName, getProjectFromPsiDirectory) { _, _ ->
|
||||
// No additional actions are needed for PsiDirectory fixture.
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private fun TestFixture<Module>.customContentRootFixture(
|
||||
root: Path,
|
||||
dirName: String,
|
||||
): TestFixture<PsiDirectory> = customDirectoryFixture(root, dirName, getProjectFromModule) { directoryVfs, module ->
|
||||
ModuleRootModificationUtil.updateModel(module) { model ->
|
||||
model.addContentEntry(directoryVfs)
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private fun TestFixture<Module>.customSourceRootFixture(
|
||||
isTestSource: Boolean = false,
|
||||
contentEntry: Path,
|
||||
dirName: String,
|
||||
): TestFixture<PsiDirectory> = customDirectoryFixture(contentEntry, dirName, getProjectFromModule) { directoryVfs, module ->
|
||||
ModuleRootModificationUtil.updateModel(module) { model ->
|
||||
val entry = model.contentEntries.find { it.file?.path == contentEntry.toAbsolutePath().toString() }
|
||||
if (entry == null) {
|
||||
println("Warning: Content entry with path '${contentEntry.toAbsolutePath()}' was not found in module ${module.name}.")
|
||||
return@updateModel
|
||||
}
|
||||
entry.addSourceFolder(directoryVfs, isTestSource)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates path fixture without generating a random name for directory inside.
|
||||
*/
|
||||
@TestOnly
|
||||
private fun customPathFixture(root: Path): TestFixture<Path> = testFixture {
|
||||
val tempDir = withContext(Dispatchers.IO) {
|
||||
if (!root.exists()) {
|
||||
root.createDirectories()
|
||||
}
|
||||
root
|
||||
}
|
||||
initialized(tempDir) {
|
||||
withContext(Dispatchers.IO) {
|
||||
if (tempDir.exists()) {
|
||||
tempDir.delete(recursively = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private fun buildMultiverseFixture(builder: MultiverseProjectBuilder): TestFixture<Project> = testFixture(builder.name) {
|
||||
val initializer = MultiverseFixtureInitializer(builder)
|
||||
val project = with(initializer) {
|
||||
initializeProjectModel()
|
||||
}
|
||||
|
||||
initialized(project) {
|
||||
/*
|
||||
Nothing to dispose
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private class MultiverseFixtureInitializer(private val builder: MultiverseProjectBuilder) {
|
||||
private lateinit var projectFixture: TestFixture<Project>
|
||||
|
||||
suspend fun TestFixtureInitializer.R<Project>.initializeProjectModel(): Project {
|
||||
this@MultiverseFixtureInitializer.projectFixture = projectFixture()
|
||||
val project = projectFixture.init()
|
||||
|
||||
val basePath = project.basePath?.let { Path.of(it) }
|
||||
?: throw IllegalStateException("Project base path is not available")
|
||||
|
||||
builder.getModules().forEach { module ->
|
||||
initializeModule(basePath, module)
|
||||
}
|
||||
|
||||
return project
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeModule(
|
||||
parentPath: Path,
|
||||
module: MultiverseProjectBuilder.ModuleBuilder,
|
||||
) {
|
||||
val modulePath = parentPath.resolve(module.moduleName)
|
||||
val modulePathFixture = customPathFixture(modulePath)
|
||||
val moduleFixture = projectFixture.moduleFixture(modulePathFixture)
|
||||
moduleFixture.init()
|
||||
|
||||
val contentRoots = builder.getContentRoot(module.moduleName)
|
||||
?: throw IllegalStateException("Content roots entity for module '${module.moduleName}' is null")
|
||||
|
||||
contentRoots.values.forEach { contentRoot ->
|
||||
initializeContentRoot(modulePath, contentRoot, moduleFixture)
|
||||
}
|
||||
|
||||
module.getNestedModules().forEach { nestedModule ->
|
||||
initializeModule(modulePath, nestedModule)
|
||||
}
|
||||
|
||||
initializeDirectoriesAndFiles(modulePath, modulePathFixture.asPsiDirectoryFixture(), module)
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeContentRoot(
|
||||
modulePath: Path,
|
||||
contentRoot: MultiverseProjectBuilder.ContentRootBuilder,
|
||||
moduleFixture: TestFixture<Module>,
|
||||
) {
|
||||
val contentRootPath = modulePath.resolve(contentRoot.name)
|
||||
val contentRootFixture = if (contentRoot.isExisting) {
|
||||
moduleFixture.customContentRootFixture(contentRootPath.parent, contentRoot.name)
|
||||
}
|
||||
else {
|
||||
moduleFixture.customContentRootFixture(modulePath, contentRoot.name)
|
||||
}
|
||||
contentRootFixture.init()
|
||||
|
||||
initializeDirectoriesAndFiles(
|
||||
parentPath = contentRootPath,
|
||||
psiFixture = contentRootFixture,
|
||||
parent = contentRoot
|
||||
)
|
||||
|
||||
contentRoot.getSourceRoots().forEach { sourceRoot ->
|
||||
val sourceRootPath = contentRootPath.resolve(sourceRoot.name)
|
||||
val sourceRootFixture = moduleFixture.customSourceRootFixture(contentEntry = contentRootPath, dirName = sourceRoot.name)
|
||||
sourceRootFixture.init()
|
||||
|
||||
if (!sourceRoot.isExisting) {
|
||||
initializeDirectoriesAndFiles(
|
||||
parentPath = sourceRootPath,
|
||||
psiFixture = sourceRootFixture,
|
||||
parent = sourceRoot
|
||||
)
|
||||
|
||||
sourceRoot.getNestedModules().forEach { nestedModule ->
|
||||
initializeModule(sourceRootPath, nestedModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentRoot.getNestedModules().forEach { nestedModule ->
|
||||
initializeModule(contentRootPath, nestedModule)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TestFixtureInitializer.R<Project>.initializeDirectoriesAndFiles(
|
||||
parentPath: Path,
|
||||
psiFixture: TestFixture<PsiDirectory>,
|
||||
parent: MultiverseProjectBuilder.DirectoryContainer,
|
||||
) {
|
||||
val directories = parent.getDirectories()
|
||||
directories.forEach { directory ->
|
||||
val directoryFixture = psiFixture.customPsiDirectoryFixture(
|
||||
root = parentPath,
|
||||
dirName = directory.name
|
||||
)
|
||||
|
||||
directoryFixture.init()
|
||||
|
||||
val directoryPath = parentPath.resolve(directory.name)
|
||||
|
||||
initializeDirectoriesAndFiles(
|
||||
parentPath = directoryPath,
|
||||
psiFixture = directoryFixture,
|
||||
parent = directory
|
||||
)
|
||||
|
||||
directory.getNestedModules().forEach { nestedModule ->
|
||||
initializeModule(directoryPath, nestedModule)
|
||||
}
|
||||
}
|
||||
|
||||
val files = parent.getFiles()
|
||||
files.forEach { file ->
|
||||
psiFixture.psiFileFixture(file.getFileName(), file.getFileContent()).init()
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestFixture<Path>.asPsiDirectoryFixture(): TestFixture<PsiDirectory> = testFixture {
|
||||
val dirPath = this@asPsiDirectoryFixture.init()
|
||||
val project = projectFixture.init()
|
||||
val vDir = VfsUtil.findFile(dirPath, true) ?: throw IllegalStateException("Virtual file for path '$dirPath' was not found")
|
||||
val dir = readAction { PsiManager.getInstance(project).findDirectory(vDir) } ?: throw IllegalStateException("PsiDirectory for path '$dirPath' was not found")
|
||||
initialized(dir) {/*nothing to clean up*/ }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user