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

Notify and reason to the user that UtBot can't be run on the class in editor #1105

Merged
merged 2 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -64,6 +64,12 @@ object UnsupportedJdkNotifier : ErrorNotifier() {
"JDK versions older than 8 are not supported. This project's JDK version is $info"
}

object InvalidClassNotifier : WarningNotifier() {
override val displayId: String = "Invalid class"
override fun content(project: Project?, module: Module?, info: String): String =
"Generate tests with UtBot for the $info is not supported."
}

object MissingLibrariesNotifier : WarningNotifier() {
override val displayId: String = "Missing libraries"
override fun content(project: Project?, module: Module?, info: String): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ import org.utbot.intellij.plugin.util.isVisible
import java.util.*
import org.jetbrains.kotlin.j2k.getContainingClass
import org.jetbrains.kotlin.utils.addIfNotNull
import org.utbot.intellij.plugin.models.packageName
import org.utbot.intellij.plugin.ui.InvalidClassNotifier
import org.utbot.intellij.plugin.util.isAbstract

class GenerateTestsAction : AnAction(), UpdateInBackground {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return

val (srcClasses, focusedMethods, extractMembersFromSrcClasses) = getPsiTargets(e) ?: return
UtTestsDialogProcessor.createDialogAndGenerateTests(project, srcClasses, extractMembersFromSrcClasses, focusedMethods)
val validatedSrcClasses = validateSrcClasses(srcClasses) ?: return

UtTestsDialogProcessor.createDialogAndGenerateTests(project, validatedSrcClasses, extractMembersFromSrcClasses, focusedMethods)
}

override fun update(e: AnActionEvent) {
Expand All @@ -53,7 +59,6 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {

if (psiElementHandler.isCreateTestActionAvailable(element)) {
val srcClass = psiElementHandler.containingClass(element) ?: return null
if (srcClass.isInterface || !srcClass.isVisible) return null
val srcSourceRoot = srcClass.getSourceRoot() ?: return null
val srcMembers = srcClass.extractFirstLevelMembers(false)
val focusedMethod = focusedMethodOrNull(element, srcMembers, psiElementHandler)
Expand Down Expand Up @@ -113,7 +118,7 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
}
}
}
srcClasses.removeIf { it.isInterface }

if (srcClasses.size > 1) {
extractMembersFromSrcClasses = false
}
Expand All @@ -136,6 +141,45 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
return null
}

/**
* Validates that a set of source classes matches some requirements from [isInvalid].
* If no one of them matches, shows a warning about the first mismatch reason.
*/
private fun validateSrcClasses(srcClasses: Set<PsiClass>): Set<PsiClass>? {
val filteredClasses = srcClasses
.filterNot { it.isInvalid(withWarnings = false) }
.toSet()

if (filteredClasses.isEmpty()) {
srcClasses.first().isInvalid(withWarnings = true)
return null
}

return filteredClasses
}

private fun PsiClass.isInvalid(withWarnings: Boolean): Boolean {
val isAbstractOrInterface = this.isInterface || this.isAbstract
if (isAbstractOrInterface) {
if (withWarnings) InvalidClassNotifier.notify("abstract class or interface ${this.name}")
return true
}

val isInvisible = !this.isVisible
if (isInvisible) {
if (withWarnings) InvalidClassNotifier.notify("private or protected class ${this.name}")
return true
}

val packageIsIncorrect = this.packageName.startsWith("java")
if (packageIsIncorrect) {
if (withWarnings) InvalidClassNotifier.notify("class ${this.name} located in java.* package")
return true
}

return false
}

private fun PsiElement?.getSourceRoot() : VirtualFile? {
val project = this?.project?: return null
val virtualFile = this.containingFile?.originalFile?.virtualFile?: return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import org.jetbrains.kotlin.asJava.elements.isSetter
import org.utbot.common.filterWhen
import org.utbot.framework.UtSettings

private val PsiMember.isAbstract: Boolean
val PsiMember.isAbstract: Boolean
get() = modifierList?.hasModifierProperty(PsiModifier.ABSTRACT)?: false


private val PsiMember.isKotlinGetterOrSetter: Boolean
get() {
if (this !is KtLightMethod)
Expand Down