diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt index 913990c39e..1dd8526d5d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt @@ -168,7 +168,7 @@ class Mocker( fun shouldMock( type: RefType, mockInfo: UtMockInfo, - ): Boolean = checkIfShouldMock(type, mockInfo).also { if (it) mockListenerController?.onShouldMock(strategy) } + ): Boolean = checkIfShouldMock(type, mockInfo).also { if (it) mockListenerController?.onShouldMock(strategy, mockInfo) } private fun checkIfShouldMock( type: RefType, diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/Exceptions.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/Exceptions.kt new file mode 100644 index 0000000000..335a36929e --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/Exceptions.kt @@ -0,0 +1,13 @@ +package org.utbot.engine.util.mockListeners + +import kotlinx.coroutines.CancellationException + +/** + * Exception used in [org.utbot.engine.util.mockListeners.ForceMockListener]. + */ +class ForceMockCancellationException: CancellationException("Forced mocks without Mockito") + +/** + * Exception used in [org.utbot.engine.util.mockListeners.ForceStaticMockListener]. + */ +class ForceStaticMockCancellationException: CancellationException("Forced static mocks without Mockito-inline") \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceMockListener.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceMockListener.kt index 756cef4059..d1ae9f2737 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceMockListener.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceMockListener.kt @@ -1,7 +1,7 @@ package org.utbot.engine.util.mockListeners import org.utbot.engine.EngineController import org.utbot.engine.MockStrategy -import org.utbot.engine.util.mockListeners.exceptions.ForceMockCancellationException +import org.utbot.engine.UtMockInfo /** * Listener for mocker events in [org.utbot.engine.UtBotSymbolicEngine]. @@ -13,7 +13,7 @@ class ForceMockListener: MockListener { var forceMockHappened = false private set - override fun onShouldMock(controller: EngineController, strategy: MockStrategy) { + override fun onShouldMock(controller: EngineController, strategy: MockStrategy, mockInfo: UtMockInfo) { // If force mocking happened -- сancel engine job controller.job?.cancel(ForceMockCancellationException()) forceMockHappened = true diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceStaticMockListener.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceStaticMockListener.kt new file mode 100644 index 0000000000..98d5f4c100 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceStaticMockListener.kt @@ -0,0 +1,29 @@ +package org.utbot.engine.util.mockListeners + +import org.utbot.engine.EngineController +import org.utbot.engine.MockStrategy +import org.utbot.engine.UtMockInfo +import org.utbot.engine.UtNewInstanceMockInfo +import org.utbot.engine.UtStaticMethodMockInfo +import org.utbot.engine.UtStaticObjectMockInfo + +/** + * Listener for mocker events in [org.utbot.engine.UtBotSymbolicEngine]. + * If forced static mock happened, cancels the engine job. + * + * Supposed to be created only if Mockito inline is not installed. + */ +class ForceStaticMockListener: MockListener { + var forceStaticMockHappened = false + private set + + override fun onShouldMock(controller: EngineController, strategy: MockStrategy, mockInfo: UtMockInfo) { + if (mockInfo is UtNewInstanceMockInfo + || mockInfo is UtStaticMethodMockInfo + || mockInfo is UtStaticObjectMockInfo) { + // If force static mocking happened -- сancel engine job + controller.job?.cancel(ForceStaticMockCancellationException()) + forceStaticMockHappened = true + } + } +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListener.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListener.kt index 5d004e3a1c..50e2d1a6cc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListener.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListener.kt @@ -2,10 +2,11 @@ package org.utbot.engine.util.mockListeners import org.utbot.engine.EngineController import org.utbot.engine.MockStrategy +import org.utbot.engine.UtMockInfo /** * Listener that can be attached using [MockListenerController] to mocker in [org.utbot.engine.UtBotSymbolicEngine]. */ interface MockListener { - fun onShouldMock(controller: EngineController, strategy: MockStrategy) + fun onShouldMock(controller: EngineController, strategy: MockStrategy, mockInfo: UtMockInfo) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListenerController.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListenerController.kt index 765b0edb04..b3d04db2e2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListenerController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListenerController.kt @@ -2,6 +2,7 @@ package org.utbot.engine.util.mockListeners import org.utbot.engine.EngineController import org.utbot.engine.MockStrategy +import org.utbot.engine.UtMockInfo /** * Controller that allows to attach listeners to mocker in [org.utbot.engine.UtBotSymbolicEngine]. @@ -13,7 +14,7 @@ class MockListenerController(private val controller: EngineController) { listeners += listener } - fun onShouldMock(strategy: MockStrategy) { - listeners.map { it.onShouldMock(controller, strategy) } + fun onShouldMock(strategy: MockStrategy, mockInfo: UtMockInfo) { + listeners.map { it.onShouldMock(controller, strategy, mockInfo) } } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/exceptions/ForceMockCancellationException.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/exceptions/ForceMockCancellationException.kt deleted file mode 100644 index d5b2e3d86c..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/exceptions/ForceMockCancellationException.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.utbot.engine.util.mockListeners.exceptions - -import kotlinx.coroutines.CancellationException - -/** - * Exception used in [org.utbot.engine.util.mockListeners.ForceMockListener]. - */ -class ForceMockCancellationException: CancellationException("Forced mocks without Mockito") diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/UtBotTestCaseGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/UtBotTestCaseGenerator.kt index 9c078dd7e2..b2d4f8f45f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/UtBotTestCaseGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/UtBotTestCaseGenerator.kt @@ -58,7 +58,7 @@ object UtBotTestCaseGenerator : TestCaseGenerator { private val logger = KotlinLogging.logger {} private val timeoutLogger = KotlinLogging.logger(logger.name + ".timeout") - lateinit var configureEngine: (UtBotSymbolicEngine) -> Unit + lateinit var engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> lateinit var isCanceled: () -> Boolean //properties to save time on soot initialization @@ -76,7 +76,7 @@ object UtBotTestCaseGenerator : TestCaseGenerator { buildDir, classpath, dependencyPaths, - configureEngine = {}, + engineActions = mutableListOf(), isCanceled ) @@ -84,11 +84,11 @@ object UtBotTestCaseGenerator : TestCaseGenerator { buildDir: Path, classpath: String?, dependencyPaths: String, - configureEngine: (UtBotSymbolicEngine) -> Unit, + engineActions: MutableList<(UtBotSymbolicEngine) -> Unit>, isCanceled: () -> Boolean ) { this.isCanceled = isCanceled - this.configureEngine = configureEngine + this.engineActions = engineActions if (isCanceled()) return checkFrameworkDependencies(dependencyPaths) @@ -293,7 +293,9 @@ object UtBotTestCaseGenerator : TestCaseGenerator { mockStrategy, chosenClassesToMockAlways, executionTimeEstimator - ).apply(configureEngine) + ) + + engineActions.map { engine.apply(it) } generate(engine).collect { when (it) { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerator.kt index e8472f9112..d24c103d95 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerator.kt @@ -33,7 +33,7 @@ class CodeGenerator( buildDir: String, classpath: String, pluginJarsPath: String, - configureEngine: (UtBotSymbolicEngine) -> Unit = {}, + engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(), isCanceled: () -> Boolean, ) { init { @@ -41,7 +41,7 @@ class CodeGenerator( } val generator = (project.service().testCasesGenerator as UtBotTestCaseGenerator).apply { - init(Paths.get(buildDir), classpath, pluginJarsPath, configureEngine, isCanceled) + init(Paths.get(buildDir), classpath, pluginJarsPath, engineActions, isCanceled) } private val settingsState = project.service().state diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/TestGenerator.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/TestGenerator.kt index b27bd8d365..75270ad4e9 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/TestGenerator.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/TestGenerator.kt @@ -405,11 +405,11 @@ object TestGenerator { """.trimIndent() appendHtmlLine(savedFileMessage) } - TestsReportNotifier.notify(notifyMessage, model.project, model.testModule) + TestsReportNotifier.notify(notifyMessage) } private fun processInitialWarnings(testsCodeWithTestReport: TestsCodeWithTestReport, model: GenerateTestsModel) { - val hasInitialWarnings = model.forceMockHappened || model.hasTestFrameworkConflict + val hasInitialWarnings = model.forceMockHappened || model.forceStaticMockHappened || model.hasTestFrameworkConflict if (!hasInitialWarnings) { return } @@ -425,6 +425,14 @@ object TestGenerator { """.trimIndent() } } + if (model.forceStaticMockHappened) { + initialWarnings.add { + """ + Warning: Some test cases were ignored, because mockito-inline is not installed in the project.
+ Better results could be achieved by configuring mockito-inline. + """.trimIndent() + } + } if (model.hasTestFrameworkConflict) { initialWarnings.add { """ diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/ConfigureWindowCommon.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/ConfigureWindowCommon.kt deleted file mode 100644 index d682574bb0..0000000000 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/ConfigureWindowCommon.kt +++ /dev/null @@ -1,47 +0,0 @@ -package org.utbot.intellij.plugin.ui - -import com.intellij.openapi.module.Module -import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.DependencyScope -import com.intellij.openapi.roots.ExternalLibraryDescriptor -import com.intellij.openapi.roots.JavaProjectModelModificationService -import com.intellij.openapi.ui.Messages -import org.jetbrains.concurrency.Promise -import org.utbot.framework.plugin.api.MockFramework -import org.utbot.intellij.plugin.ui.utils.LibrarySearchScope -import org.utbot.intellij.plugin.ui.utils.findFrameworkLibrary -import org.utbot.intellij.plugin.ui.utils.parseVersion - -fun createMockFrameworkNotificationDialog(title: String) = Messages.showYesNoDialog( - """Mock framework ${MockFramework.MOCKITO.displayName} is not installed into current module. - |Would you like to install it now?""".trimMargin(), - title, - "Yes", - "No", - Messages.getQuestionIcon(), -) - -fun configureMockFramework(project: Project, module: Module) { - val selectedMockFramework = MockFramework.MOCKITO - - val libraryInProject = - findFrameworkLibrary(project, module, selectedMockFramework, LibrarySearchScope.Project) - val versionInProject = libraryInProject?.libraryName?.parseVersion() - - selectedMockFramework.isInstalled = true - addDependency(project, module, mockitoCoreLibraryDescriptor(versionInProject)) - .onError { selectedMockFramework.isInstalled = false } -} - -/** - * Adds the dependency for selected framework via [JavaProjectModelModificationService]. - * - * Note that version restrictions will be applied only if they are present on target machine - * Otherwise latest release version will be installed. - */ -fun addDependency(project: Project, module: Module, libraryDescriptor: ExternalLibraryDescriptor): Promise { - return JavaProjectModelModificationService - .getInstance(project) - //this method returns JetBrains internal Promise that is difficult to deal with, but it is our way - .addDependency(module, libraryDescriptor, DependencyScope.TEST) -} 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 6177131a0d..a91b00c0c9 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,6 +4,35 @@ package org.utbot.intellij.plugin.ui import com.intellij.codeInsight.hint.HintUtil import com.intellij.icons.AllIcons +import org.utbot.common.PathUtil.toPath +import org.utbot.framework.UtSettings +import org.utbot.framework.codegen.ForceStaticMocking +import org.utbot.framework.codegen.Junit4 +import org.utbot.framework.codegen.Junit5 +import org.utbot.framework.codegen.NoStaticMocking +import org.utbot.framework.codegen.ParametrizedTestSource +import org.utbot.framework.codegen.StaticsMocking +import org.utbot.framework.codegen.TestFramework +import org.utbot.framework.codegen.TestNg +import org.utbot.framework.codegen.model.util.MOCKITO_EXTENSIONS_FILE_CONTENT +import org.utbot.framework.codegen.model.util.MOCKITO_EXTENSIONS_STORAGE +import org.utbot.framework.codegen.model.util.MOCKITO_MOCKMAKER_FILE_NAME +import org.utbot.framework.plugin.api.CodeGenerationSettingItem +import org.utbot.framework.plugin.api.CodegenLanguage +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.intellij.plugin.settings.Settings +import org.utbot.intellij.plugin.ui.components.TestFolderComboWithBrowseButton +import org.utbot.intellij.plugin.ui.utils.LibrarySearchScope +import org.utbot.intellij.plugin.ui.utils.findFrameworkLibrary +import org.utbot.intellij.plugin.ui.utils.getOrCreateTestResourcesPath +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.addSourceRootIfAbsent +import org.utbot.intellij.plugin.ui.utils.testRootType import com.intellij.ide.impl.ProjectNewWindowDoNotAskOption import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.command.WriteCommandAction @@ -12,6 +41,9 @@ import com.intellij.openapi.editor.colors.EditorColorsManager import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.roots.ContentEntry +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ExternalLibraryDescriptor +import com.intellij.openapi.roots.JavaProjectModelModificationService import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ui.configuration.ClasspathEditor import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable @@ -64,35 +96,7 @@ import com.intellij.util.ui.JBUI.scale import com.intellij.util.ui.JBUI.size import com.intellij.util.ui.UIUtil import com.intellij.util.ui.components.BorderLayoutPanel -import org.utbot.common.PathUtil.toPath -import org.utbot.framework.UtSettings -import org.utbot.framework.codegen.ForceStaticMocking -import org.utbot.framework.codegen.Junit4 -import org.utbot.framework.codegen.Junit5 -import org.utbot.framework.codegen.NoStaticMocking -import org.utbot.framework.codegen.ParametrizedTestSource -import org.utbot.framework.codegen.StaticsMocking -import org.utbot.framework.codegen.TestFramework -import org.utbot.framework.codegen.TestNg -import org.utbot.framework.codegen.model.util.MOCKITO_EXTENSIONS_FILE_CONTENT -import org.utbot.framework.codegen.model.util.MOCKITO_EXTENSIONS_STORAGE -import org.utbot.framework.codegen.model.util.MOCKITO_MOCKMAKER_FILE_NAME -import org.utbot.framework.plugin.api.CodeGenerationSettingItem -import org.utbot.framework.plugin.api.CodegenLanguage -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.intellij.plugin.settings.Settings -import org.utbot.intellij.plugin.ui.components.TestFolderComboWithBrowseButton -import org.utbot.intellij.plugin.ui.utils.LibrarySearchScope -import org.utbot.intellij.plugin.ui.utils.addSourceRootIfAbsent -import org.utbot.intellij.plugin.ui.utils.findFrameworkLibrary -import org.utbot.intellij.plugin.ui.utils.getOrCreateTestResourcesPath -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 +import org.jetbrains.concurrency.Promise import org.utbot.intellij.plugin.util.AndroidApiHelper import java.awt.BorderLayout import java.awt.Color @@ -162,6 +166,20 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m init { title = "Generate tests with UtBot" setResizable(false) + + // Configure notification urls callbacks + TestsReportNotifier.urlOpeningListener.callbacks[TestReportUrlOpeningListener.mockitoSuffix]?.plusAssign { + if (createMockFrameworkNotificationDialog() == Messages.YES) { + configureMockFramework() + } + } + + TestsReportNotifier.urlOpeningListener.callbacks[TestReportUrlOpeningListener.mockitoInlineSuffix]?.plusAssign { + if (createStaticsMockingNotificationDialog() == Messages.YES) { + configureStaticMocking() + } + } + init() } @@ -596,8 +614,8 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m val frameworkNotInstalled = mockStrategies.item != MockStrategyApi.NO_MOCKS && !MOCKITO.isInstalled - if (frameworkNotInstalled && createMockFrameworkNotificationDialog(title) == Messages.YES) { - configureMockFramework(model.project, model.testModule) + if (frameworkNotInstalled && createMockFrameworkNotificationDialog() == Messages.YES) { + configureMockFramework() } } @@ -624,10 +642,31 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } selectedTestFramework.isInstalled = true - addDependency(model.project, model.testModule, libraryDescriptor) + addDependency(libraryDescriptor) .onError { selectedTestFramework.isInstalled = false } } + private fun createTestFrameworkNotificationDialog() = Messages.showYesNoDialog( + """Selected test framework ${testFrameworks.item.displayName} is not installed into current module. + |Would you like to install it now?""".trimMargin(), + title, + "Yes", + "No", + Messages.getQuestionIcon(), + ) + + private fun configureMockFramework() { + val selectedMockFramework = MOCKITO + + val libraryInProject = + findFrameworkLibrary(model.project, model.testModule, selectedMockFramework, LibrarySearchScope.Project) + val versionInProject = libraryInProject?.libraryName?.parseVersion() + + selectedMockFramework.isInstalled = true + addDependency(mockitoCoreLibraryDescriptor(versionInProject)) + .onError { selectedMockFramework.isInstalled = false } + } + private fun configureStaticMocking() { val testResourcesUrl = model.testModule.getOrCreateTestResourcesPath(model.testSourceRoot) configureMockitoResources(testResourcesUrl) @@ -656,8 +695,21 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } } - private fun createTestFrameworkNotificationDialog() = Messages.showYesNoDialog( - """Selected test framework ${testFrameworks.item.displayName} is not installed into current module. + /** + * Adds the dependency for selected framework via [JavaProjectModelModificationService]. + * + * Note that version restrictions will be applied only if they are present on target machine + * Otherwise latest release version will be installed. + */ + private fun addDependency(libraryDescriptor: ExternalLibraryDescriptor): Promise { + return JavaProjectModelModificationService + .getInstance(model.project) + //this method returns JetBrains internal Promise that is difficult to deal with, but it is our way + .addDependency(model.testModule, libraryDescriptor, DependencyScope.TEST) + } + + private fun createMockFrameworkNotificationDialog() = Messages.showYesNoDialog( + """Mock framework ${MOCKITO.displayName} is not installed into current module. |Would you like to install it now?""".trimMargin(), title, "Yes", diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsModel.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsModel.kt index d2fcf6436c..b79d916223 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsModel.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsModel.kt @@ -28,6 +28,7 @@ data class GenerateTestsModel( var timeout:Long, var generateWarningsForStaticMocking: Boolean = false, var forceMockHappened: Boolean = false, + var forceStaticMockHappened: Boolean = false, var hasTestFrameworkConflict: Boolean = false, ) { var testSourceRoot: VirtualFile? = null diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt index ffd0af96d9..fe9c229252 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/Notifications.kt @@ -12,7 +12,6 @@ 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.Messages import com.intellij.openapi.ui.popup.Balloon import com.intellij.openapi.wm.WindowManager import com.intellij.ui.GotItMessage @@ -112,31 +111,27 @@ object TestsReportNotifier : InformationUrlNotifier() { override val titleText: String = "Report of the unit tests generation via UtBot" - override val urlOpeningListener: TestReportUrlOpeningListener = TestReportUrlOpeningListener() + public override val urlOpeningListener: TestReportUrlOpeningListener = TestReportUrlOpeningListener() - override fun content(project: Project?, module: Module?, info: String): String { - // Remember last project and module to use them for configurations. - urlOpeningListener.project = project - urlOpeningListener.module = module - return info - } + override fun content(project: Project?, module: Module?, info: String): String = info } /** * Listener that handles URLs starting with [prefix], like "#utbot/configure-mockito". - * - * Current implementation */ class TestReportUrlOpeningListener: NotificationListener.Adapter() { companion object { const val prefix = "#utbot/" const val mockitoSuffix = "configure-mockito" + const val mockitoInlineSuffix = "mockito-inline" } - private val defaultListener = NotificationListener.UrlOpeningListener(false) - // Last project and module to be able to use them when activated for configuration tasks. - var project: Project? = null - var module: Module? = null + val callbacks: Map Unit>> = hashMapOf( + Pair(mockitoSuffix, mutableListOf()), + Pair(mockitoInlineSuffix, mutableListOf()), + ) + + private val defaultListener = NotificationListener.UrlOpeningListener(false) override fun hyperlinkActivated(notification: Notification, e: HyperlinkEvent) { val description = e.description @@ -147,19 +142,8 @@ class TestReportUrlOpeningListener: NotificationListener.Adapter() { } } - private fun handleDescription(descriptionSuffix: String) { - when { - descriptionSuffix.startsWith(mockitoSuffix) -> { - project?.let { project -> module?.let { module -> - if (createMockFrameworkNotificationDialog("Configure mock framework") == Messages.YES) { - configureMockFramework(project, module) - } - } ?: error("Could not configure mock framework: module is null for project $project") - } ?: error("Could not configure mock framework: project is null") - } - else -> error("No such command with #utbot prefix: $descriptionSuffix") - } - } + private fun handleDescription(descriptionSuffix: String) = + callbacks[descriptionSuffix]?.map { it() } ?: error("No such command with #utbot prefix: $descriptionSuffix") } object GotItTooltipActivity : StartupActivity { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/UtTestsDialogProcessor.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/UtTestsDialogProcessor.kt index 02137c6824..540f92fea4 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/UtTestsDialogProcessor.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/UtTestsDialogProcessor.kt @@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit import mu.KotlinLogging import org.jetbrains.kotlin.idea.util.module import org.utbot.engine.util.mockListeners.ForceMockListener +import org.utbot.engine.util.mockListeners.ForceStaticMockListener import org.utbot.intellij.plugin.error.showErrorDialogLater object UtTestsDialogProcessor { @@ -166,12 +167,20 @@ object UtTestsDialogProcessor { val forceMockListener = if (!mockFrameworkInstalled) { ForceMockListener().apply { - codeGenerator.generator.configureEngine = { engine -> engine.attachMockListener(this) } + codeGenerator.generator.engineActions.add { engine -> engine.attachMockListener(this) } } } else { null } + val forceStaticMockListener = if (!model.staticsMocking.isConfigured) { + ForceStaticMockListener().apply { + codeGenerator.generator.engineActions.add { engine -> engine.attachMockListener(this) } + } + } else { + null + } + val notEmptyCases = withUtContext(context) { codeGenerator .generateForSeveralMethods(methods, model.timeout) @@ -192,6 +201,10 @@ object UtTestsDialogProcessor { model.forceMockHappened = forceMockHappened } + forceStaticMockListener?.run { + model.forceStaticMockHappened = forceStaticMockHappened + } + timerHandler.cancel(true) } processedClasses++ @@ -214,8 +227,10 @@ object UtTestsDialogProcessor { } private fun errorMessage(className: String?, timeout: Long) = buildString { - append("UtBot failed to generate any test cases for class $className.") - append("You could try to increase current timeout $timeout sec for generating tests in generation dialog.") + appendLine("UtBot failed to generate any test cases for class $className.") + appendLine() + appendLine("Try to alter test generation configuration, e.g. enable mocking and static mocking.") + appendLine("Alternatively, you could try to increase current timeout $timeout sec for generating tests in generation dialog.") } }