From dfc869a7234de3b4dae2a3e4cc891aab8bab0c51 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Fri, 7 Apr 2023 14:54:14 +0300 Subject: [PATCH 1/3] Update source code compatibility with IDEA 2023.1 API #2109 --- gradle.properties | 8 +- .../plugin/language/js/JsDialogProcessor.kt | 2 +- .../generator/UtTestsDialogProcessor.kt | 2 +- .../inspection/UnitTestBotInspectionTool.kt | 2 +- .../plugin/settings/SettingsWindow.kt | 246 ++++++++---------- .../plugin/ui/GenerateTestsDialogWindow.kt | 172 +++++++----- 6 files changed, 223 insertions(+), 209 deletions(-) diff --git a/gradle.properties b/gradle.properties index 59862181bb..2c2903607e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ kotlin.code.style=official # IU, IC, PC, PY # IC for AndroidStudio ideType=IC -ideVersion=223.8617.56 +ideVersion=231.8109.175 # ALL, NOJS buildType=NOJS @@ -16,11 +16,11 @@ goIde=IU #androidStudioPath=your_path_to_android_studio # Version numbers: https://plugins.jetbrains.com/plugin/7322-python-community-edition/versions -pythonCommunityPluginVersion=223.7571.182 +pythonCommunityPluginVersion=231.8109.144 # Version numbers: https://plugins.jetbrains.com/plugin/631-python/versions -pythonUltimatePluginVersion=223.7571.182 +pythonUltimatePluginVersion=231.8109.175 # Version numbers: https://plugins.jetbrains.com/plugin/9568-go/versions -goPluginVersion=223.7571.182 +goPluginVersion=231.8109.175 junit5Version=5.8.2 junit4Version=4.13.2 diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt index e695e347a0..ba0cff9b85 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt @@ -201,7 +201,7 @@ object JsDialogProcessor { testDir.add(temp) testDir.findFile(testFileName)!! } - val testFileEditor = CodeInsightUtil.positionCursor(project, testPsiFile, testPsiFile) + val testFileEditor = CodeInsightUtil.positionCursor(project, testPsiFile, testPsiFile) as Editor unblockDocument(project, testFileEditor.document) testFileEditor.document.setText(generatedCode) unblockDocument(project, testFileEditor.document) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt index cd1958d82f..f2adae134b 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt @@ -25,7 +25,6 @@ import com.intellij.task.impl.ProjectTaskList import com.intellij.util.concurrency.AppExecutorUtil import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.nullize -import com.intellij.util.io.exists import java.io.File import java.nio.file.Path import java.nio.file.Paths @@ -34,6 +33,7 @@ import java.time.format.DateTimeFormatter import java.util.Arrays import java.util.concurrent.TimeUnit import java.util.stream.Collectors +import kotlin.io.path.exists import kotlin.io.path.pathString import mu.KotlinLogging import org.jetbrains.concurrency.Promise diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/inspection/UnitTestBotInspectionTool.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/inspection/UnitTestBotInspectionTool.kt index e32b540bbe..ad1e36fb73 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/inspection/UnitTestBotInspectionTool.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/inspection/UnitTestBotInspectionTool.kt @@ -95,7 +95,7 @@ class UnitTestBotInspectionTool : GlobalSimpleInspectionTool() { sarifResultMessage, ProblemHighlightType.ERROR, /* onTheFly = */ true, - viewGeneratedTestFix, + viewGeneratedTestFix as LocalQuickFix, analyzeStackTraceFix ) problemDescriptionsProcessor.addProblemElement( diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt index c6f5bb8ea3..9353e5a07a 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt @@ -5,16 +5,14 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.DialogPanel import com.intellij.ui.ContextHelpLabel -import com.intellij.ui.components.ActionLink import com.intellij.ui.components.JBLabel -import com.intellij.ui.layout.CCFlags -import com.intellij.ui.layout.LayoutBuilder -import com.intellij.ui.layout.PropertyBinding -import com.intellij.ui.layout.labelTable -import com.intellij.ui.layout.panel +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.bindIntValue +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.bindValue +import com.intellij.ui.dsl.builder.labelTable +import com.intellij.ui.dsl.builder.panel import com.intellij.ui.layout.selectedValueMatches -import com.intellij.ui.layout.slider -import com.intellij.ui.layout.withValueBinding import com.intellij.util.ui.UIUtil import com.intellij.util.ui.components.BorderLayoutPanel import org.utbot.framework.SummariesGenerationType @@ -47,23 +45,21 @@ class SettingsWindow(val project: Project) { val panel: JPanel = panel { row("Generated test language:") { - cell { - codegenLanguageCombo = comboBox( - DefaultComboBoxModel(CodegenLanguage.values()), - getter = { settings.providerNameByServiceLoader(CodegenLanguage::class) as CodegenLanguage }, - setter = { settings.setProviderByLoader(CodegenLanguage::class, it as CodeGenerationSettingItem) } - ).apply { - component.renderer = CodeGenerationSettingItemRenderer() - ContextHelpLabel.create("You can generate test methods in Java or Kotlin regardless of your source code language.") - }.component - codegenLanguageCombo.addActionListener { - if (!codegenLanguageCombo.item.isSummarizationCompatible()) { - enableSummarizationGenerationCheckBox.isSelected = false - } + codegenLanguageCombo = comboBox(DefaultComboBoxModel(CodegenLanguage.values())) + .apply { + component.renderer = CodeGenerationSettingItemRenderer() + ContextHelpLabel.create("You can generate test methods in Java or Kotlin regardless of your source code language.") + }.bindItem( + getter = { settings.providerNameByServiceLoader(CodegenLanguage::class) as CodegenLanguage }, + setter = { settings.setProviderByLoader(CodegenLanguage::class, it as CodeGenerationSettingItem) } + ).component + codegenLanguageCombo.addActionListener { + if (!codegenLanguageCombo.item.isSummarizationCompatible()) { + enableSummarizationGenerationCheckBox.isSelected = false } } } - val valuesComboBox: LayoutBuilder.(KClass<*>, Array<*>) -> Unit = { loader, values -> + val valuesComboBox: (KClass<*>, Array<*>) -> Unit = { loader, values -> val serviceLabels = mapOf( RuntimeExceptionTestsBehaviour::class to "Tests with exceptions:", TreatOverflowAsError::class to "Overflow detection:", @@ -71,41 +67,36 @@ class SettingsWindow(val project: Project) { ) row(serviceLabels[loader] ?: error("Unknown service loader: $loader")) { - cell { - comboBox( - DefaultComboBoxModel(values), + comboBox(DefaultComboBoxModel(values)) + .bindItem( getter = { settings.providerNameByServiceLoader(loader) }, setter = { settings.setProviderByLoader(loader, it as CodeGenerationSettingItem) }, - ).apply { - component.renderer = CodeGenerationSettingItemRenderer() - } - } + ).component.renderer = CodeGenerationSettingItemRenderer() } } row("Hanging test timeout:") { - cell { - spinner( - getter = { - settings.hangingTestsTimeout.timeoutMs - .coerceIn(HangingTestsTimeout.MIN_TIMEOUT_MS, HangingTestsTimeout.MAX_TIMEOUT_MS).toInt() - }, - setter = { - settings.hangingTestsTimeout = HangingTestsTimeout(it.toLong()) - }, - minValue = HangingTestsTimeout.MIN_TIMEOUT_MS.toInt(), - maxValue = HangingTestsTimeout.MAX_TIMEOUT_MS.toInt(), - step = 50, - ) + spinner( + range = IntRange( + HangingTestsTimeout.MIN_TIMEOUT_MS.toInt(), + HangingTestsTimeout.MAX_TIMEOUT_MS.toInt() + ), + step = 50 + ).bindIntValue( + getter = { + settings.hangingTestsTimeout.timeoutMs + .coerceIn(HangingTestsTimeout.MIN_TIMEOUT_MS, HangingTestsTimeout.MAX_TIMEOUT_MS).toInt() + }, + setter = { + settings.hangingTestsTimeout = HangingTestsTimeout(it.toLong()) + } + ) - label("milliseconds per method") - .apply { - ContextHelpLabel.create( - "Set this timeout to define which test is \"hanging\". Increase it to test the " + - "time-consuming method or decrease if the execution speed is critical for you." - )() - } - } + label("milliseconds per method") + contextHelp( + "Set this timeout to define which test is \"hanging\". Increase it to test the " + + "time-consuming method or decrease if the execution speed is critical for you." + ) } mapOf( @@ -117,127 +108,116 @@ class SettingsWindow(val project: Project) { } row { - cell { - runInspectionAfterTestGenerationCheckBox = checkBox("Display detected errors on the Problems tool window") - .onApply { - settings.state.runInspectionAfterTestGeneration = runInspectionAfterTestGenerationCheckBox.isSelected - } - .onReset { - runInspectionAfterTestGenerationCheckBox.isSelected = settings.state.runInspectionAfterTestGeneration - } - .onIsModified { - runInspectionAfterTestGenerationCheckBox.isSelected xor settings.state.runInspectionAfterTestGeneration - } - // .apply { ContextHelpLabel.create("Automatically run code inspection after test generation")() } - .component - } + runInspectionAfterTestGenerationCheckBox = checkBox("Display detected errors on the Problems tool window") + .onApply { + settings.state.runInspectionAfterTestGeneration = + runInspectionAfterTestGenerationCheckBox.isSelected + } + .onReset { + runInspectionAfterTestGenerationCheckBox.isSelected = + settings.state.runInspectionAfterTestGeneration + } + .onIsModified { + runInspectionAfterTestGenerationCheckBox.isSelected xor settings.state.runInspectionAfterTestGeneration + } + .component + contextHelp("Automatically run code inspection after test generation") } row { - cell { - enableSummarizationGenerationCheckBox = checkBox("Enable Summaries Generation") - .onApply { - settings.state.summariesGenerationType = - if (enableSummarizationGenerationCheckBox.isSelected) SummariesGenerationType.FULL else SummariesGenerationType.NONE - } - .onReset { - enableSummarizationGenerationCheckBox.isSelected = - settings.state.summariesGenerationType != SummariesGenerationType.NONE - } - .onIsModified { - enableSummarizationGenerationCheckBox.isSelected xor (settings.state.summariesGenerationType != SummariesGenerationType.NONE) - } - .enableIf(codegenLanguageCombo.selectedValueMatches(CodegenLanguage?::isSummarizationCompatible)) - .component - } + enableSummarizationGenerationCheckBox = checkBox("Enable Summaries Generation") + .onApply { + settings.state.summariesGenerationType = + if (enableSummarizationGenerationCheckBox.isSelected) SummariesGenerationType.FULL else SummariesGenerationType.NONE + } + .onReset { + enableSummarizationGenerationCheckBox.isSelected = + settings.state.summariesGenerationType != SummariesGenerationType.NONE + } + .onIsModified { + enableSummarizationGenerationCheckBox.isSelected xor (settings.state.summariesGenerationType != SummariesGenerationType.NONE) + }.enabledIf(codegenLanguageCombo.selectedValueMatches(CodegenLanguage?::isSummarizationCompatible)) + .component } + row { - cell { - forceMockCheckBox = checkBox("Force mocking static methods") - .onApply { - settings.state.forceStaticMocking = - if (forceMockCheckBox.isSelected) ForceStaticMocking.FORCE else ForceStaticMocking.DO_NOT_FORCE - } - .onReset { forceMockCheckBox.isSelected = settings.forceStaticMocking == ForceStaticMocking.FORCE } - .onIsModified { forceMockCheckBox.isSelected xor (settings.forceStaticMocking != ForceStaticMocking.DO_NOT_FORCE) } - .apply { ContextHelpLabel.create("Overrides other mocking settings")() } - .component - } + forceMockCheckBox = checkBox("Force mocking static methods") + .onApply { + settings.state.forceStaticMocking = + if (forceMockCheckBox.isSelected) ForceStaticMocking.FORCE else ForceStaticMocking.DO_NOT_FORCE + } + .onReset { forceMockCheckBox.isSelected = settings.forceStaticMocking == ForceStaticMocking.FORCE } + .onIsModified { forceMockCheckBox.isSelected xor (settings.forceStaticMocking != ForceStaticMocking.DO_NOT_FORCE) } + .component + contextHelp("Overrides other mocking settings") } row { - cell { - enableExperimentalLanguagesCheckBox = checkBox("Experimental languages support") - .onApply { - settings.state.enableExperimentalLanguagesSupport = - enableExperimentalLanguagesCheckBox.isSelected - } - .onReset { - enableExperimentalLanguagesCheckBox.isSelected = - settings.experimentalLanguagesSupport == true - } - .onIsModified { enableExperimentalLanguagesCheckBox.isSelected xor settings.experimentalLanguagesSupport } - .apply { ContextHelpLabel.create("Enable JavaScript and Python if IDE supports them")() } - .component - } + enableExperimentalLanguagesCheckBox = checkBox("Experimental languages support") + .onApply { + settings.state.enableExperimentalLanguagesSupport = + enableExperimentalLanguagesCheckBox.isSelected + } + .onReset { + enableExperimentalLanguagesCheckBox.isSelected = + settings.experimentalLanguagesSupport == true + } + .onIsModified { enableExperimentalLanguagesCheckBox.isSelected xor settings.experimentalLanguagesSupport } + .component + contextHelp("Enable JavaScript and Python if IDE supports them") } row("Classes to be forcedly mocked:") {} row { - val excludeTableCellBuilder = excludeTable.component(CCFlags.grow) val updater = Runnable { - UIUtil.setEnabled(excludeTableCellBuilder.component, forceMockCheckBox.isSelected, true) + UIUtil.setEnabled(excludeTable.component, forceMockCheckBox.isSelected, true) } - excludeTableCellBuilder + cell(excludeTable.component) + .align(Align.FILL) .onApply { excludeTable.apply() } .onReset { excludeTable.reset() updater.run() } .onIsModified { excludeTable.isModified() } - forceMockCheckBox.addActionListener { updater.run() } - + forceMockCheckBox.addActionListener { updater.run() } } val fuzzLabel = JBLabel("Fuzzing") val symLabel = JBLabel("Symbolic execution") row("Test generation method:") { - enabled = UtSettings.useFuzzing val granularity = 20 - slider(0, granularity, 1, granularity / 4) - .labelTable { - // clear all labels - }.withValueBinding( - PropertyBinding( - get = { ((1 - settings.fuzzingValue) * granularity).toInt() }, - set = { settings.fuzzingValue = 1 - it / granularity.toDouble() } - ) - ) - .constraints(CCFlags.growX) + slider(0, granularity, 1, granularity / 4).apply { + // clear all labels + labelTable(emptyMap()) + }.bindValue( + getter = { ((1 - settings.fuzzingValue) * granularity).toInt() }, + setter = { settings.fuzzingValue = 1 - it / granularity.toDouble() } + ) + .align(Align.FILL) .component.apply { - toolTipText = "While fuzzer \"guesses\" the values to enter as much execution paths as possible, symbolic executor tries to \"deduce\" them. Choose the proportion of generation time allocated for each of these methods within Test generation timeout. The slide has no effect for Spring Projects." + this.toolTipText = + "While fuzzer \"guesses\" the values to enter as much execution paths as possible, symbolic executor tries to \"deduce\" them. Choose the proportion of generation time allocated for each of these methods within Test generation timeout. The slide has no effect for Spring Projects." addChangeListener { fuzzLabel.text = "Fuzzing " + "%.0f %%".format(100.0 * (granularity - value) / granularity) symLabel.text = "%.0f %%".format(100.0 * value / granularity) + " Symbolic execution" } } - } - row("") { - BorderLayoutPanel().apply { + }.enabled(UtSettings.useFuzzing) + row { + cell(BorderLayoutPanel().apply { addToLeft(fuzzLabel) addToRight(symLabel) - }().constraints(CCFlags.growX) + }).align(Align.FILL) } if (!UtSettings.useFuzzing) { - row("") { - cell { - component(comment("Fuzzing is disabled in configuration file.").component) - component(ActionLink("Edit configuration") { - UIUtil.getWindow(fuzzLabel)?.dispose() - showSettingsEditor(project, "useFuzzing") - }) + row { + comment("Fuzzing is disabled in configuration file.") + link("Edit configuration") { + UIUtil.getWindow(fuzzLabel)?.dispose() + showSettingsEditor(project, "useFuzzing") } } } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index 6a9341bd35..a92bc77468 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -22,7 +22,6 @@ import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.roots.ModuleSourceOrderEntry import com.intellij.openapi.roots.ui.configuration.ClasspathEditor -import com.intellij.openapi.roots.ui.configuration.ComboBoxWithSeparators import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.DialogPanel @@ -31,7 +30,9 @@ import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.OptionAction import com.intellij.openapi.ui.ValidationInfo import com.intellij.openapi.ui.popup.IconButton +import com.intellij.openapi.ui.popup.ListSeparator import com.intellij.openapi.util.Computable +import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtilCore.urlToPath @@ -46,7 +47,7 @@ import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo import com.intellij.refactoring.util.RefactoringUtil import com.intellij.refactoring.util.classMembers.MemberInfo import com.intellij.ui.ColoredListCellRenderer -import com.intellij.ui.ContextHelpLabel +import com.intellij.ui.GroupHeaderSeparator import com.intellij.ui.HyperlinkLabel import com.intellij.ui.IdeBorderFactory.createBorder import com.intellij.ui.InplaceButton @@ -56,18 +57,14 @@ import com.intellij.ui.SideBorder import com.intellij.ui.SimpleTextAttributes import com.intellij.ui.components.CheckBox import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.Panel +import com.intellij.ui.components.JBScrollPane import com.intellij.ui.components.panels.HorizontalLayout import com.intellij.ui.components.panels.NonOpaquePanel -import com.intellij.ui.layout.Cell -import com.intellij.ui.layout.CellBuilder +import com.intellij.ui.components.panels.OpaquePanel +import com.intellij.ui.dsl.builder.Align import com.intellij.ui.layout.ComboBoxPredicate -import com.intellij.ui.layout.Row -import com.intellij.ui.layout.enableIf -import com.intellij.ui.layout.panel -import com.intellij.ui.layout.selectedValueMatches +import com.intellij.ui.dsl.builder.panel import com.intellij.util.IncorrectOperationException -import com.intellij.util.io.exists import com.intellij.util.lang.JavaVersion import com.intellij.util.ui.JBUI import com.intellij.util.ui.JBUI.Borders.empty @@ -79,6 +76,7 @@ import com.intellij.util.ui.components.BorderLayoutPanel import mu.KotlinLogging import java.awt.BorderLayout import java.awt.Color +import java.awt.Component import java.awt.Dimension import java.awt.event.ActionEvent import java.nio.file.Files @@ -94,7 +92,6 @@ import javax.swing.JCheckBox import javax.swing.JComboBox import javax.swing.JComponent import javax.swing.JList -import javax.swing.JPanel import javax.swing.JSpinner import javax.swing.text.DefaultFormatter import org.jetbrains.concurrency.Promise @@ -120,7 +117,6 @@ import org.utbot.framework.plugin.api.MockFramework import org.utbot.framework.plugin.api.MockFramework.MOCKITO import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.framework.plugin.api.TreatOverflowAsError -import org.utbot.framework.plugin.api.isSummarizationCompatible import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FILE_CONTENT import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FOLDER import org.utbot.framework.plugin.api.utils.MOCKITO_MOCKMAKER_FILE_NAME @@ -157,6 +153,7 @@ import org.utbot.intellij.plugin.util.findSdkVersion import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* +import kotlin.io.path.exists private const val RECENTS_KEY = "org.utbot.recents" @@ -238,28 +235,87 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } } - private fun createComboBoxWithSeparatorsForSpringConfigs( - separatorToValues: Collection>>, + private fun createComboBoxWithSeparatorsForSpringConfigs( + separatorToValues: Collection>>, width: Int = 300 - ): ComboBoxWithSeparators { - val comboBox = object : ComboBoxWithSeparators() {}.apply { - fun wrapInEntryModel(value: T) = object : ComboBoxWithSeparators.EntryModel(value) { - override fun getPresentableText(): String = value.toString() + ): ComboBox { + val comboBox = object : ComboBox() { + override fun setSelectedItem(anObject: Any?) { + if (anObject !is ListSeparator) { + super.setSelectedItem(anObject) + } } + }.apply { + isSwingPopup = false + renderer = MyListCellRenderer() setMinimumAndPreferredWidth(width) separatorToValues.forEach { (separator, values) -> if (values.isEmpty()) return@forEach - separator?.let { addItem(Separator(it.toString())) } - values.forEach { value -> - addItem(wrapInEntryModel(value)) + separator?.let { + addItem(ListSeparator(it)) } + values.forEach(::addItem) } } return comboBox } + private class MyListCellRenderer: ColoredListCellRenderer() { + private val separatorRenderer = SeparatorRenderer() + override fun getListCellRendererComponent( + list: JList?, + value: Any?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ): Component { + return when (value) { + is ListSeparator -> { + separatorRenderer.init(value.text, index < 0) + } + else -> { + super.getListCellRendererComponent(list, value, index, selected, hasFocus) + } + } + } + + override fun customizeCellRenderer( + list: JList, + value: Any?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ) { + append(java.lang.String.valueOf(value)) + } + } + + class SeparatorRenderer : OpaquePanel() { + private val separator = GroupHeaderSeparator(JBUI.insets(3, 8, 1, 0)) + private var emptyPreferredHeight = false + + init { + layout = BorderLayout() + add(separator) + } + + fun init(@NlsContexts.Separator caption: String, emptyPreferredHeight: Boolean) : SeparatorRenderer { + separator.caption = caption + this.emptyPreferredHeight = emptyPreferredHeight + return this + } + + override fun getPreferredSize(): Dimension { + return super.getPreferredSize().apply { + if (emptyPreferredHeight) { + height = 0 + } + } + } + } + private fun createHelpLabel(commonTooltip: String? = null) = JBLabel(AllIcons.General.ContextHelp).apply { if (!commonTooltip.isNullOrEmpty()) toolTipText = commonTooltip } @@ -311,54 +367,47 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m override fun createCenterPanel(): JComponent { panel = panel { row("Test sources root:") { - component(testSourceFolderField) + cell(testSourceFolderField).align(Align.FILL) } row("Testing framework:") { - makePanelWithHelpTooltip( - testFrameworks, - null - ) + cell(testFrameworks) } if (model.projectType == ProjectType.Spring) { row("Spring configuration:") { - makePanelWithHelpTooltip( - springConfig, - ContextHelpLabel.create( - "100% Symbolic execution mode.\n" + - "Classes defined in Spring configuration will be used instead " + - "of interfaces and abstract classes.\n" + - "Mocks will be used when necessary." - ) + cell(springConfig) + contextHelp( + "100% Symbolic execution mode.\n" + + "Classes defined in Spring configuration will be used instead " + + "of interfaces and abstract classes.\n" + + "Mocks will be used when necessary." ) } } row("Mocking strategy:") { - makePanelWithHelpTooltip( - mockStrategies, - ContextHelpLabel.create("Mock everything around the target class or the whole package except the system classes. " + - "Otherwise, mock nothing. Mockito will be installed, if you don't have one.") + cell(mockStrategies) + contextHelp( + "Mock everything around the target class or the whole package except the system classes. " + + "Otherwise, mock nothing. Mockito will be installed, if you don't have one." ) - }.enableIf(ComboBoxPredicate(springConfig) { - model.projectType != ProjectType.Spring || springConfig.item.getItem() == NO_SPRING_CONFIGURATION_OPTION + }.enabledIf(ComboBoxPredicate(springConfig) { + model.projectType != ProjectType.Spring || springConfig.item == NO_SPRING_CONFIGURATION_OPTION }) - row { component(staticsMocking)} + row { cell(staticsMocking)} row { - cell { - component(parametrizedTestSources) - component(ContextHelpLabel.create("Parametrization is not supported in some configurations, e.g. if mocks are used.")) - } + cell(parametrizedTestSources) + contextHelp("Parametrization is not supported in some configurations, e.g. if mocks are used.") } row("Test generation timeout:") { - cell { - component(timeoutSpinner) - label("seconds per class") - component(ContextHelpLabel.create("Set the timeout for all test generation processes per class to complete.")) - } + cell(BorderLayoutPanel().apply { + addToLeft(timeoutSpinner) + addToRight(JBLabel("seconds per class")) + }) + contextHelp("Set the timeout for all test generation processes per class to complete.") } row("Generate tests for:") {} row { - scrollPane(membersTable) + cell(JBScrollPane(membersTable)).align(Align.FILL) } } @@ -368,21 +417,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m return panel } - private inline fun Cell.panelWithHelpTooltip(tooltipText: String?, crossinline init: Cell.() -> Unit): Cell { - init() - tooltipText?.let { component(ContextHelpLabel.create(it)) } - return this - } - - private fun Row.makePanelWithHelpTooltip( - mainComponent: JComponent, - label: JBLabel? - ): CellBuilder = - component(Panel().apply { - add(mainComponent, BorderLayout.LINE_START) - label?.let { add(it, BorderLayout.LINE_END) } - }) - override fun createTitlePane(): JComponent? { val sdkVersion = findSdkVersion(model.srcModule) // TODO:SAT-1571 investigate Android Studio specific sdk issues @@ -578,9 +612,9 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.testSourceRoot?.apply { model.updateSourceRootHistory(this.toNioPath().toString()) } model.typeReplacementApproach = - when (springConfig.item.getItem()) { + when (springConfig.item) { NO_SPRING_CONFIGURATION_OPTION -> TypeReplacementApproach.DoNotReplace - else -> TypeReplacementApproach.ReplaceIfPossible(springConfig.item.getItem().toString()) + else -> TypeReplacementApproach.ReplaceIfPossible(springConfig.item.toString()) } val settings = model.project.service() @@ -1025,7 +1059,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } springConfig.addActionListener { _ -> - val isSpringConfigSelected = springConfig.item.getItem() != NO_SPRING_CONFIGURATION_OPTION + val isSpringConfigSelected = springConfig.item != NO_SPRING_CONFIGURATION_OPTION if (isSpringConfigSelected) { mockStrategies.item = MockStrategyApi.springDefaultItem mockStrategies.isEnabled = false From f3e0a5fbd493e4bfdd711b5c3ebffef1443e5e70 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Fri, 7 Apr 2023 18:59:12 +0300 Subject: [PATCH 2/3] Update source code compatibility with IDEA 2023.1 API #2109 Get rid of obsolete code API migration GotItMessage -> GotItTooltip --- .../plugin/ui/GenerateTestsDialogWindow.kt | 54 ------------------- .../utbot/intellij/plugin/ui/Notifications.kt | 22 +++----- 2 files changed, 8 insertions(+), 68 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index a92bc77468..358816348d 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -4,7 +4,6 @@ package org.utbot.intellij.plugin.ui import com.intellij.codeInsight.hint.HintUtil import com.intellij.icons.AllIcons -import com.intellij.ide.impl.ProjectNewWindowDoNotAskOption import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.components.service @@ -143,7 +142,6 @@ import org.utbot.intellij.plugin.ui.utils.findFrameworkLibrary import org.utbot.intellij.plugin.ui.utils.findParametrizedTestsLibrary import org.utbot.intellij.plugin.ui.utils.getOrCreateTestResourcesPath import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle -import org.utbot.intellij.plugin.ui.utils.kotlinTargetPlatform import org.utbot.intellij.plugin.ui.utils.parseVersion import org.utbot.intellij.plugin.ui.utils.testResourceRootTypes import org.utbot.intellij.plugin.ui.utils.testRootType @@ -651,7 +649,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m println(e.message) } - configureJvmTargetIfRequired() configureTestFrameworkIfRequired() configureMockFrameworkIfRequired() configureStaticMockingIfRequired() @@ -941,57 +938,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m //endregion - /** - * Configures JVM Target if required. - * - * We need to notify the user about potential problems and to give - * him a chance to change JVM targets in his application. - * - * Note that now we need it for Kotlin plugin only. - */ - private fun configureJvmTargetIfRequired() { - if (codegenLanguages.item == CodegenLanguage.KOTLIN - && parametrizedTestSources.isSelected - && createKotlinJvmTargetNotificationDialog() == Messages.YES - ) { - configureKotlinJvmTarget() - } - } - - /** - * Checks if JVM target for Kotlin plugin if configured appropriately - * and allows user to configure it via ProjectStructure tab if not. - * - * For Kotlin plugin until version 1.5 default JVM target is 1.6. - * Sometimes (i.e. in parametrized tests) we use some annotations - * and statements that are supported since JVM version 1.8 only. - */ - private fun configureKotlinJvmTarget() { - val activeKotlinJvmTarget = model.srcModule.kotlinTargetPlatform().description - if (activeKotlinJvmTarget == actualKotlinJvmTarget) { - return - } - - ShowSettingsUtil.getInstance().editConfigurable( - model.project, - ProjectStructureConfigurable.getInstance(Objects.requireNonNull(model.project)) - ) - } - - private fun createKotlinJvmTargetNotificationDialog() = Messages.showYesNoDialog( - """Your current JVM target is 1.6. Some Kotlin features may not be supported. - |Would you like to update current target to $actualKotlinJvmTarget?""".trimMargin(), - title, - "Yes", - "No", - Messages.getQuestionIcon(), - ProjectNewWindowDoNotAskOption(), - ) - - // Language features we use to generate parametrized tests - // (i.e. @JvmStatic attribute or JUnit5 arguments) are supported since JVM target 1.8 - private val actualKotlinJvmTarget = "1.8" - private fun setListeners() { itemsToHelpTooltip.forEach { (box, tooltip) -> if (box is ComboBox<*> && tooltip != null) { box.setHelpTooltipTextChanger(tooltip) diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt index dd70a769f9..97cc93c24c 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt @@ -1,6 +1,5 @@ package org.utbot.intellij.plugin.ui -import com.intellij.ide.util.PropertiesComponent import com.intellij.notification.Notification import com.intellij.notification.NotificationDisplayType import com.intellij.notification.NotificationGroup @@ -13,13 +12,8 @@ import com.intellij.openapi.keymap.KeymapUtil import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.startup.StartupActivity -import com.intellij.openapi.ui.popup.Balloon import com.intellij.openapi.wm.WindowManager -import com.intellij.ui.GotItMessage -import com.intellij.ui.awt.RelativePoint -import com.intellij.util.ui.JBFont -import com.intellij.util.ui.UIUtil -import java.awt.Point +import com.intellij.ui.GotItTooltip import javax.swing.event.HyperlinkEvent import mu.KotlinLogging @@ -196,17 +190,17 @@ object TestReportUrlOpeningListener: NotificationListener.Adapter() { object GotItTooltipActivity : StartupActivity { private const val KEY = "UTBot.GotItMessageWasShown" override fun runActivity(project: Project) { - if (PropertiesComponent.getInstance().isTrueValue(KEY)) return ApplicationManager.getApplication().invokeLater { val shortcut = ActionManager.getInstance() .getKeyboardShortcut("org.utbot.intellij.plugin.ui.actions.GenerateTestsAction")?:return@invokeLater val shortcutText = KeymapUtil.getShortcutText(shortcut) - val message = GotItMessage.createMessage("UnitTestBot is ready!", - "
" + - "You can get test coverage for methods, Java classes,
and even for whole source roots
with $shortcutText
") - message.setCallback { PropertiesComponent.getInstance().setValue(KEY, true) } - WindowManager.getInstance().getFrame(project)?.rootPane?.let { - message.show(RelativePoint(it, Point(it.width, it.height)), Balloon.Position.above) + val message = GotItTooltip(KEY, + "
You can get test coverage for methods,
Java classes, and even for whole source roots
with $shortcutText
") + .withHeader("UnitTestBot is ready!") + if (message.canShow()) { + WindowManager.getInstance().getFrame(project)?.rootPane?.let { + message.show(it, GotItTooltip.BOTTOM_LEFT) + } } } } From ecd01ddc73e66099856c91f5863a746670ac0c5a Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Mon, 10 Apr 2023 12:37:18 +0300 Subject: [PATCH 3/3] Fix broken compilation --- .../org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index 835d46c013..5301bf6f77 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -627,7 +627,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m when (springConfig.item) { NO_SPRING_CONFIGURATION_OPTION -> TypeReplacementApproach.DoNotReplace else -> { - val shortConfigName = springConfig.item.getItem().toString() + val shortConfigName = springConfig.item.toString() //TODO: avoid this check on xml here, merge two helpers into one val fullConfigName = if (shortConfigName.endsWith(".xml")) { xmlConfigurationHelper.restoreFullName(shortConfigName)