diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt index 0fa534e303..aa10ce6fec 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt @@ -13,6 +13,7 @@ import com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction import com.intellij.openapi.command.executeCommand import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.module.Module import com.intellij.openapi.project.DumbService @@ -129,67 +130,87 @@ object CodeGenerationController { val testClass = createTestClass(srcClass, testDirectory, model) ?: continue val testFilePointer = SmartPointerManager.getInstance(model.project).createSmartPsiElementPointer(testClass.containingFile) val cut = psi2KClass[srcClass] ?: error("Didn't find KClass instance for class ${srcClass.name}") - runWriteCommandAction(model.project, "Generate tests with UtBot", null, { - try { - generateCodeAndReport(srcClass, cut, testClass, testFilePointer, testSets, model, latch, reports, utilClassListener) - testFilesPointers.add(testFilePointer) - } catch (e: IncorrectOperationException) { - logger.error { e } - showCreatingClassError(model.project, createTestClassName(srcClass)) - } - }) + run(EDT_LATER) { + runWriteCommandAction(model.project, "Generate tests with UtBot", null, { + try { + generateCodeAndReport( + srcClass, + cut, + testClass, + testFilePointer, + testSets, + model, + latch, + reports, + utilClassListener + ) + testFilesPointers.add(testFilePointer) + } catch (e: IncorrectOperationException) { + logger.error { e } + showCreatingClassError(model.project, createTestClassName(srcClass)) + } + }) + } } catch (e: IncorrectOperationException) { logger.error { e } showCreatingClassError(model.project, createTestClassName(srcClass)) } } - - run(EDT_LATER) { - waitForCountDown(latch, timeout = 100, timeUnit = TimeUnit.MILLISECONDS) { - val requiredUtilClassKind = utilClassListener.requiredUtilClassKind - ?: return@waitForCountDown // no util class needed - - val existingUtilClass = model.codegenLanguage.getUtilClassOrNull(model.project, model.testModule) - val utilClassKind = newUtilClassKindOrNull(existingUtilClass, requiredUtilClassKind) - if (utilClassKind != null) { - createOrUpdateUtilClass( - testDirectory = baseTestDirectory, - utilClassKind = utilClassKind, - existingUtilClass = existingUtilClass, - model = model - ) - } - } - } - - run(READ_ACTION) { - val sarifReportsPath = model.testModule.getOrCreateSarifReportsPath(model.testSourceRoot) - run(THREAD_POOL) { - waitForCountDown(latch) { - try { - // Parametrized tests are not supported in tests report yet - // TODO JIRA:1507 - if (model.parametrizedTestSource != ParametrizedTestSource.PARAMETRIZE) { - showTestsReport(reports, model) + run(THREAD_POOL) { + waitForCountDown(latch) { + run(EDT_LATER) { + run(WRITE_ACTION) { + createUtilityClassIfNeed(utilClassListener, model, baseTestDirectory) + run(EDT_LATER) { + try { + // Parametrized tests are not supported in tests report yet + // TODO JIRA:1507 + if (model.parametrizedTestSource != ParametrizedTestSource.PARAMETRIZE) { + showTestsReport(reports, model) + } + } catch (e: Exception) { + showErrorDialogLater( + model.project, + message = "Cannot save tests generation report: error occurred '${e.message}'", + title = "Failed to save tests report" + ) + } + run(THREAD_POOL) { + val sarifReportsPath = + model.testModule.getOrCreateSarifReportsPath(model.testSourceRoot) + mergeSarifReports(model, sarifReportsPath) + if (model.runGeneratedTestsWithCoverage) { + RunConfigurationHelper.runTestsWithCoverage(model, testFilesPointers) + } + } } - } catch (e: Exception) { - showErrorDialogLater( - model.project, - message = "Cannot save tests generation report: error occurred '${e.message}'", - title = "Failed to save tests report" - ) - } - - mergeSarifReports(model, sarifReportsPath) - if (model.runGeneratedTestsWithCoverage) { - RunConfigurationHelper.runTestsWithCoverage(model, testFilesPointers) } } } } } + private fun createUtilityClassIfNeed( + utilClassListener: UtilClassListener, + model: GenerateTestsModel, + baseTestDirectory: PsiDirectory + ) { + val requiredUtilClassKind = utilClassListener.requiredUtilClassKind + ?: return // no util class needed + + val existingUtilClass = model.codegenLanguage.getUtilClassOrNull(model.project, model.testModule) + val utilClassKind = newUtilClassKindOrNull(existingUtilClass, requiredUtilClassKind) + if (utilClassKind != null) { + createOrUpdateUtilClass( + testDirectory = baseTestDirectory, + utilClassKind = utilClassKind, + existingUtilClass = existingUtilClass, + model = model + ) + } + } + /** * This method decides whether to overwrite an existing util class with a new one. And if so, then with what kind of util class. * - If no util class exists, then we generate a new one. @@ -275,9 +296,9 @@ object CodeGenerationController { }) val utUtilsDocument = runReadAction { - PsiDocumentManager - .getInstance(model.project) - .getDocument(utUtilsFile) ?: error("Failed to get a Document for UtUtils file") + FileDocumentManager + .getInstance() + .getDocument(utUtilsFile.viewProvider.virtualFile) ?: error("Failed to get a Document for UtUtils file") } unblockDocument(model.project, utUtilsDocument) @@ -620,9 +641,9 @@ object CodeGenerationController { // reformatting before creating reports due to // SarifReport requires the final version of the generated tests code run(THREAD_POOL) { - IntentionHelper(model.project, editor, filePointer).applyIntentions() +// IntentionHelper(model.project, editor, filePointer).applyIntentions() run(EDT_LATER) { - runWriteCommandAction(testClassUpdated.project, "UtBot tests reformatting", null, { + runWriteCommandAction(filePointer.project, "UtBot tests reformatting", null, { reformat(model, filePointer, testClassUpdated) }) unblockDocument(testClassUpdated.project, editor.document) @@ -657,16 +678,18 @@ object CodeGenerationController { val project = model.project val codeStyleManager = CodeStyleManager.getInstance(project) val file = smartPointer.containingFile?: return - codeStyleManager.reformat(file) - when (model.codegenLanguage) { - CodegenLanguage.JAVA -> { - val range = file.textRange - val startOffset = range.startOffset - val endOffset = range.endOffset - val reformatRange = codeStyleManager.reformatRange(file, startOffset, endOffset, false) - JavaCodeStyleManager.getInstance(project).shortenClassReferences(reformatRange) + DumbService.getInstance(model.project).runWhenSmart { + codeStyleManager.reformat(file) + when (model.codegenLanguage) { + CodegenLanguage.JAVA -> { + val range = file.textRange + val startOffset = range.startOffset + val endOffset = range.endOffset + val reformatRange = codeStyleManager.reformatRange(file, startOffset, endOffset, false) + JavaCodeStyleManager.getInstance(project).shortenClassReferences(reformatRange) + } + CodegenLanguage.KOTLIN -> ShortenReferences.DEFAULT.process((testClass as KtUltraLightClass).kotlinOrigin.containingKtFile) } - CodegenLanguage.KOTLIN -> ShortenReferences.DEFAULT.process((testClass as KtUltraLightClass).kotlinOrigin.containingKtFile) } } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/IntentionHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/IntentionHelper.kt index 964cf7bb55..1cf3c20618 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/IntentionHelper.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/IntentionHelper.kt @@ -15,8 +15,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiFile import com.intellij.psi.SmartPsiElementPointer import mu.KotlinLogging -import org.utbot.intellij.plugin.util.IntelliJApiHelper -import org.utbot.intellij.plugin.util.IntelliJApiHelper.run +import org.jetbrains.kotlin.idea.util.application.runReadAction private val logger = KotlinLogging.logger {} @@ -52,30 +51,30 @@ class IntentionHelper(val project: Project, private val editor: Editor, private actions }) actions.forEach { - if (it.value.isApplicable()) { + if (runReadAction { + it.value.isApplicable() && it.key.isAvailable( + project, + editor, + testFile.containingFile + ) + }) { if (it.key.startInWriteAction()) { WriteCommandAction.runWriteCommandAction(project) { - try { - it.key.invoke(project, editor, testFile.containingFile) - } catch (e: Exception) { - logger.error { e } - } + invokeIntentionAction(it) } } else { - run(IntelliJApiHelper.Target.EDT_LATER) { - run(IntelliJApiHelper.Target.READ_ACTION) { - try { - it.key.invoke(project, editor, testFile.containingFile) - } catch (e: Exception) { - logger.error { e } - } - } + runReadAction { + invokeIntentionAction(it) } } } } } + private fun invokeIntentionAction(it: Map.Entry) { + it.key.invoke(project, editor, testFile.containingFile) + } + private fun String.isApplicable(): Boolean { if (this.startsWith("Change type of actual to ")) return true if (this == "Replace 'switch' with 'if'") return true // SetsTest