Skip to content

Commit df18efe

Browse files
volivan239AbdullinAM
authored andcommitted
Select Kotlin test src root by default when generating for Kotlin UnitTestBot#949 (UnitTestBot#1074)
1 parent be9d931 commit df18efe

File tree

5 files changed

+65
-29
lines changed

5 files changed

+65
-29
lines changed

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,8 @@ object CodeGenerationController {
416416
// all test roots for the given test module
417417
val testRoots = runReadAction {
418418
testModule
419-
.suitableTestSourceRoots(this)
420-
.mapNotNull { psiManager.findDirectory(it) }
419+
.suitableTestSourceRoots()
420+
.mapNotNull { psiManager.findDirectory(it.dir) }
421421
}
422422

423423
// return an util class from one of the test source roots or null if no util class was found

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile
1919
import com.intellij.psi.PsiClass
2020
import com.intellij.psi.PsiJavaFile
2121
import com.intellij.refactoring.util.classMembers.MemberInfo
22+
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
2223
import org.jetbrains.kotlin.psi.KtFile
2324
import org.utbot.framework.plugin.api.JavaDocCommentStyle
2425
import org.utbot.framework.util.ConflictTriggers
@@ -56,13 +57,14 @@ data class GenerateTestsModel(
5657
?: error("Could not find module for $newTestSourceRoot")
5758
}
5859

60+
var codegenLanguage = if (srcClasses.all { it is KtUltraLightClass }) CodegenLanguage.KOTLIN else CodegenLanguage.JAVA
61+
5962
var testPackageName: String? = null
6063
lateinit var testFramework: TestFramework
6164
lateinit var mockStrategy: MockStrategyApi
6265
lateinit var mockFramework: MockFramework
6366
lateinit var staticsMocking: StaticsMocking
6467
lateinit var parametrizedTestSource: ParametrizedTestSource
65-
lateinit var codegenLanguage: CodegenLanguage
6668
lateinit var runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour
6769
lateinit var hangingTestsTimeout: HangingTestsTimeout
6870
lateinit var forceStaticMocking: ForceStaticMocking

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ import javax.swing.JSpinner
9595
import javax.swing.text.DefaultFormatter
9696
import org.jetbrains.concurrency.Promise
9797
import org.jetbrains.concurrency.thenRun
98-
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
9998
import org.utbot.common.PathUtil.toPath
10099
import org.utbot.framework.UtSettings
101100
import org.utbot.framework.codegen.ForceStaticMocking
@@ -651,8 +650,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
651650
mockStrategies.isEnabled = areMocksSupported
652651
staticsMocking.isEnabled = areMocksSupported && mockStrategies.item != MockStrategyApi.NO_MOCKS
653652

654-
codegenLanguages.item =
655-
if (model.srcClasses.all { it is KtUltraLightClass }) CodegenLanguage.KOTLIN else CodegenLanguage.JAVA
653+
codegenLanguages.item = model.codegenLanguage
656654

657655
val installedTestFramework = TestFramework.allItems.singleOrNull { it.isInstalled }
658656
currentFrameworkItem = when (parametrizedTestSources.isSelected) {

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt

+17-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import javax.swing.JList
1919
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
2020
import org.utbot.common.PathUtil
2121
import org.utbot.intellij.plugin.models.GenerateTestsModel
22+
import org.utbot.intellij.plugin.ui.utils.TestSourceRoot
2223
import org.utbot.intellij.plugin.ui.utils.addDedicatedTestRoot
2324
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
2425
import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots
@@ -58,9 +59,20 @@ class TestFolderComboWithBrowseButton(private val model: GenerateTestsModel) :
5859
val suggestedModules =
5960
if (model.project.isBuildWithGradle) model.project.allModules() else model.potentialTestModules
6061

61-
val testRoots = suggestedModules.flatMap { it.suitableTestSourceRoots().toList() }.toMutableList()
62+
val testRoots = suggestedModules.flatMap {
63+
it.suitableTestSourceRoots()
64+
}.sortedWith(
65+
compareByDescending<TestSourceRoot> {
66+
// Heuristics: Dirs with language == codegenLanguage should go first
67+
it.expectedLanguage == model.codegenLanguage
68+
}.thenBy {
69+
// Heuristics: User is more likely to choose the shorter path
70+
it.dir.path.length
71+
}
72+
).toMutableList()
73+
6274
// this method is blocked for Gradle, where multiple test modules can exist
63-
model.testModule.addDedicatedTestRoot(testRoots)
75+
model.testModule.addDedicatedTestRoot(testRoots, model.codegenLanguage)
6476

6577
if (testRoots.isNotEmpty()) {
6678
configureRootsCombo(testRoots)
@@ -94,13 +106,12 @@ class TestFolderComboWithBrowseButton(private val model: GenerateTestsModel) :
94106
files.singleOrNull()
95107
}
96108

97-
private fun configureRootsCombo(testRoots: List<VirtualFile>) {
98-
// unfortunately, Gradle creates Kotlin test source root with Java source root type, so type is misleading
109+
private fun configureRootsCombo(testRoots: List<TestSourceRoot>) {
99110
val selectedRoot = testRoots.first()
100111

101112
// do not update model.testModule here, because fake test source root could have been chosen
102-
model.testSourceRoot = selectedRoot
103-
newItemList(testRoots.toSet())
113+
model.testSourceRoot = selectedRoot.dir
114+
newItemList(testRoots.map { it.dir }.toSet())
104115
}
105116

106117
private fun newItemList(comboItems: Set<Any>) {

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt

+42-17
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ import org.jetbrains.kotlin.platform.TargetPlatformVersion
3737

3838
private val logger = KotlinLogging.logger {}
3939

40+
data class TestSourceRoot(
41+
val dir: VirtualFile,
42+
val expectedLanguage: CodegenLanguage
43+
)
44+
4045
/**
4146
* @return jdk version of the module
4247
*/
@@ -60,12 +65,6 @@ fun Module.kotlinTargetPlatform(): TargetPlatformVersion {
6065
?.singleOrNull() ?: error("Can't determine target platform for module $this")
6166
}
6267

63-
fun Module.suitableTestSourceRoots(): List<VirtualFile> =
64-
suitableTestSourceRoots(CodegenLanguage.JAVA) + suitableTestSourceRoots(CodegenLanguage.KOTLIN)
65-
66-
fun Module.suitableTestSourceFolders(): List<SourceFolder> =
67-
suitableTestSourceFolders(CodegenLanguage.JAVA) + suitableTestSourceFolders(CodegenLanguage.KOTLIN)
68-
6968
/**
7069
* Gets a path to test resources source root.
7170
*
@@ -121,8 +120,8 @@ private fun findPotentialModulesForTests(project: Project, srcModule: Module): L
121120
/**
122121
* Finds all suitable test root virtual files.
123122
*/
124-
fun Module.suitableTestSourceRoots(codegenLanguage: CodegenLanguage): List<VirtualFile> {
125-
val sourceRootsInModule = suitableTestSourceFolders(codegenLanguage).mapNotNull { it.file }
123+
fun Module.suitableTestSourceRoots(): List<TestSourceRoot> {
124+
val sourceRootsInModule = suitableTestSourceFolders().mapNotNull { it.testSourceRoot }
126125

127126
if (sourceRootsInModule.isNotEmpty()) {
128127
return sourceRootsInModule
@@ -133,22 +132,30 @@ fun Module.suitableTestSourceRoots(codegenLanguage: CodegenLanguage): List<Virtu
133132
ModuleUtilCore.collectModulesDependsOn(this, dependentModules)
134133

135134
return dependentModules
136-
.flatMap { it.suitableTestSourceFolders(codegenLanguage) }
137-
.mapNotNull { it.file }
135+
.flatMap { it.suitableTestSourceFolders() }
136+
.mapNotNull { it.testSourceRoot }
138137
}
139138

140-
private fun Module.suitableTestSourceFolders(codegenLanguage: CodegenLanguage): List<SourceFolder> {
139+
private val SourceFolder.testSourceRoot:TestSourceRoot?
140+
get() {
141+
val file = file
142+
val expectedLanguage = expectedLanguageForTests
143+
if (file != null && expectedLanguage != null)
144+
return TestSourceRoot(file, expectedLanguage)
145+
return null
146+
}
147+
148+
private fun Module.suitableTestSourceFolders(): List<SourceFolder> {
141149
val sourceFolders = ModuleRootManager.getInstance(this)
142150
.contentEntries
143151
.flatMap { it.sourceFolders.toList() }
144152
.filterNotNull()
145153

146154
return sourceFolders
147155
.filterNot { it.isForGeneratedSources() }
148-
.filter { it.rootType == codegenLanguage.testRootType() }
149-
// Heuristics: User is more likely to choose the shorter path
150-
.sortedBy { it.url.length }
156+
.filter { it.isTestSource }
151157
}
158+
152159
private val GRADLE_SYSTEM_ID = ProjectSystemId("GRADLE")
153160

154161
val Project.isBuildWithGradle get() =
@@ -157,19 +164,20 @@ val Project.isBuildWithGradle get() =
157164
}
158165

159166
private const val dedicatedTestSourceRootName = "utbot_tests"
160-
fun Module.addDedicatedTestRoot(testSourceRoots: MutableList<VirtualFile>): VirtualFile? {
167+
168+
fun Module.addDedicatedTestRoot(testSourceRoots: MutableList<TestSourceRoot>, language: CodegenLanguage): VirtualFile? {
161169
// Don't suggest new test source roots for Gradle project where 'unexpected' test roots won't work
162170
if (project.isBuildWithGradle) return null
163171
// Dedicated test root already exists
164-
if (testSourceRoots.any { file -> file.name == dedicatedTestSourceRootName }) return null
172+
if (testSourceRoots.any { root -> root.dir.name == dedicatedTestSourceRootName }) return null
165173

166174
val moduleInstance = ModuleRootManager.getInstance(this)
167175
val testFolder = moduleInstance.contentEntries.flatMap { it.sourceFolders.toList() }
168176
.firstOrNull { it.rootType in testSourceRootTypes }
169177
(testFolder?.let { testFolder.file?.parent }
170178
?: testFolder?.contentEntry?.file ?: this.guessModuleDir())?.let {
171179
val file = FakeVirtualFile(it, dedicatedTestSourceRootName)
172-
testSourceRoots.add(file)
180+
testSourceRoots.add(TestSourceRoot(file, language))
173181
// We return "true" IFF it's case of not yet created fake directory
174182
return if (VfsUtil.findRelativeFile(it, dedicatedTestSourceRootName) == null) file else null
175183
}
@@ -275,3 +283,20 @@ private fun jdkVersionBy(sdk: Sdk?): JavaSdkVersion {
275283
}
276284
return jdkVersion
277285
}
286+
287+
private val SourceFolder.expectedLanguageForTests: CodegenLanguage?
288+
get() {
289+
// unfortunately, Gradle creates Kotlin test source root with Java source root type, so type is misleading,
290+
// and we should try looking for name first
291+
if (file?.name == "kotlin")
292+
return CodegenLanguage.KOTLIN
293+
294+
if (file?.name == "java")
295+
return CodegenLanguage.JAVA
296+
297+
return when (rootType) {
298+
CodegenLanguage.KOTLIN.testRootType() -> CodegenLanguage.KOTLIN
299+
CodegenLanguage.JAVA.testRootType() -> CodegenLanguage.JAVA
300+
else -> null
301+
}
302+
}

0 commit comments

Comments
 (0)