Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IndexNotReadyException thrown in IDEA with installed UnitTestBot plug… #1047

Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down Expand Up @@ -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<IntentionAction, String>) {
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
Expand Down