Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Computable
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.*
import com.intellij.psi.codeStyle.CodeStyleManager
Expand Down Expand Up @@ -73,6 +74,9 @@ import java.nio.file.Path
import java.util.concurrent.CancellationException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.utbot.intellij.plugin.ui.utils.TestSourceRoot
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle

object CodeGenerationController {
private val logger = KotlinLogging.logger {}
Expand Down Expand Up @@ -433,6 +437,12 @@ object CodeGenerationController {
}
}

fun GenerateTestsModel.getAllTestSourceRoots() : MutableList<TestSourceRoot> {
with(if (project.isBuildWithGradle) project.allModules() else potentialTestModules) {
return this.flatMap { it.suitableTestSourceRoots().toList() }.toMutableList()
}
}

private val CodegenLanguage.utilClassFileName: String
get() = "$UT_UTILS_CLASS_NAME${this.extension}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ import org.utbot.intellij.plugin.process.EngineProcess
import org.utbot.intellij.plugin.process.RdTestGenerationResult
import org.utbot.intellij.plugin.settings.Settings
import org.utbot.intellij.plugin.ui.GenerateTestsDialogWindow
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater
import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots
import org.utbot.intellij.plugin.ui.utils.testModules
import org.utbot.intellij.plugin.util.*
import org.utbot.rd.terminateOnException
Expand All @@ -48,6 +46,7 @@ import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import kotlin.io.path.pathString
import org.utbot.intellij.plugin.generator.CodeGenerationController.getAllTestSourceRoots
import org.utbot.framework.plugin.api.util.LockFile

object UtTestsDialogProcessor {
Expand Down Expand Up @@ -92,7 +91,16 @@ object UtTestsDialogProcessor {
// we want to start the child process in the same directory as the test runner
WorkingDirService.workingDirProvider = PluginWorkingDirProvider(project)

if (project.isBuildWithGradle && testModules.flatMap { it.suitableTestSourceRoots() }.isEmpty()) {
val model = GenerateTestsModel(
project,
srcModule,
testModules,
srcClasses,
extractMembersFromSrcClasses,
focusedMethods,
UtSettings.utBotGenerationTimeoutInMillis,
)
if (model.getAllTestSourceRoots().isEmpty()) {
val errorMessage = """
<html>No test source roots found in the project.<br>
Please, <a href="https://www.jetbrains.com/help/idea/testing.html#add-test-root">create or configure</a> at least one test source root.
Expand All @@ -101,17 +109,7 @@ object UtTestsDialogProcessor {
return null
}

return GenerateTestsDialogWindow(
GenerateTestsModel(
project,
srcModule,
testModules,
srcClasses,
extractMembersFromSrcClasses,
focusedMethods,
UtSettings.utBotGenerationTimeoutInMillis,
)
)
return GenerateTestsDialogWindow(model)
}

private fun createTests(project: Project, model: GenerateTestsModel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.ui.ComboBox
import com.intellij.openapi.ui.ComponentWithBrowseButton
import com.intellij.openapi.ui.FixedSizeButton
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile
import com.intellij.ui.ColoredListCellRenderer
Expand All @@ -16,13 +17,13 @@ import com.intellij.util.ui.UIUtil
import java.io.File
import javax.swing.DefaultComboBoxModel
import javax.swing.JList
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.idea.util.rootManager
import org.utbot.common.PathUtil
import org.utbot.intellij.plugin.generator.CodeGenerationController.getAllTestSourceRoots
import org.utbot.intellij.plugin.models.GenerateTestsModel
import org.utbot.intellij.plugin.ui.utils.TestSourceRoot
import org.utbot.intellij.plugin.ui.utils.addDedicatedTestRoot
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots

class TestFolderComboWithBrowseButton(private val model: GenerateTestsModel) :
ComponentWithBrowseButton<ComboBox<Any>>(ComboBox(), null) {
Expand Down Expand Up @@ -56,20 +57,40 @@ class TestFolderComboWithBrowseButton(private val model: GenerateTestsModel) :
}
}

val suggestedModules =
if (model.project.isBuildWithGradle) model.project.allModules() else model.potentialTestModules

val testRoots = suggestedModules.flatMap {
it.suitableTestSourceRoots()
}.sortedWith(
var commonModuleSourceDirectory = ""
for ((i, sourceRoot) in model.srcModule.rootManager.sourceRoots.withIndex()) {
commonModuleSourceDirectory = if (i == 0) {
sourceRoot.toNioPath().toString()
} else {
StringUtil.commonPrefix(commonModuleSourceDirectory, sourceRoot.toNioPath().toString())
}
}
// The first sorting to obtain the best candidate
val testRoots = model.getAllTestSourceRoots().distinct().sortedWith(
compareByDescending<TestSourceRoot> {
// Heuristics: Dirs with language == codegenLanguage should go first
it.expectedLanguage == model.codegenLanguage
}.thenBy {
// Heuristics: User is more likely to choose the shorter path
it.dir.path.length
// Heuristics: move root that is 'closer' to module 'common' directory to the first position
StringUtil.commonPrefixLength(commonModuleSourceDirectory, it.dir.toNioPath().toString())
}).toMutableList()

val theBest = if (testRoots.isNotEmpty()) testRoots[0] else null

// The second sorting to make full list ordered
testRoots.sortWith(compareByDescending<TestSourceRoot> {
// Heuristics: Dirs with language == codegenLanguage should go first
it.expectedLanguage == model.codegenLanguage
}.thenBy {
// ABC-sorting
it.dir.toNioPath()
}
).toMutableList()
)
// The best candidate should go first to be pre-selected
theBest?.let {
testRoots.remove(it)
testRoots.add(0, it)
}

// this method is blocked for Gradle, where multiple test modules can exist
model.testModule.addDedicatedTestRoot(testRoots, model.codegenLanguage)
Expand Down