@@ -26,12 +26,18 @@ import org.utbot.intellij.plugin.util.isVisible
2626import java.util.*
2727import org.jetbrains.kotlin.j2k.getContainingClass
2828import org.jetbrains.kotlin.utils.addIfNotNull
29+ import org.utbot.intellij.plugin.models.packageName
30+ import org.utbot.intellij.plugin.ui.InvalidClassNotifier
31+ import org.utbot.intellij.plugin.util.isAbstract
2932
3033class GenerateTestsAction : AnAction (), UpdateInBackground {
3134 override fun actionPerformed (e : AnActionEvent ) {
3235 val project = e.project ? : return
36+
3337 val (srcClasses, focusedMethods, extractMembersFromSrcClasses) = getPsiTargets(e) ? : return
34- UtTestsDialogProcessor .createDialogAndGenerateTests(project, srcClasses, extractMembersFromSrcClasses, focusedMethods)
38+ val validatedSrcClasses = validateSrcClasses(srcClasses) ? : return
39+
40+ UtTestsDialogProcessor .createDialogAndGenerateTests(project, validatedSrcClasses, extractMembersFromSrcClasses, focusedMethods)
3541 }
3642
3743 override fun update (e : AnActionEvent ) {
@@ -53,7 +59,6 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
5359
5460 if (psiElementHandler.isCreateTestActionAvailable(element)) {
5561 val srcClass = psiElementHandler.containingClass(element) ? : return null
56- if (srcClass.isInterface || ! srcClass.isVisible) return null
5762 val srcSourceRoot = srcClass.getSourceRoot() ? : return null
5863 val srcMembers = srcClass.extractFirstLevelMembers(false )
5964 val focusedMethod = focusedMethodOrNull(element, srcMembers, psiElementHandler)
@@ -113,7 +118,7 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
113118 }
114119 }
115120 }
116- srcClasses.removeIf { it.isInterface }
121+
117122 if (srcClasses.size > 1 ) {
118123 extractMembersFromSrcClasses = false
119124 }
@@ -136,6 +141,45 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
136141 return null
137142 }
138143
144+ /* *
145+ * Validates that a set of source classes matches some requirements from [isInvalid].
146+ * If no one of them matches, shows a warning about the first mismatch reason.
147+ */
148+ private fun validateSrcClasses (srcClasses : Set <PsiClass >): Set <PsiClass >? {
149+ val filteredClasses = srcClasses
150+ .filterNot { it.isInvalid(withWarnings = false ) }
151+ .toSet()
152+
153+ if (filteredClasses.isEmpty()) {
154+ srcClasses.first().isInvalid(withWarnings = true )
155+ return null
156+ }
157+
158+ return filteredClasses
159+ }
160+
161+ private fun PsiClass.isInvalid (withWarnings : Boolean ): Boolean {
162+ val isAbstractOrInterface = this .isInterface || this .isAbstract
163+ if (isAbstractOrInterface) {
164+ if (withWarnings) InvalidClassNotifier .notify(" abstract class or interface ${this .name} " )
165+ return true
166+ }
167+
168+ val isInvisible = ! this .isVisible
169+ if (isInvisible) {
170+ if (withWarnings) InvalidClassNotifier .notify(" private or protected class ${this .name} " )
171+ return true
172+ }
173+
174+ val packageIsIncorrect = this .packageName.startsWith(" java" )
175+ if (packageIsIncorrect) {
176+ if (withWarnings) InvalidClassNotifier .notify(" class ${this .name} located in java.* package" )
177+ return true
178+ }
179+
180+ return false
181+ }
182+
139183 private fun PsiElement?.getSourceRoot () : VirtualFile ? {
140184 val project = this ?.project? : return null
141185 val virtualFile = this .containingFile?.originalFile?.virtualFile? : return null
0 commit comments