mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[extract module action] fixes - remove illegal usage of junit5 - extract duplicated code - specify the return type of getActionUpdateThread - fix properties' naming - fix the dialog message [extract module action] Replace AbstractDependencyVisitor with JvmBytecodeAnalysis; bazel; unignore test [extract module action] Extract Module From Package Action - Use classfiles instead of psi - Tests - Coroutines Co-authored-by: Kirill Bochkarev <kirill.bochkarev@jetbrains.com> Merge-request: IJ-MR-163922 Merged-by: Kirill Bochkarev <kirill.bochkarev@jetbrains.com> GitOrigin-RevId: 03cf1754a17d5a9e819ea8cfe812ca2e0a1855e0
155 lines
7.8 KiB
Kotlin
155 lines
7.8 KiB
Kotlin
// 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.ide.projectView.actions
|
|
|
|
import com.intellij.ide.extractModule.ExtractModuleService
|
|
import com.intellij.openapi.application.runReadAction
|
|
import com.intellij.openapi.compiler.CompilerMessageCategory
|
|
import com.intellij.openapi.components.service
|
|
import com.intellij.openapi.module.Module
|
|
import com.intellij.openapi.module.ModuleManager
|
|
import com.intellij.openapi.roots.DependencyScope
|
|
import com.intellij.openapi.roots.ModuleRootManager
|
|
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
|
import com.intellij.openapi.vfs.LocalFileSystem
|
|
import com.intellij.psi.PsiDirectory
|
|
import com.intellij.psi.PsiManager
|
|
import com.intellij.testFramework.ApplicationRule
|
|
import com.intellij.testFramework.CompilerTester
|
|
import com.intellij.testFramework.DisposableRule
|
|
import com.intellij.testFramework.VfsTestUtil
|
|
import com.intellij.testFramework.rules.ProjectModelRule
|
|
import kotlinx.coroutines.runBlocking
|
|
import org.assertj.core.api.Assertions.assertThat
|
|
import org.assertj.core.api.SoftAssertions
|
|
import org.jetbrains.jps.model.java.JavaSourceRootType
|
|
import org.junit.ClassRule
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import java.nio.file.Path
|
|
import kotlin.io.path.invariantSeparatorsPathString
|
|
|
|
class ExtractModuleFromPackageActionTest {
|
|
companion object {
|
|
@JvmField
|
|
@ClassRule
|
|
val appRule = ApplicationRule()
|
|
}
|
|
|
|
@Rule
|
|
@JvmField
|
|
val projectModel = ProjectModelRule()
|
|
|
|
@Rule
|
|
@JvmField
|
|
val disposableRule = DisposableRule()
|
|
|
|
@Test
|
|
fun `extract module in place`() {
|
|
val (main, directory) = prepareProject()
|
|
|
|
extractModule(directory, main, null)
|
|
val xxx = projectModel.moduleManager.findModuleByName("main.xxx")!!
|
|
val dep1 = projectModel.moduleManager.findModuleByName("dep1")!!
|
|
val dep2 = projectModel.moduleManager.findModuleByName("dep2")!!
|
|
assertThat(xxx.moduleNioFile).isEqualTo(projectModel.baseProjectDir.rootPath.resolve("main/main.xxx.iml"))
|
|
val xxxRoots = ModuleRootManager.getInstance(xxx)
|
|
assertThat(xxxRoots.sourceRoots).containsExactly(directory.virtualFile)
|
|
assertThat(xxxRoots.dependencies).containsExactly(dep1)
|
|
assertThat(xxxRoots.contentEntries.single().sourceFolders.single().packagePrefix).isEqualTo("xxx")
|
|
val mainRoots = ModuleRootManager.getInstance(main)
|
|
assertThat(mainRoots.dependencies).containsExactly(dep2)
|
|
}
|
|
|
|
@Test
|
|
fun `extract module to separate directory`() {
|
|
val (main, directory) = prepareProject()
|
|
|
|
val targetSourceRoot = projectModel.baseProjectDir.rootPath.resolve("xxx/src").invariantSeparatorsPathString
|
|
extractModule(directory, main, targetSourceRoot)
|
|
val srcRoot = LocalFileSystem.getInstance().findFileByPath(targetSourceRoot)!!
|
|
val xxx = projectModel.moduleManager.findModuleByName("main.xxx")!!
|
|
assertThat(xxx.moduleNioFile).isEqualTo(projectModel.baseProjectDir.rootPath.resolve("xxx/main.xxx.iml"))
|
|
val xxxRoots = ModuleRootManager.getInstance(xxx)
|
|
assertThat(xxxRoots.contentRoots).containsExactly(srcRoot.parent)
|
|
assertThat(xxxRoots.sourceRoots).containsExactly(srcRoot)
|
|
assertThat(xxxRoots.contentEntries.single().sourceFolders.single().packagePrefix).isEqualTo("")
|
|
assertThat(Path.of(targetSourceRoot, "xxx/Main.java")).exists()
|
|
assertThat(projectModel.baseProjectDir.rootPath.resolve("main/src/xxx/Main.java")).doesNotExist()
|
|
}
|
|
|
|
@Test
|
|
fun `extract module and replace by exported dependency`() {
|
|
val (main, directory) = prepareProject(addDirectUsageOfExportedModule = true)
|
|
|
|
extractModule(directory, main, null)
|
|
val exported = projectModel.moduleManager.findModuleByName("exported")!!
|
|
val dep2 = projectModel.moduleManager.findModuleByName("dep2")!!
|
|
val mainRoots = ModuleRootManager.getInstance(main)
|
|
assertThat(mainRoots.dependencies).containsExactly(dep2, exported)
|
|
}
|
|
|
|
@Test
|
|
fun `add dependencies from others modules after extracting`() {
|
|
val (main, directory) = prepareProject()
|
|
val otherModuleWithoutReference = projectModel.createModule("otherWithoutReference")
|
|
|
|
val otherModuleWithReference = projectModel.createModule("otherWithReference")
|
|
projectModel.addSourceRoot(otherModuleWithReference, "src", JavaSourceRootType.SOURCE).let {
|
|
VfsTestUtil.createFile(it, "other/Other.java", "package other;\npublic class Other { main.MyClass myClass; xxx.Main main; }")
|
|
}
|
|
|
|
val otherModuleWithReferenceOnExtractedOnly = projectModel.createModule("otherWithReferenceOnExtracedOnly")
|
|
projectModel.addSourceRoot(otherModuleWithReferenceOnExtractedOnly, "src", JavaSourceRootType.SOURCE).let {
|
|
VfsTestUtil.createFile(it, "other2/Other2.java", "package other2;\npublic class Other2 { xxx.Main other2; }")
|
|
}
|
|
|
|
ModuleRootModificationUtil.addDependency(otherModuleWithoutReference, main)
|
|
ModuleRootModificationUtil.addDependency(otherModuleWithReference, main)
|
|
ModuleRootModificationUtil.addDependency(otherModuleWithReferenceOnExtractedOnly, main)
|
|
|
|
extractModule(directory, main, null)
|
|
val extracted = projectModel.moduleManager.findModuleByName("main.xxx")!!
|
|
|
|
with(SoftAssertions()) {
|
|
assertThat(ModuleRootManager.getInstance(otherModuleWithReference).dependencies).containsExactly(main, extracted)
|
|
assertThat(ModuleRootManager.getInstance(otherModuleWithoutReference).dependencies).containsExactly(main)
|
|
assertThat(ModuleRootManager.getInstance(otherModuleWithReferenceOnExtractedOnly).dependencies).containsExactly(extracted)
|
|
assertAll()
|
|
}
|
|
}
|
|
|
|
private fun extractModule(directory: PsiDirectory, main: Module, targetSourceRoot: String?) {
|
|
val compilerTester = CompilerTester(projectModel.project, ModuleManager.getInstance(projectModel.project).modules.toList(), disposableRule.disposable)
|
|
val messages = compilerTester.rebuild()
|
|
assertThat(messages.filter { it.category == CompilerMessageCategory.ERROR }).isEmpty()
|
|
runBlocking {
|
|
projectModel.project.service<ExtractModuleService>().extractModuleFromDirectory(directory, main, "main.xxx",
|
|
targetSourceRoot)
|
|
}
|
|
}
|
|
|
|
private fun prepareProject(addDirectUsageOfExportedModule: Boolean = false): Pair<Module, PsiDirectory> {
|
|
val main = projectModel.createModule("main")
|
|
val dep1 = projectModel.createModule("dep1")
|
|
val dep2 = projectModel.createModule("dep2")
|
|
val exported = projectModel.createModule("exported")
|
|
ModuleRootModificationUtil.addDependency(main, dep1)
|
|
ModuleRootModificationUtil.addDependency(dep1, exported, DependencyScope.COMPILE, true)
|
|
ModuleRootModificationUtil.addDependency(main, dep2)
|
|
val mainSrc = projectModel.addSourceRoot(main, "src", JavaSourceRootType.SOURCE)
|
|
val dep1Src = projectModel.addSourceRoot(dep1, "src", JavaSourceRootType.SOURCE)
|
|
val dep2Src = projectModel.addSourceRoot(dep2, "src", JavaSourceRootType.SOURCE)
|
|
val exportedSrc = projectModel.addSourceRoot(exported, "src", JavaSourceRootType.SOURCE)
|
|
val mainClass = VfsTestUtil.createFile(mainSrc, "xxx/Main.java", "package xxx;\npublic class Main extends dep1.Dep1 { exported.Util u; }")
|
|
VfsTestUtil.createFile(mainSrc, "main/MyClass.java", "package main;\npublic class MyClass { dep2.Dep2 d; }")
|
|
if (addDirectUsageOfExportedModule) {
|
|
VfsTestUtil.createFile(mainSrc, "main/ExportedUsage.java", "package main;\nclass ExportedUsage { exported.Util u; }")
|
|
}
|
|
VfsTestUtil.createFile(dep1Src, "dep1/Dep1.java", "package dep1;\npublic class Dep1 {}")
|
|
VfsTestUtil.createFile(dep2Src, "dep2/Dep2.java", "package dep2;\npublic class Dep2 {}")
|
|
VfsTestUtil.createFile(exportedSrc, "exported/Util.java", "package exported;\npublic class Util {}")
|
|
|
|
val directory = runReadAction { PsiManager.getInstance(projectModel.project).findDirectory(mainClass.parent)!! }
|
|
return Pair(main, directory)
|
|
}
|
|
} |