Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,7 @@ open class TypeParameters(val parameters: List<ClassId> = emptyList())
class WildcardTypeParameter : TypeParameters(emptyList())

interface CodeGenerationSettingItem {
val id : String
val displayName: String
val description: String
}
Expand All @@ -1120,20 +1121,23 @@ interface CodeGenerationSettingBox {
}

enum class MockStrategyApi(
override val id : String,
override val displayName: String,
override val description: String
) : CodeGenerationSettingItem {
NO_MOCKS("Do not mock", "Do not use mock frameworks at all"),
NO_MOCKS("No mocks", "Do not mock", "Do not use mock frameworks at all"),
OTHER_PACKAGES(
"Other packages: Mockito",
"Mock package environment",
"Mock all classes outside the current package except system ones"
),
OTHER_CLASSES(
"Other classes: Mockito",
"Mock class environment",
"Mock all classes outside the class under test except system ones"
);

override fun toString() = displayName
override fun toString() = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand All @@ -1144,20 +1148,23 @@ enum class MockStrategyApi(
}

enum class TreatOverflowAsError(
override val id : String,
override val displayName: String,
override val description: String,
) : CodeGenerationSettingItem {
AS_ERROR(
id = "Treat overflows as errors",
displayName = "Treat overflows as errors",
description = "Generate tests that treat possible overflows in arithmetic operations as errors " +
"that throw Arithmetic Exception",
),
IGNORE(
id = "Ignore overflows",
displayName = "Ignore overflows",
description = "Ignore possible overflows in arithmetic operations",
);

override fun toString(): String = displayName
override fun toString(): String = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand All @@ -1168,13 +1175,14 @@ enum class TreatOverflowAsError(
}

enum class MockFramework(
override val id: String = "Mockito",
override val displayName: String,
override val description: String = "Use $displayName as mock framework",
var isInstalled: Boolean = false
) : CodeGenerationSettingItem {
MOCKITO("Mockito");
MOCKITO(displayName = "Mockito");

override fun toString() = displayName
override fun toString() = id

companion object : CodeGenerationSettingBox {
override val defaultItem: MockFramework = MOCKITO
Expand All @@ -1183,11 +1191,12 @@ enum class MockFramework(
}

enum class CodegenLanguage(
override val id: String,
override val displayName: String,
@Suppress("unused") override val description: String = "Generate unit tests in $displayName"
) : CodeGenerationSettingItem {
JAVA(displayName = "Java"),
KOTLIN(displayName = "Kotlin (experimental)");
JAVA(id = "Java", displayName = "Java"),
KOTLIN(id = "Kotlin", displayName = "Kotlin (experimental)");

enum class OperatingSystem {
WINDOWS,
Expand Down Expand Up @@ -1226,7 +1235,7 @@ enum class CodegenLanguage(
KOTLIN -> listOf(System.getenv("JAVA_HOME"), "bin", "java")
}.joinToString(File.separator)

override fun toString(): String = displayName
override fun toString(): String = id

fun getCompilationCommand(buildDirectory: String, classPath: String, sourcesFiles: List<String>): List<String> {
val arguments = when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ fun testFrameworkByName(testFramework: String): TestFramework =
*/
sealed class StaticsMocking(
var isConfigured: Boolean = false,
override val id: String,
override val displayName: String,
override val description: String = "Use static methods mocking"
) : CodeGenerationSettingItem {
override fun toString(): String = displayName
override fun toString(): String = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand All @@ -119,11 +120,12 @@ sealed class StaticsMocking(
}

object NoStaticMocking : StaticsMocking(
id = "No static mocking",
displayName = "No static mocking",
description = "Do not use additional settings to mock static fields"
)

object MockitoStaticMocking : StaticsMocking(displayName = "Mockito static mocking") {
object MockitoStaticMocking : StaticsMocking(id = "Mockito static mocking", displayName = "Mockito static mocking") {

val mockedStaticClassId = BuiltinClassId(
name = "org.mockito.MockedStatic",
Expand Down Expand Up @@ -170,6 +172,7 @@ object MockitoStaticMocking : StaticsMocking(displayName = "Mockito static mocki
}

sealed class TestFramework(
override val id: String,
override val displayName: String,
override val description: String = "Use $displayName as test framework",
) : CodeGenerationSettingItem {
Expand Down Expand Up @@ -235,7 +238,7 @@ sealed class TestFramework(
additionalArguments: List<String>
): List<String>

override fun toString() = displayName
override fun toString() = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value, i.e. allItems = [null, JUnit5, TestNg]
Expand All @@ -246,7 +249,7 @@ sealed class TestFramework(
}
}

object TestNg : TestFramework(displayName = "TestNG") {
object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
override val mainPackage: String = TEST_NG_PACKAGE
override val testAnnotation: String = "@$mainPackage.Test"
override val testAnnotationFqn: String = "$mainPackage.Test"
Expand Down Expand Up @@ -375,7 +378,7 @@ object TestNg : TestFramework(displayName = "TestNG") {
""".trimIndent()
}

object Junit4 : TestFramework("JUnit4") {
object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit4") {
private val parametrizedTestsNotSupportedError: Nothing
get() = error("Parametrized tests are not supported for JUnit4")

Expand Down Expand Up @@ -448,7 +451,7 @@ object Junit4 : TestFramework("JUnit4") {
}
}

object Junit5 : TestFramework("JUnit5") {
object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit5") {
override val mainPackage: String = JUNIT5_PACKAGE
override val testAnnotation = "@$mainPackage.Test"
override val testAnnotationFqn: String = "$mainPackage.Test"
Expand Down Expand Up @@ -589,20 +592,23 @@ object Junit5 : TestFramework("JUnit5") {
}

enum class RuntimeExceptionTestsBehaviour(
override val id: String,
override val displayName: String,
override val description: String
) : CodeGenerationSettingItem {
PASS(
id = "Passing",
displayName = "Pass",
description = "Tests that produce Runtime exceptions should pass (by inserting throwable assertion)"
),
FAIL(
id = "Failing",
displayName = "Fail",
description = "Tests that produce Runtime exceptions should fail" +
"(WARNING!: failing tests may appear in testing class)"
);

override fun toString(): String = displayName
override fun toString(): String = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand All @@ -623,11 +629,13 @@ data class HangingTestsTimeout(val timeoutMs: Long) {
}

enum class ForceStaticMocking(
override val id: String,
override val displayName: String,
override val description: String,
val warningMessage: List<String>,
) : CodeGenerationSettingItem {
FORCE(
id = "Force static mocking",
displayName = "Force static mocking",
description = "Use mocks for static methods and constructors invocations even if static mocking is disabled" +
"(WARNING!: can add imports from missing dependencies)",
Expand All @@ -638,6 +646,7 @@ enum class ForceStaticMocking(
)
),
DO_NOT_FORCE(
id = "Do not force static mocking",
displayName = "Do not force static mocking",
description = "Do not force static mocking if static mocking setting is disabled" +
"(WARNING!: flaky tests can appear)",
Expand All @@ -647,7 +656,7 @@ enum class ForceStaticMocking(
)
);

override fun toString(): String = displayName
override fun toString(): String = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand All @@ -658,19 +667,22 @@ enum class ForceStaticMocking(
}

enum class ParametrizedTestSource(
override val id: String,
override val displayName: String,
override val description: String = "Use $displayName for parametrized tests"
) : CodeGenerationSettingItem {
DO_NOT_PARAMETRIZE(
id = "Not parametrized",
displayName = "Not parametrized",
description = "Do not generate parametrized tests"
),
PARAMETRIZE(
id = "Parametrized",
displayName = "Parametrized",
description = "Generate parametrized tests"
);

override fun toString(): String = displayName
override fun toString(): String = id

// Get is mandatory because of the initialization order of the inheritors.
// Otherwise, in some cases we could get an incorrect value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.utbot.framework.codegen.RuntimeExceptionTestsBehaviour
import org.utbot.framework.plugin.api.CodeGenerationSettingItem
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.TreatOverflowAsError
import org.utbot.intellij.plugin.ui.components.CodeGenerationSettingItemRenderer

class SettingsWindow(val project: Project) {
private val settings = project.service<Settings>()
Expand All @@ -36,7 +37,7 @@ class SettingsWindow(val project: Project) {
val valuesComboBox: LayoutBuilder.(KClass<*>, Array<*>) -> Unit = { loader, values ->
val serviceLabels = mapOf(
CodegenLanguage::class to "Generated test language:",
RuntimeExceptionTestsBehaviour::class to "Test with exceptions:",
RuntimeExceptionTestsBehaviour::class to "Tests with exceptions:",
TreatOverflowAsError::class to "Overflow detection:",
)
val tooltipLabels = mapOf(
Expand All @@ -49,7 +50,10 @@ class SettingsWindow(val project: Project) {
DefaultComboBoxModel(values),
getter = { settings.providerNameByServiceLoader(loader) },
setter = { settings.setProviderByLoader(loader, it as CodeGenerationSettingItem) },
).apply { ContextHelpLabel.create(tooltipLabels[loader] ?: return@apply)() }
).apply {
component.renderer = CodeGenerationSettingItemRenderer()
ContextHelpLabel.create(tooltipLabels[loader] ?: return@apply)()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import org.utbot.intellij.plugin.models.mockitoCoreLibraryDescriptor
import org.utbot.intellij.plugin.models.packageName
import org.utbot.intellij.plugin.models.testNgLibraryDescriptor
import org.utbot.intellij.plugin.settings.Settings
import org.utbot.intellij.plugin.ui.components.CodeGenerationSettingItemRenderer
import org.utbot.intellij.plugin.ui.components.TestFolderComboWithBrowseButton
import org.utbot.intellij.plugin.ui.utils.LibrarySearchScope
import org.utbot.intellij.plugin.ui.utils.addSourceRootIfAbsent
Expand Down Expand Up @@ -168,9 +169,9 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m

private val testSourceFolderField = TestFolderComboWithBrowseButton(model)

private val codegenLanguages = ComboBox(DefaultComboBoxModel(CodegenLanguage.values()))
private val testFrameworks = ComboBox(DefaultComboBoxModel(TestFramework.allItems.toTypedArray()))
private val mockStrategies = ComboBox(DefaultComboBoxModel(MockStrategyApi.values()))
private val codegenLanguages = createComboBox(CodegenLanguage.values())
private val testFrameworks = createComboBox(TestFramework.allItems.toTypedArray())
private val mockStrategies = createComboBox(MockStrategyApi.values())
private val staticsMocking = JCheckBox("Mock static methods")
private val timeoutSpinner =
JBIntSpinner(
Expand All @@ -191,6 +192,12 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
parametrizedTestSources to null
)

private fun <T : CodeGenerationSettingItem> createComboBox(values: Array<T>) : ComboBox<T> {
return ComboBox<T>(DefaultComboBoxModel(values)).also {
it.renderer = CodeGenerationSettingItemRenderer()
}
}

private fun createHelpLabel(commonTooltip: String? = null) = JBLabel(AllIcons.General.ContextHelp).apply {
if (!commonTooltip.isNullOrEmpty()) toolTipText = commonTooltip
}
Expand Down Expand Up @@ -239,22 +246,16 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
row("Test source root:") {
component(testSourceFolderField)
}
row("Code generation language:") {
makePanelWithHelpTooltip(
codegenLanguages as ComboBox<CodeGenerationSettingItem>,
itemsToHelpTooltip[codegenLanguages]
)
}.visible = false
row("Testing framework:") {
makePanelWithHelpTooltip(
testFrameworks as ComboBox<CodeGenerationSettingItem>,
testFrameworks,
null
)
}
row { component(parametrizedTestSources) }
row("Mock strategy:") {
makePanelWithHelpTooltip(
mockStrategies as ComboBox<CodeGenerationSettingItem>,
mockStrategies,
ContextHelpLabel.create("Mock everything around the target class or the whole package except the system classes. Otherwise mock nothing.")
)
}
Expand Down Expand Up @@ -956,11 +957,11 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
testFrameworks.item = if (currentFrameworkItem in enabledTestFrameworks) currentFrameworkItem else defaultItem
testFrameworks.renderer = object : ColoredListCellRenderer<TestFramework>() {
override fun customizeCellRenderer(
list: JList<out TestFramework>, value: TestFramework?,
list: JList<out TestFramework>, value: TestFramework,
index: Int, selected: Boolean, hasFocus: Boolean
) {
this.append(value.toString(), SimpleTextAttributes.REGULAR_ATTRIBUTES)
if (value == null || !value.isInstalled) {
this.append(value.displayName, SimpleTextAttributes.REGULAR_ATTRIBUTES)
if (!value.isInstalled) {
this.append(WILL_BE_INSTALLED_LABEL, SimpleTextAttributes.ERROR_ATTRIBUTES)
}
}
Expand All @@ -981,10 +982,10 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
private fun updateMockStrategyList() {
mockStrategies.renderer = object : ColoredListCellRenderer<MockStrategyApi>() {
override fun customizeCellRenderer(
list: JList<out MockStrategyApi>, value: MockStrategyApi?,
list: JList<out MockStrategyApi>, value: MockStrategyApi,
index: Int, selected: Boolean, hasFocus: Boolean
) {
this.append(value.toString(), SimpleTextAttributes.REGULAR_ATTRIBUTES)
this.append(value.displayName, SimpleTextAttributes.REGULAR_ATTRIBUTES)
if (value != MockStrategyApi.NO_MOCKS && !MOCKITO.isInstalled) {
this.append(WILL_BE_INSTALLED_LABEL, SimpleTextAttributes.ERROR_ATTRIBUTES)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.utbot.intellij.plugin.ui.components

import java.awt.Component
import javax.swing.DefaultListCellRenderer
import javax.swing.JList
import org.utbot.framework.plugin.api.CodeGenerationSettingItem

internal class CodeGenerationSettingItemRenderer : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
value: Any?,
index: Int,
isSelected: Boolean,
cellHasFocus: Boolean
): Component {
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus).apply {
if (value is CodeGenerationSettingItem) {
text = value.displayName
}
}
}
}