diff --git a/.github/workflows/publish-plugin-from-branch.yml b/.github/workflows/publish-plugin-from-branch.yml index 2e4f5ec84b..b6c191deb9 100644 --- a/.github/workflows/publish-plugin-from-branch.yml +++ b/.github/workflows/publish-plugin-from-branch.yml @@ -48,6 +48,8 @@ jobs: extra_options: "-PideType=IC -PprojectType=Community" - plugin_type: IU extra_options: "-PideType=IU -PprojectType=Ultimate" + - plugin_type: PY + extra_options: "-PideType=PY -PprojectType=Ultimate" runs-on: ubuntu-20.04 container: unittestbot/java-env:java17-zulu-jdk-gradle7.6.1-kotlinc1.8.0 steps: @@ -79,13 +81,13 @@ jobs: - name: Build UTBot IntelliJ IDEA plugin run: | gradle clean buildPlugin --no-daemon --build-cache --no-parallel ${{ matrix.configuration.extra_options }} -Dorg.gradle.jvmargs=-Xmx2g -Dkotlin.daemon.jvm.options=-Xmx4g -PsemVer=${{ env.VERSION }} - cd utbot-intellij/build/distributions - unzip utbot-intellij-${{ env.VERSION }}.zip - rm utbot-intellij-${{ env.VERSION }}.zip + cd utbot-intellij-main/build/distributions + unzip utbot-intellij-main-${{ env.VERSION }}.zip + rm utbot-intellij-main-${{ env.VERSION }}.zip - name: Archive UTBot IntelliJ IDEA plugin if: ${{ inputs.upload-artifact == 'true' }} uses: actions/upload-artifact@v3 with: name: utbot-intellij-${{ matrix.configuration.plugin_type }}-${{ env.VERSION_ARCHIVE }} - path: utbot-intellij/build/distributions/* + path: utbot-intellij-main/build/distributions/* diff --git a/buildSrc/src/main/java/SettingsTemplateHelper.java b/buildSrc/src/main/java/SettingsTemplateHelper.java index 45502e2f33..d55390eaac 100644 --- a/buildSrc/src/main/java/SettingsTemplateHelper.java +++ b/buildSrc/src/main/java/SettingsTemplateHelper.java @@ -30,7 +30,7 @@ public class SettingsTemplateHelper { public static void proceed(Project project) { File settingsSourceDir = new File(project.getBuildDir().getParentFile().getParentFile(), "utbot-framework-api/src/main/kotlin/org/utbot/framework/"); String sourceFileName = "UtSettings.kt"; - File settingsResourceDir = new File(project.getBuildDir().getParentFile().getParentFile(), "utbot-intellij/src/main/resources/"); + File settingsResourceDir = new File(project.getBuildDir().getParentFile().getParentFile(), "utbot-intellij-main/src/main/resources/"); String settingsFileName = "settings.properties"; Map dictionary = new HashMap<>(); diff --git a/gradle.properties b/gradle.properties index 00719b83c7..d67d7f007d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ kotlin.code.style=official -#Project Type +# === IDE settings === +# Project Type # - Community: for Java + Spring + Python (IC supported features) # - Ultimate: for Java + Spring + Python (IU supported features) + JavaScript + Go projectType=Ultimate @@ -11,14 +12,17 @@ ultimateEdition=Ultimate # IU, IC, PC, PY # IC for AndroidStudio ideType=IC -ideVersion=232.8660.185 +ideaVersion=232.8660.185 +pycharmVersion=2023.2 +golandVersion=2023.2 # ALL, NOJS buildType=NOJS +javaIde=IC,IU pythonIde=IC,IU,PC,PY -jsIde=IU,PY,WS +jsIde=IU,PY jsBuild=ALL -goIde=IU +goIde=IU,GO # In order to run Android Studio instead of IntelliJ Community, specify the path to your Android Studio installation #androidStudioPath=your_path_to_android_studio @@ -29,6 +33,7 @@ pythonCommunityPluginVersion=232.8660.185 pythonUltimatePluginVersion=232.8660.185 # Version numbers: https://plugins.jetbrains.com/plugin/9568-go/versions goPluginVersion=232.8660.142 +# === IDE settings === junit5Version=5.8.2 junit4Version=4.13.2 diff --git a/settings.gradle.kts b/settings.gradle.kts index 3a54a76c59..38c5173f3b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,7 @@ val ultimateEdition: String by settings val ideType: String by settings val buildType: String by settings +val javaIde: String by settings val pythonIde: String by settings val jsIde: String by settings val jsBuild: String by settings @@ -27,7 +28,6 @@ include("utbot-core") include("utbot-framework") include("utbot-framework-api") include("utbot-modificators-analyzer") -include("utbot-intellij") include("utbot-sample") include("utbot-java-fuzzing") include("utbot-fuzzing") @@ -60,6 +60,12 @@ include("utbot-spring-framework") include("utbot-spring-commons-api") include("utbot-spring-commons") include("utbot-spring-analyzer") +include("utbot-spring-sample") +include("utbot-spring-test") + +if (javaIde.split(",").contains(ideType)) { + include("utbot-intellij") +} if (pythonIde.split(",").contains(ideType)) { include("utbot-python") @@ -70,9 +76,6 @@ if (pythonIde.split(",").contains(ideType)) { include("utbot-python-executor") } -include("utbot-spring-sample") -include("utbot-spring-test") - if (projectType == ultimateEdition) { if (jsBuild == buildType || jsIde.split(",").contains(ideType)) { include("utbot-js") @@ -88,3 +91,4 @@ if (projectType == ultimateEdition) { } include("utbot-light") +include("utbot-intellij-main") diff --git a/utbot-cli-python/src/main/kotlin/org/utbot/cli/language/python/Utils.kt b/utbot-cli-python/src/main/kotlin/org/utbot/cli/language/python/Utils.kt index 8ff7f71457..708cfa6131 100644 --- a/utbot-cli-python/src/main/kotlin/org/utbot/cli/language/python/Utils.kt +++ b/utbot-cli-python/src/main/kotlin/org/utbot/cli/language/python/Utils.kt @@ -25,5 +25,4 @@ fun writeToFileAndSave(filename: String, fileContent: String) { val file = File(filename) file.parentFile?.mkdirs() file.writeText(fileContent) - file.createNewFile() } diff --git a/utbot-intellij-go/build.gradle.kts b/utbot-intellij-go/build.gradle.kts index 377bad3660..fff30caba1 100644 --- a/utbot-intellij-go/build.gradle.kts +++ b/utbot-intellij-go/build.gradle.kts @@ -2,17 +2,44 @@ val intellijPluginVersion: String? by rootProject val kotlinLoggingVersion: String? by rootProject val apacheCommonsTextVersion: String? by rootProject val jacksonVersion: String? by rootProject -val ideType: String? by rootProject -val ideVersion: String by rootProject val kotlinPluginVersion: String by rootProject + +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject +val androidStudioPath: String? by rootProject + +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + val pythonCommunityPluginVersion: String? by rootProject val pythonUltimatePluginVersion: String? by rootProject val goPluginVersion: String? by rootProject +// https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file +val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" + +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + plugins { id("org.jetbrains.intellij") version "1.13.1" } -project.tasks.asMap["runIde"]?.enabled = false tasks { compileKotlin { @@ -46,10 +73,16 @@ intellij { val androidPlugins = listOf("org.jetbrains.android") - val jvmPlugins = listOf( + val jvmPlugins = mutableListOf( "java" ) + val kotlinPlugins = listOf( + "org.jetbrains.kotlin" + ) + + androidStudioPath?.let { jvmPlugins += androidPlugins } + val pythonCommunityPlugins = listOf( "PythonCore:${pythonCommunityPluginVersion}" ) @@ -66,13 +99,24 @@ intellij { "org.jetbrains.plugins.go:${goPluginVersion}" ) + val mavenUtilsPlugins = listOf( + "org.jetbrains.idea.maven" + ) + + val basePluginSet = jvmPlugins + kotlinPlugins + mavenUtilsPlugins + androidPlugins + plugins.set( - when (ideType) { - "IC" -> jvmPlugins + pythonCommunityPlugins + androidPlugins - "IU" -> jvmPlugins + pythonUltimatePlugins + jsPlugins + goPlugins + androidPlugins - "PC" -> pythonCommunityPlugins - "PU" -> pythonUltimatePlugins // something else, JS? - else -> jvmPlugins + when (projectType) { + communityEdition -> basePluginSet + pythonCommunityPlugins + ultimateEdition -> when (ideType) { + "IC" -> basePluginSet + pythonCommunityPlugins + "IU" -> basePluginSet + pythonUltimatePlugins + jsPlugins + goPlugins + "PC" -> pythonCommunityPlugins + "PY" -> pythonUltimatePlugins + jsPlugins + "GO" -> goPlugins + else -> basePluginSet + } + else -> basePluginSet } ) diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsCodeFileWriter.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsCodeFileWriter.kt similarity index 87% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsCodeFileWriter.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsCodeFileWriter.kt index 14dca93611..19b81b6421 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsCodeFileWriter.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsCodeFileWriter.kt @@ -1,7 +1,7 @@ -package org.utbot.intellij.plugin.language.go.generator +package org.utbot.intellij.plugin.go.generator -import com.intellij.codeInsight.CodeInsightUtil import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiFile @@ -9,8 +9,8 @@ import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiManager import com.intellij.util.IncorrectOperationException import org.utbot.go.api.GoUtFile -import org.utbot.intellij.plugin.language.go.GoLanguageAssistant -import org.utbot.intellij.plugin.language.go.models.GenerateGoTestsModel +import org.utbot.intellij.plugin.go.language.GoLanguageAssistant +import org.utbot.intellij.plugin.go.models.GenerateGoTestsModel import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import java.nio.file.Paths @@ -37,7 +37,7 @@ object GoUtTestsCodeFileWriter { sourceFileDir.add(testPsiFile) val testFile = sourceFileDir.findFile(testsFileNameWithExtension)!! - CodeInsightUtil.positionCursor(model.project, testFile, testFile) + OpenFileDescriptor(model.project, testFile.virtualFile).navigate(true) } } catch (e: IncorrectOperationException) { showCreatingFileError(model.project, testsFileName) diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsDialogProcessor.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsDialogProcessor.kt similarity index 95% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsDialogProcessor.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsDialogProcessor.kt index be9b8cf6a7..b5c1fcdd9d 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/GoUtTestsDialogProcessor.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/GoUtTestsDialogProcessor.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.generator +package org.utbot.intellij.plugin.go.generator import com.goide.project.DefaultGoRootsProvider import com.goide.psi.GoFunctionOrMethodDeclaration @@ -16,9 +16,9 @@ import com.intellij.openapi.ui.Messages import org.utbot.go.gocodeanalyzer.GoParsingSourceCodeAnalysisResultException import org.utbot.go.logic.GoUtTestsGenerationConfig import org.utbot.go.worker.GoWorkerFailedException -import org.utbot.intellij.plugin.language.go.models.GenerateGoTestsModel -import org.utbot.intellij.plugin.language.go.ui.GenerateGoTestsDialogWindow -import org.utbot.intellij.plugin.language.go.ui.utils.resolveGoExecutablePath +import org.utbot.intellij.plugin.go.models.GenerateGoTestsModel +import org.utbot.intellij.plugin.go.ui.GenerateGoTestsDialogWindow +import org.utbot.intellij.plugin.go.ui.utils.resolveGoExecutablePath import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import java.nio.file.Paths diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/IntellijGoUtTestsGenerationController.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/IntellijGoUtTestsGenerationController.kt similarity index 98% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/IntellijGoUtTestsGenerationController.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/IntellijGoUtTestsGenerationController.kt index 43858f3ece..b5a89b4c17 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/generator/IntellijGoUtTestsGenerationController.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/generator/IntellijGoUtTestsGenerationController.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.generator +package org.utbot.intellij.plugin.go.generator import com.intellij.openapi.application.invokeLater import com.intellij.openapi.progress.ProgressIndicator @@ -7,7 +7,7 @@ import org.utbot.go.api.GoUtFunction import org.utbot.go.api.GoUtFuzzedFunctionTestCase import org.utbot.go.gocodeanalyzer.GoSourceCodeAnalyzer import org.utbot.go.logic.AbstractGoUtTestsGenerationController -import org.utbot.intellij.plugin.language.go.models.GenerateGoTestsModel +import org.utbot.intellij.plugin.go.models.GenerateGoTestsModel import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import org.utbot.intellij.plugin.ui.utils.showWarningDialogLater import java.nio.file.Path diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/GoLanguageAssistant.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/language/GoLanguageAssistant.kt similarity index 94% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/GoLanguageAssistant.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/language/GoLanguageAssistant.kt index b2265756c3..f88c243ab8 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/GoLanguageAssistant.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/language/GoLanguageAssistant.kt @@ -1,16 +1,16 @@ -package org.utbot.intellij.plugin.language.go +package org.utbot.intellij.plugin.go.language import com.goide.psi.* import com.intellij.lang.Language import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.editor.Editor +import com.intellij.openapi.module.ModuleUtilCore import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.idea.base.util.module import org.utbot.intellij.plugin.language.agnostic.LanguageAssistant -import org.utbot.intellij.plugin.language.go.generator.GoUtTestsDialogProcessor +import org.utbot.intellij.plugin.go.generator.GoUtTestsDialogProcessor @Suppress("unused") // is used in org.utbot.intellij.plugin.language.agnostic.LanguageAssistant via reflection object GoLanguageAssistant : LanguageAssistant() { @@ -26,7 +26,7 @@ object GoLanguageAssistant : LanguageAssistant() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return val file = e.getData(CommonDataKeys.PSI_FILE) as? GoFile ?: return - val module = file.module ?: return + val module = ModuleUtilCore.findModuleForFile(file) ?: return val (targetFunctions, focusedTargetFunctions) = getPsiTargets(e) ?: return GoUtTestsDialogProcessor.createDialogAndGenerateTests( project, diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/models/GenerateGoTestsModel.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/models/GenerateGoTestsModel.kt similarity index 96% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/models/GenerateGoTestsModel.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/models/GenerateGoTestsModel.kt index 2e1cc8f2ef..0b62e84649 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/models/GenerateGoTestsModel.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/models/GenerateGoTestsModel.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.models +package org.utbot.intellij.plugin.go.models import com.goide.psi.GoFunctionDeclaration import com.goide.psi.GoFunctionOrMethodDeclaration diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GenerateGoTestsDialogWindow.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GenerateGoTestsDialogWindow.kt similarity index 97% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GenerateGoTestsDialogWindow.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GenerateGoTestsDialogWindow.kt index 6232e8a7e9..b24febe97e 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GenerateGoTestsDialogWindow.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GenerateGoTestsDialogWindow.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.ui +package org.utbot.intellij.plugin.go.ui import com.goide.psi.GoFunctionDeclaration import com.goide.psi.GoFunctionOrMethodDeclaration @@ -16,7 +16,7 @@ import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil import org.utbot.go.logic.GoUtTestsGenerationConfig import org.utbot.go.logic.TestsGenerationMode -import org.utbot.intellij.plugin.language.go.models.GenerateGoTestsModel +import org.utbot.intellij.plugin.go.models.GenerateGoTestsModel import org.utbot.intellij.plugin.settings.Settings import java.text.ParseException import java.util.concurrent.TimeUnit diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GoFunctionsSelectionTable.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GoFunctionsSelectionTable.kt similarity index 95% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GoFunctionsSelectionTable.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GoFunctionsSelectionTable.kt index cd7e93eb7d..ee6203c875 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/GoFunctionsSelectionTable.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/GoFunctionsSelectionTable.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.ui +package org.utbot.intellij.plugin.go.ui import com.goide.psi.GoNamedElement import com.goide.refactor.ui.GoDeclarationInfo diff --git a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/utils/GoSdkUtils.kt b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/utils/GoSdkUtils.kt similarity index 81% rename from utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/utils/GoSdkUtils.kt rename to utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/utils/GoSdkUtils.kt index 049098ed64..fd385cc82c 100644 --- a/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/language/go/ui/utils/GoSdkUtils.kt +++ b/utbot-intellij-go/src/main/kotlin/org/utbot/intellij/plugin/go/ui/utils/GoSdkUtils.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.go.ui.utils +package org.utbot.intellij.plugin.go.ui.utils import com.goide.sdk.GoSdk import java.nio.file.Paths diff --git a/utbot-intellij-js/build.gradle.kts b/utbot-intellij-js/build.gradle.kts index 815e860514..916c540eed 100644 --- a/utbot-intellij-js/build.gradle.kts +++ b/utbot-intellij-js/build.gradle.kts @@ -2,16 +2,43 @@ val intellijPluginVersion: String? by rootProject val kotlinLoggingVersion: String? by rootProject val apacheCommonsTextVersion: String? by rootProject val jacksonVersion: String? by rootProject -val ideType: String? by rootProject -val ideVersion: String? by rootProject + +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject +val androidStudioPath: String? by rootProject + +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + val pythonCommunityPluginVersion: String? by rootProject val pythonUltimatePluginVersion: String? by rootProject val goPluginVersion: String? by rootProject +// https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file +val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" + +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + plugins { id("org.jetbrains.intellij") version "1.13.1" } -project.tasks.asMap["runIde"]?.enabled = false tasks { compileKotlin { @@ -46,10 +73,16 @@ intellij { val androidPlugins = listOf("org.jetbrains.android") - val jvmPlugins = listOf( + val jvmPlugins = mutableListOf( "java" ) + val kotlinPlugins = listOf( + "org.jetbrains.kotlin" + ) + + androidStudioPath?.let { jvmPlugins += androidPlugins } + val pythonCommunityPlugins = listOf( "PythonCore:${pythonCommunityPluginVersion}" ) @@ -66,13 +99,24 @@ intellij { "org.jetbrains.plugins.go:${goPluginVersion}" ) + val mavenUtilsPlugins = listOf( + "org.jetbrains.idea.maven" + ) + + val basePluginSet = jvmPlugins + kotlinPlugins + mavenUtilsPlugins + androidPlugins + plugins.set( - when (ideType) { - "IC" -> jvmPlugins + pythonCommunityPlugins + androidPlugins - "IU" -> jvmPlugins + pythonUltimatePlugins + jsPlugins + goPlugins + androidPlugins - "PC" -> pythonCommunityPlugins - "PY" -> pythonUltimatePlugins // something else, JS? - else -> jvmPlugins + when (projectType) { + communityEdition -> basePluginSet + pythonCommunityPlugins + ultimateEdition -> when (ideType) { + "IC" -> basePluginSet + pythonCommunityPlugins + "IU" -> basePluginSet + pythonUltimatePlugins + jsPlugins + goPlugins + "PC" -> pythonCommunityPlugins + "PY" -> pythonUltimatePlugins + jsPlugins + "GO" -> goPlugins + else -> basePluginSet + } + else -> basePluginSet } ) diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/CoverageModeButtons.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/CoverageModeButtons.kt similarity index 94% rename from utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/CoverageModeButtons.kt rename to utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/CoverageModeButtons.kt index 874a3f1fe9..c2f8c2f1e6 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/CoverageModeButtons.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/CoverageModeButtons.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.js +package org.utbot.intellij.plugin.js import javax.swing.ButtonGroup import javax.swing.JRadioButton diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogProcessor.kt similarity index 93% rename from utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt rename to utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogProcessor.kt index ba0cff9b85..164c2b0929 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogProcessor.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogProcessor.kt @@ -1,14 +1,17 @@ -package org.utbot.intellij.plugin.language.js +package org.utbot.intellij.plugin.js import api.JsTestGenerator -import com.intellij.codeInsight.CodeInsightUtil import com.intellij.javascript.nodejs.interpreter.local.NodeJsLocalInterpreterManager import com.intellij.lang.ecmascript6.psi.ES6Class import com.intellij.lang.javascript.psi.JSFile import com.intellij.lang.javascript.refactoring.util.JSMemberInfo +import com.intellij.openapi.application.invokeLater +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.Task @@ -19,13 +22,9 @@ import com.intellij.psi.PsiFileFactory import com.intellij.psi.impl.file.PsiDirectoryFactory import com.intellij.util.concurrency.AppExecutorUtil import mu.KotlinLogging -import org.jetbrains.kotlin.idea.util.application.invokeLater -import org.jetbrains.kotlin.idea.util.application.runReadAction -import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.konan.file.File import org.utbot.framework.plugin.api.TimeoutException +import org.utbot.intellij.plugin.js.language.JsLanguageAssistant import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater -import org.utbot.intellij.plugin.ui.utils.testModules import settings.JsDynamicSettings import settings.JsExportsSettings.endComment import settings.JsExportsSettings.startComment @@ -34,6 +33,7 @@ import settings.PackageDataService import settings.jsPackagesList import utils.JsCmdExec import utils.OsProvider +import java.io.File import java.io.IOException private val logger = KotlinLogging.logger {} @@ -117,7 +117,7 @@ object JsDialogProcessor { filePath: String, file: JSFile ): JsTestsModel? { - val testModules = srcModule.testModules(project) + val testModules = srcModule.testModules() if (testModules.isEmpty()) { val errorMessage = """ @@ -130,11 +130,10 @@ object JsDialogProcessor { val (pathToNode, pathToNPM) = findNodeAndNPM() ?: return null return JsTestsModel( project = project, - srcModule = srcModule, potentialTestModules = testModules, + file = file, fileMethods = fileMethods, selectedMethods = if (focusedMethod != null) setOf(focusedMethod) else emptySet(), - file = file, ).apply { containingFilePath = filePath this.pathToNode = pathToNode @@ -201,10 +200,7 @@ object JsDialogProcessor { testDir.add(temp) testDir.findFile(testFileName)!! } - val testFileEditor = CodeInsightUtil.positionCursor(project, testPsiFile, testPsiFile) as Editor - unblockDocument(project, testFileEditor.document) - testFileEditor.document.setText(generatedCode) - unblockDocument(project, testFileEditor.document) + OpenFileDescriptor(project, testPsiFile.virtualFile).navigate(true) } } } @@ -268,6 +264,8 @@ object JsDialogProcessor { } } +private fun Module.testModules() = listOf(this) + private fun PackageDataService.checkAndInstallRequirements(project: Project): Boolean { val missingPackages = jsPackagesList.filterNot { this.findPackage(it) } if (missingPackages.isEmpty()) return true diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogWindow.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogWindow.kt similarity index 98% rename from utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogWindow.kt rename to utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogWindow.kt index 24d934ada1..14b71160c7 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsDialogWindow.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsDialogWindow.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.js +package org.utbot.intellij.plugin.js import com.intellij.lang.javascript.refactoring.ui.JSMemberSelectionTable import com.intellij.lang.javascript.refactoring.util.JSMemberInfo @@ -111,7 +111,7 @@ class JsDialogWindow(val model: JsTestsModel) : DialogWrapper(model.project) { model.testFramework = testFrameworks.item model.timeout = timeoutSpinner.number.toLong() model.pathToNYC = nycSourceFileChooserField.text - model.coverageMode = coverageMode.mode + model.coverageMode = CoverageModeButtons.mode File(testSourceFolderField.text).mkdir() model.testSourceRoot = VirtualFileManager.getInstance().refreshAndFindFileByNioPath(Paths.get(testSourceFolderField.text)) diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsTestsModel.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsTestsModel.kt new file mode 100644 index 0000000000..de18043117 --- /dev/null +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/JsTestsModel.kt @@ -0,0 +1,49 @@ +package org.utbot.intellij.plugin.js + +import com.intellij.lang.javascript.psi.JSFile +import com.intellij.lang.javascript.refactoring.util.JSMemberInfo +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtil +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile +import org.utbot.framework.codegen.domain.TestFramework +import org.utbot.intellij.plugin.models.BaseTestsModel +import service.coverage.CoverageMode +import settings.JsTestGenerationSettings.defaultTimeout + +class JsTestsModel( + project: Project, + val potentialTestModules: List, + val file: JSFile, + val fileMethods: Set, + var selectedMethods: Set, +) : BaseTestsModel( + project +) { + var testModule: Module = potentialTestModules.firstOrNull() ?: error("Empty list of test modules in model") + + var timeout = defaultTimeout + + lateinit var testFramework: TestFramework + lateinit var containingFilePath: String + var pathToNode: String = "node" + var pathToNYC: String = "nyc" + var pathToNPM: String = "npm" + var coverageMode: CoverageMode = CoverageMode.FAST + + fun setSourceRootAndFindTestModule(newTestSourceRoot: VirtualFile?) { + requireNotNull(newTestSourceRoot) + testSourceRoot = newTestSourceRoot + var target = newTestSourceRoot + while (target != null && target is FakeVirtualFile) { + target = target.parent + } + if (target == null) { + error("Could not find module for $newTestSourceRoot") + } + + testModule = ModuleUtil.findModuleForFile(target, project) + ?: error("Could not find module for $newTestSourceRoot") + } +} diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/NycSourceFileChooser.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/NycSourceFileChooser.kt similarity index 95% rename from utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/NycSourceFileChooser.kt rename to utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/NycSourceFileChooser.kt index ebe84a48b3..e3683d5a6d 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/NycSourceFileChooser.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/NycSourceFileChooser.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.js +package org.utbot.intellij.plugin.js import com.intellij.openapi.fileChooser.FileChooserDescriptor import com.intellij.openapi.ui.TextBrowseFolderListener diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsLanguageAssistant.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/language/JsLanguageAssistant.kt similarity index 94% rename from utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsLanguageAssistant.kt rename to utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/language/JsLanguageAssistant.kt index 3d3eefe17a..ec84561b6f 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsLanguageAssistant.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/js/language/JsLanguageAssistant.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.js +package org.utbot.intellij.plugin.js.language import com.intellij.lang.Language import com.intellij.lang.ecmascript6.psi.ES6Class @@ -10,15 +10,17 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.editor.Editor import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.idea.util.projectStructure.module +import org.utbot.intellij.plugin.js.JsDialogProcessor import org.utbot.intellij.plugin.language.agnostic.LanguageAssistant import settings.JsTestGenerationSettings.dummyClassName +@Suppress("unused") // is used in org.utbot.intellij.plugin.language.agnostic.LanguageAssistant via reflection object JsLanguageAssistant : LanguageAssistant() { private const val jsId = "ECMAScript 6" @@ -60,7 +62,7 @@ object JsLanguageAssistant : LanguageAssistant() { } else { e.getData(CommonDataKeys.PSI_ELEMENT) ?: return null } - val module = element.module ?: return null + val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null val virtualFile = (e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return null).path val focusedMethod = getContainingMethod(element) containingClass(element)?.let { diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt deleted file mode 100644 index 8c8508953d..0000000000 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.utbot.intellij.plugin.language.js - -import com.intellij.lang.javascript.psi.JSFile -import com.intellij.lang.javascript.refactoring.util.JSMemberInfo -import com.intellij.openapi.module.Module -import com.intellij.openapi.project.Project -import org.utbot.framework.codegen.domain.TestFramework -import org.utbot.intellij.plugin.models.BaseTestsModel -import service.coverage.CoverageMode -import settings.JsTestGenerationSettings.defaultTimeout - -class JsTestsModel( - project: Project, - srcModule: Module, - potentialTestModules: List, - val file: JSFile, - val fileMethods: Set, - var selectedMethods: Set, -) : BaseTestsModel( - project, srcModule, potentialTestModules, emptySet() -) { - - var timeout = defaultTimeout - - lateinit var testFramework: TestFramework - lateinit var containingFilePath: String - var pathToNode: String = "node" - var pathToNYC: String = "nyc" - var pathToNPM: String = "npm" - var coverageMode: CoverageMode = CoverageMode.FAST -} diff --git a/utbot-intellij-main/build.gradle.kts b/utbot-intellij-main/build.gradle.kts new file mode 100644 index 0000000000..30e728a74d --- /dev/null +++ b/utbot-intellij-main/build.gradle.kts @@ -0,0 +1,157 @@ +val semVer: String? by rootProject +val junit5Version: String by rootProject +val junit4PlatformVersion: String by rootProject + +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject +val androidStudioPath: String? by rootProject + +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + +val pythonCommunityPluginVersion: String? by rootProject +val pythonUltimatePluginVersion: String? by rootProject +val goPluginVersion: String? by rootProject + +// https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file +val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" + +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + +plugins { + id("org.jetbrains.intellij") version "1.13.1" +} + +intellij { + + val androidPlugins = listOf("org.jetbrains.android") + + val jvmPlugins = mutableListOf( + "java" + ) + + val kotlinPlugins = listOf( + "org.jetbrains.kotlin" + ) + + androidStudioPath?.let { jvmPlugins += androidPlugins } + + val pythonCommunityPlugins = listOf( + "PythonCore:${pythonCommunityPluginVersion}" + ) + + val pythonUltimatePlugins = listOf( + "Pythonid:${pythonUltimatePluginVersion}" + ) + + val jsPlugins = listOf( + "JavaScript" + ) + + val goPlugins = listOf( + "org.jetbrains.plugins.go:${goPluginVersion}" + ) + + val mavenUtilsPlugins = listOf( + "org.jetbrains.idea.maven" + ) + + val basePluginSet = jvmPlugins + kotlinPlugins + mavenUtilsPlugins + androidPlugins + + plugins.set( + when (projectType) { + communityEdition -> basePluginSet + pythonCommunityPlugins + ultimateEdition -> when (ideType) { + "IC" -> basePluginSet + pythonCommunityPlugins + "IU" -> basePluginSet + pythonUltimatePlugins + jsPlugins + goPlugins + "PC" -> pythonCommunityPlugins + "PY" -> pythonUltimatePlugins + jsPlugins + "GO" -> goPlugins + else -> basePluginSet + } + else -> basePluginSet + } + ) + + version.set(ideVersion) + type.set(ideTypeOrAndroidStudio) + SettingsTemplateHelper.proceed(project) +} + +tasks { + compileKotlin { + kotlinOptions { + jvmTarget = "17" + freeCompilerArgs = freeCompilerArgs + listOf("-Xallow-result-return-type", "-Xsam-conversions=class") + allWarningsAsErrors = false + } + } + + java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + runIde { + jvmArgs("-Xmx2048m") + jvmArgs("--add-exports", "java.desktop/sun.awt.windows=ALL-UNNAMED") + androidStudioPath?.let { ideDir.set(file(it)) } + } + + patchPluginXml { + sinceBuild.set("223") + untilBuild.set("232.*") + version.set(semVer) + } +} + +dependencies { + implementation(project(":utbot-ui-commons")) + + //Family + + if (javaIde?.split(',')?.contains(ideType) == true) { + implementation(project(":utbot-intellij")) + } + + if (pythonIde?.split(',')?.contains(ideType) == true) { + implementation(project(":utbot-python")) + implementation(project(":utbot-intellij-python")) + } + + if (projectType == ultimateEdition) { + if (jsIde?.split(',')?.contains(ideType) == true) { + implementation(project(":utbot-js")) + implementation(project(":utbot-intellij-js")) + } + + if (goIde?.split(',')?.contains(ideType) == true) { + implementation(project(":utbot-go")) + implementation(project(":utbot-intellij-go")) + } + } + + implementation(project(":utbot-android-studio")) + + testImplementation("org.junit.jupiter:junit-jupiter-api:$junit5Version") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junit4PlatformVersion") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junit5Version") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:$junit5Version") +} diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/actions/GenerateTestsAction.kt b/utbot-intellij-main/src/main/kotlin/org/utbot/intellij/plugin/ui/actions/GenerateTestsAction.kt similarity index 100% rename from utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/actions/GenerateTestsAction.kt rename to utbot-intellij-main/src/main/kotlin/org/utbot/intellij/plugin/ui/actions/GenerateTestsAction.kt diff --git a/utbot-intellij/src/main/resources/META-INF/plugin.xml b/utbot-intellij-main/src/main/resources/META-INF/plugin.xml similarity index 83% rename from utbot-intellij/src/main/resources/META-INF/plugin.xml rename to utbot-intellij-main/src/main/resources/META-INF/plugin.xml index 024c39dc04..89f84572f4 100644 --- a/utbot-intellij/src/main/resources/META-INF/plugin.xml +++ b/utbot-intellij-main/src/main/resources/META-INF/plugin.xml @@ -31,13 +31,7 @@ displayName="UnitTestBot"/> - - - - - - @@ -89,15 +83,4 @@ ]]> - - - - diff --git a/utbot-intellij/src/main/resources/META-INF/pluginIcon.svg b/utbot-intellij-main/src/main/resources/META-INF/pluginIcon.svg similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/pluginIcon.svg rename to utbot-intellij-main/src/main/resources/META-INF/pluginIcon.svg diff --git a/utbot-intellij/src/main/resources/META-INF/withAndroid.xml b/utbot-intellij-main/src/main/resources/META-INF/withAndroid.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withAndroid.xml rename to utbot-intellij-main/src/main/resources/META-INF/withAndroid.xml diff --git a/utbot-intellij/src/main/resources/META-INF/withGo.xml b/utbot-intellij-main/src/main/resources/META-INF/withGo.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withGo.xml rename to utbot-intellij-main/src/main/resources/META-INF/withGo.xml diff --git a/utbot-intellij/src/main/resources/META-INF/withIdeaMaven.xml b/utbot-intellij-main/src/main/resources/META-INF/withIdeaMaven.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withIdeaMaven.xml rename to utbot-intellij-main/src/main/resources/META-INF/withIdeaMaven.xml diff --git a/utbot-intellij/src/main/resources/META-INF/withJS.xml b/utbot-intellij-main/src/main/resources/META-INF/withJS.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withJS.xml rename to utbot-intellij-main/src/main/resources/META-INF/withJS.xml diff --git a/utbot-intellij-main/src/main/resources/META-INF/withJava.xml b/utbot-intellij-main/src/main/resources/META-INF/withJava.xml new file mode 100644 index 0000000000..eafe833bc7 --- /dev/null +++ b/utbot-intellij-main/src/main/resources/META-INF/withJava.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/utbot-intellij/src/main/resources/META-INF/withKotlin.xml b/utbot-intellij-main/src/main/resources/META-INF/withKotlin.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withKotlin.xml rename to utbot-intellij-main/src/main/resources/META-INF/withKotlin.xml diff --git a/utbot-intellij/src/main/resources/META-INF/withLang.xml b/utbot-intellij-main/src/main/resources/META-INF/withLang.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withLang.xml rename to utbot-intellij-main/src/main/resources/META-INF/withLang.xml diff --git a/utbot-intellij/src/main/resources/META-INF/withPython.xml b/utbot-intellij-main/src/main/resources/META-INF/withPython.xml similarity index 100% rename from utbot-intellij/src/main/resources/META-INF/withPython.xml rename to utbot-intellij-main/src/main/resources/META-INF/withPython.xml diff --git a/utbot-intellij/src/main/resources/application.properties b/utbot-intellij-main/src/main/resources/application.properties similarity index 100% rename from utbot-intellij/src/main/resources/application.properties rename to utbot-intellij-main/src/main/resources/application.properties diff --git a/utbot-intellij/src/main/resources/bundles/UtbotBundle.properties b/utbot-intellij-main/src/main/resources/bundles/UtbotBundle.properties similarity index 100% rename from utbot-intellij/src/main/resources/bundles/UtbotBundle.properties rename to utbot-intellij-main/src/main/resources/bundles/UtbotBundle.properties diff --git a/utbot-intellij/src/main/resources/inspectionDescriptions/UnitTestBotInspectionTool.html b/utbot-intellij-main/src/main/resources/inspectionDescriptions/UnitTestBotInspectionTool.html similarity index 100% rename from utbot-intellij/src/main/resources/inspectionDescriptions/UnitTestBotInspectionTool.html rename to utbot-intellij-main/src/main/resources/inspectionDescriptions/UnitTestBotInspectionTool.html diff --git a/utbot-intellij/src/main/resources/log4j2.xml b/utbot-intellij-main/src/main/resources/log4j2.xml similarity index 100% rename from utbot-intellij/src/main/resources/log4j2.xml rename to utbot-intellij-main/src/main/resources/log4j2.xml diff --git a/utbot-intellij-main/src/main/resources/settings.properties b/utbot-intellij-main/src/main/resources/settings.properties new file mode 100644 index 0000000000..657e42f4f4 --- /dev/null +++ b/utbot-intellij-main/src/main/resources/settings.properties @@ -0,0 +1,607 @@ +# Copyright (c) 2023 utbot.org +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Setting to disable coroutines debug explicitly. +# Set it to false if debug info is required. +# +# Default value is [true] +#disableCoroutinesDebug=true + +# +# Make `true` for interactive mode (like Intellij plugin). If `false` UTBot can apply certain optimizations. +# +# Default value is [true] +#classfilesCanChange=true + +# +# Timeout for Z3 solver.check calls. +# Set it to 0 to disable timeout. +# +# Default value is [1000] +#checkSolverTimeoutMillis=1000 + +# +# Timeout for symbolic execution +# +# Default value is [60000] +#utBotGenerationTimeoutInMillis=60000 + +# +# Random seed in path selector. +# Set null to disable random. +# +# Default value is [42] +#seedInPathSelector=42 + +# +# Type of path selector. +# +# COVERED_NEW_SELECTOR: [CoveredNewSelector] +# INHERITORS_SELECTOR: [InheritorsSelector] +# BFS_SELECTOR: [BFSSelector] +# SUBPATH_GUIDED_SELECTOR: [SubpathGuidedSelector] +# CPI_SELECTOR: [CPInstSelector] +# FORK_DEPTH_SELECTOR: [ForkDepthSelector] +# ML_SELECTOR: [MLSelector] +# TORCH_SELECTOR: [TorchSelector] +# RANDOM_SELECTOR: [RandomSelector] +# RANDOM_PATH_SELECTOR: [RandomPathSelector] +# +# Default value is [INHERITORS_SELECTOR] +#pathSelectorType=INHERITORS_SELECTOR + +# +# Type of MLSelector recalculation. +# +# WITH_RECALCULATION: [MLSelectorWithRecalculation] +# WITHOUT_RECALCULATION: [MLSelectorWithoutRecalculation] +# +# Default value is [WITHOUT_RECALCULATION] +#mlSelectorRecalculationType=WITHOUT_RECALCULATION + +# +# Type of [MLPredictor]. +# +# MLP: [MultilayerPerceptronPredictor] +# LINREG: [LinearRegressionPredictor] +# +# Default value is [MLP] +#mlPredictorType=MLP + +# +# Steps limit for path selector. +# +# Default value is [3500] +#pathSelectorStepsLimit=3500 + +# +# Determines whether path selector should save remaining states for concrete execution after stopping by strategy. +# False for all framework tests by default. +#saveRemainingStatesForConcreteExecution=true + +# +# Use debug visualization. +# Set it to true if debug visualization is needed. +# +# Default value is [false] +#useDebugVisualization=false + +# +# Set the value to true to show library classes' graphs in visualization. +# +# Default value is [false] +#showLibraryClassesInVisualization=false + +# +# Use simplification of UtExpressions. +# Set it to false to disable expression simplification. +# +# Default value is [true] +#useExpressionSimplification=true + +# +# Enable the Summarization module to generate summaries for methods under test. +# Note: if it is [SummariesGenerationType.NONE], +# all the execution for a particular method will be stored at the same nameless region. +# +# FULL: All possible analysis actions are taken +# LIGHT: Analysis actions based on sources are NOT taken +# NONE: No summaries are generated +# +# Default value is [FULL] +#summaryGenerationType=FULL + +# +# If True test comments will be generated. +# +# Default value is [true] +#enableJavaDocGeneration=true + +# +# If True cluster comments will be generated. +# +# Default value is [true] +#enableClusterCommentsGeneration=true + +# +# If True names for tests will be generated. +# +# Default value is [true] +#enableTestNamesGeneration=true + +# +# If True display names for tests will be generated. +# +# Default value is [true] +#enableDisplayNameGeneration=true + +# +# If True display name in from -> to style will be generated. +# +# Default value is [true] +#useDisplayNameArrowStyle=true + +# +# Generate summaries using plugin's custom JavaDoc tags. +# +# Default value is [true] +#useCustomJavaDocTags=true + +# +# This option regulates which [NullPointerException] check should be performed for nested methods. +# Set an option in true if you want to perform NPE check in the corresponding situations, otherwise set false. +# +# Default value is [true] +#checkNpeInNestedMethods=true + +# +# This option regulates which [NullPointerException] check should be performed for nested not private methods. +# Set an option in true if you want to perform NPE check in the corresponding situations, otherwise set false. +# +# Default value is [false] +#checkNpeInNestedNotPrivateMethods=false + +# +# This option determines whether we should generate [NullPointerException] checks for final or non-public fields +# in non-application classes. Set by true, this option highly decreases test's readability in some cases +# because of using reflection API for setting final/non-public fields in non-application classes. +# NOTE: With false value loses some executions with NPE in system classes, but often most of these executions +# are not expected by user. +# +# Default value is [false] +#maximizeCoverageUsingReflection=false + +# +# Activate or deactivate substituting static fields values set in static initializer +# with symbolic variable to try to set them another value than in initializer. +# +# Default value is [true] +#substituteStaticsWithSymbolicVariable=true + +# +# Use concrete execution. +# +# Default value is [true] +#useConcreteExecution=true + +# +# Enable code generation tests with every possible configuration +# for every method in samples. +# Important: is enabled generation requires enormous amount of time. +# +# Default value is [false] +#checkAllCombinationsForEveryTestInSamples=false + +# +# Enable transformation UtCompositeModels into UtAssembleModels using AssembleModelGenerator. +# Note: false doesn't mean that there will be no assemble models, it means that the generator will be turned off. +# Assemble models will present for lists, sets, etc. +# +# Default value is [true] +#useAssembleModelGenerator=true + +# +# Test related files from the temp directory that are older than [daysLimitForTempFiles] +# will be removed at the beginning of the test run. +# +# Default value is [3] +#daysLimitForTempFiles=3 + +# +# Enables soft constraints in the engine. +# +# Default value is [true] +#preferredCexOption=true + +# +# Type of test minimization strategy. +# +# DO_NOT_MINIMIZE_STRATEGY: Always adds new test +# COVERAGE_STRATEGY: Adds new test only if it increases coverage +# +# Default value is [COVERAGE_STRATEGY] +#testMinimizationStrategyType=COVERAGE_STRATEGY + +# +# Set to true to start fuzzing if symbolic execution haven't return anything +# +# Default value is [true] +#useFuzzing=true + +# +# Set the total attempts to improve coverage by fuzzer. +# +# Default value is [2147483647] +#fuzzingMaxAttempts=2147483647 + +# +# Fuzzer tries to generate and run tests during this time. +# +# Default value is [3000] +#fuzzingTimeoutInMillis=3000 + +# +# Find implementations of interfaces and abstract classes to fuzz. +# +# Default value is [true] +#fuzzingImplementationOfAbstractClasses=true + +# +# Use methods to mutate fields of classes different from class under test or not. +# +# Default value is [false] +#tryMutateOtherClassesFieldsWithMethods=false + +# +# Generate tests that treat possible overflows in arithmetic operations as errors +# that throw Arithmetic Exception. +# +# Default value is [false] +#treatOverflowAsError=false + +# +# Generate tests that treat assertions as error suits. +# +# Default value is [true] +#treatAssertAsErrorSuite=true + +# +# Instrument all classes before start +# +# Default value is [false] +#warmupConcreteExecution=false + +# +# Ignore string literals during the code analysis to make possible to analyze antlr. +# It is a hack and must be removed after the competition. +# +# Default value is [false] +#ignoreStringLiterals=false + +# +# Timeout for specific concrete execution (in milliseconds). +# +# Default value is [1000] +#concreteExecutionDefaultTimeoutInInstrumentedProcessMillis=1000 + +# +# Enable taint analysis or not. +# +# Default value is [false] +#useTaintAnalysis=false + +# +# Path to custom log4j2 configuration file for EngineProcess. +# By default utbot-intellij/src/main/resources/log4j2.xml is used. +# Also default value is used if provided value is not a file. +#engineProcessLogConfigFile="" + +# +# The property is useful only for the IntelliJ IDEs. +# If the property is set in true the engine process opens a debug port. +# @see runInstrumentedProcessWithDebug +# @see org.utbot.intellij.plugin.process.EngineProcess +# +# Default value is [false] +#runEngineProcessWithDebug=false + +# +# The engine process JDWP agent's port of the engine process. +# A debugger attaches to the port in order to debug the process. +# +# Default value is [5005] +#engineProcessDebugPort=5005 + +# +# Value of the suspend mode for the JDWP agent of the engine process. +# If the value is true, the engine process will suspend until a debugger attaches to it. +# +# Default value is [true] +#suspendEngineProcessExecutionInDebugMode=true + +# +# The property is useful only for the IntelliJ IDEs. +# If the property is set in true the spring analyzer process opens a debug port. +# @see runInstrumentedProcessWithDebug +# @see org.utbot.spring.process.SpringAnalyzerProcess +# +# Default value is [false] +#runSpringAnalyzerProcessWithDebug=false + +# +# The spring analyzer process JDWP agent's port. +# A debugger attaches to the port in order to debug the process. +# +# Default value is [5007] +#springAnalyzerProcessDebugPort=5007 + +# +# Value of the suspend mode for the JDWP agent of the spring analyzer process. +# If the value is true, the spring analyzer process will suspend until a debugger attaches to it. +# +# Default value is [true] +#suspendSpringAnalyzerProcessExecutionInDebugMode=true + +# +# The instrumented process JDWP agent's port of the instrumented process. +# A debugger attaches to the port in order to debug the process. +# +# Default value is [5006] +#instrumentedProcessDebugPort=5006 + +# +# Value of the suspend mode for the JDWP agent of the instrumented process. +# If the value is true, the instrumented process will suspend until a debugger attaches to it. +# +# Default value is [true] +#suspendInstrumentedProcessExecutionInDebugMode=true + +# +# If true, runs the instrumented process with the ability to attach a debugger. +# To debug the instrumented process, set the breakpoint in the +# [org.utbot.instrumentation.rd.InstrumentedProcess.Companion.invoke] +# and in the instrumented process's main function and run the main process. +# Then run the remote JVM debug configuration in IDEA. +# If you see the message in console about successful connection, then +# the debugger is attached successfully. +# Now you can put the breakpoints in the instrumented process and debug +# both processes simultaneously. +# @see [org.utbot.instrumentation.rd.InstrumentedProcess.Companion.invoke] +# +# Default value is [false] +#runInstrumentedProcessWithDebug=false + +# +# Number of branch instructions using for clustering executions in the test minimization phase. +# +# Default value is [4] +#numberOfBranchInstructionsForClustering=4 + +# +# Determines should we choose only one crash execution with "minimal" model or keep all. +# +# Default value is [true] +#minimizeCrashExecutions=true + +# +# Enable it to calculate unsat cores for hard constraints as well. +# It may be usefull during debug. +# Note: it might highly impact performance, so do not enable it in release mode. +# +# Default value is [false] +#enableUnsatCoreCalculationForHardConstraints=false + +# +# Enable it to process states with unknown solver status +# from the queue to concrete execution. +# +# Default value is [true] +#processUnknownStatesDuringConcreteExecution=true + +# +# 2^{this} will be the length of observed subpath. +# See [SubpathGuidedSelector] +# +# Default value is [1] +#subpathGuidedSelectorIndex=1 + +# +# Flag that indicates whether feature processing for execution states enabled or not +# +# Default value is [false] +#enableFeatureProcess=false + +# +# Path to deserialized ML models +# +# Default value is [../models/0] +#modelPath=../models/0 + +# +# Full class name of the class containing the configuration for the ML models to solve path selection task. +# +# Default value is [org.utbot.AnalyticsConfiguration] +#analyticsConfigurationClassPath=org.utbot.AnalyticsConfiguration + +# +# Full class name of the class containing the configuration for the ML models exported from the PyTorch to solve path selection task. +# +# Default value is [org.utbot.AnalyticsTorchConfiguration] +#analyticsTorchConfigurationClassPath=org.utbot.AnalyticsTorchConfiguration + +# +# Number of model iterations that will be used during ContestEstimator +# +# Default value is [1] +#iterations=1 + +# +# Path for state features dir +# +# Default value is [eval/secondFeatures/antlr/INHERITORS_SELECTOR] +#featurePath=eval/secondFeatures/antlr/INHERITORS_SELECTOR + +# +# Counter for tests during testGeneration for one project in ContestEstimator +# +# Default value is [0] +#testCounter=0 + +# +# Flag that indicates whether tests for synthetic (see [Executable.isSynthetic]) and implicitly declared methods (like values, valueOf in enums) should be generated, or not +# +# Default value is [true] +#skipTestGenerationForSyntheticAndImplicitlyDeclaredMethods=true + +# +# Flag that indicates whether should we branch on and set static fields from trusted libraries or not. +# @see [org.utbot.common.WorkaroundReason.IGNORE_STATICS_FROM_TRUSTED_LIBRARIES] +# +# Default value is [true] +#ignoreStaticsFromTrustedLibraries=true + +# +# Use the sandbox in the instrumented process. +# If true, the sandbox will prevent potentially dangerous calls, e.g., file access, reading +# or modifying the environment, calls to `Unsafe` methods etc. +# If false, all these operations will be enabled and may lead to data loss during code analysis +# and test generation. +# +# Default value is [true] +#useSandbox=true + +# +# Transform bytecode in the instrumented process. +# If true, bytecode transformation will help fuzzing to find interesting input data, but the size of bytecode can increase. +# If false, bytecode won`t be changed. +# +# Default value is [false] +#useBytecodeTransformation=false + +# +# Limit for number of generated tests per method (in each region) +# +# Default value is [50] +#maxTestsPerMethodInRegion=50 + +# +# Max file length for generated test file +# +# Default value is [1000000] +#maxTestFileSize=1000000 + +# +# If this options set in true, all soot classes will be removed from a Soot Scene, +# therefore, you will be unable to test soot classes. +# +# Default value is [true] +#removeSootClassesFromHierarchy=true + +# +# If this options set in true, all UtBot classes will be removed from a Soot Scene, +# therefore, you will be unable to test UtBot classes. +# +# Default value is [true] +#removeUtBotClassesFromHierarchy=true + +# +# Use this option to enable calculation and logging of MD5 for dropped states by statistics. +# Example of such logging: +# Dropping state (lastStatus=UNDEFINED) by the distance statistics. MD5: 5d0bccc242e87d53578ca0ef64aa5864 +# +# Default value is [false] +#enableLoggingForDroppedStates=false + +# +# If this option set in true, depending on the number of possible types for +# a particular object will be used either type system based on conjunction +# or on bit vectors. +# @see useBitVecBasedTypeSystem +# +# Default value is [true] +#useBitVecBasedTypeSystem=true + +# +# The number of types on which the choice of the type system depends. +# +# Default value is [64] +#maxTypeNumberForEnumeration=64 + +# +# The threshold for numbers of types for which they will be encoded into solver. +# It is used to do not encode big type storages due to significand performance degradation. +# +# Default value is [512] +#maxNumberOfTypesToEncode=512 + +# +# The behaviour of further analysis if tests generation cancellation is requested. +# +# NONE: Do not react on cancellation +# CANCEL_EVERYTHING: Clear all generated test classes +# SAVE_PROCESSED_RESULTS: Show already processed test classes +# +# Default value is [SAVE_PROCESSED_RESULTS] +#cancellationStrategyType=SAVE_PROCESSED_RESULTS + +# +# Depending on this option, sections might be analyzed or not. +# Note that some clinit sections still will be initialized using runtime information. +# +# Default value is [true] +#enableClinitSectionsAnalysis=true + +# +# Process all clinit sections concretely. +# If [enableClinitSectionsAnalysis] is false, it disables effect of this option as well. +# Note that values processed concretely won't be replaced with unbounded symbolic variables. +# +# Default value is [false] +#processAllClinitSectionsConcretely=false + +# +# In cases where we don't have a body for a method, we can either throw an exception +# or treat this a method as a source of an unbounded symbolic variable returned as a result. +# If this option is set in true, instead of analysis we will return an unbounded symbolic +# variable with a corresponding type. Otherwise, an exception will be thrown. +# Default value is false since it is not a common situation when you cannot retrieve a body +# from a regular method. Setting this option in true might be suitable in situations when +# it is more important not to fall at all rather than work precisely. +#treatAbsentMethodsAsUnboundedValue=false + +# +# A maximum size for any array in the program. Note that input arrays might be less than this value +# due to the symbolic engine limitation, see `org.utbot.engine.Traverser.softMaxArraySize`. +# +# Default value is [1024] +#maxArraySize=1024 + +# +# A maximum size for any array in the program. Note that input arrays might be less than this value +# due to the symbolic engine limitation, see `org.utbot.engine.Traverser.softMaxArraySize`. +# +# Default value is [false] +#disableUnsatChecking=false + +# +# When generating integration tests we only partially reset context in between executions to save time. +# For example, entity id generators do not get reset. It may lead to non-reproduceable results if +# IDs leak to the output of the method under test. +# To cope with that, we rerun executions that are left after minimization, fully resetting Spring context +# between executions. However, full context reset is slow, so we use this setting to limit number of +# tests per method that are rerun with full context reset in case minimization outputs too many tests. +# +# Default value is [25] +#maxSpringContextResetsPerMethod=25 diff --git a/utbot-intellij/src/test/resources/application.properties b/utbot-intellij-main/src/test/resources/application.properties similarity index 100% rename from utbot-intellij/src/test/resources/application.properties rename to utbot-intellij-main/src/test/resources/application.properties diff --git a/utbot-intellij/src/test/resources/junit-platform.properties b/utbot-intellij-main/src/test/resources/junit-platform.properties similarity index 100% rename from utbot-intellij/src/test/resources/junit-platform.properties rename to utbot-intellij-main/src/test/resources/junit-platform.properties diff --git a/utbot-intellij/src/test/resources/log4j.properties b/utbot-intellij-main/src/test/resources/log4j.properties similarity index 100% rename from utbot-intellij/src/test/resources/log4j.properties rename to utbot-intellij-main/src/test/resources/log4j.properties diff --git a/utbot-intellij/src/test/resources/log4j2.xml b/utbot-intellij-main/src/test/resources/log4j2.xml similarity index 100% rename from utbot-intellij/src/test/resources/log4j2.xml rename to utbot-intellij-main/src/test/resources/log4j2.xml diff --git a/utbot-intellij-python/build.gradle.kts b/utbot-intellij-python/build.gradle.kts index bf7d404342..cf1e5ea9f1 100644 --- a/utbot-intellij-python/build.gradle.kts +++ b/utbot-intellij-python/build.gradle.kts @@ -2,16 +2,43 @@ val intellijPluginVersion: String? by rootProject val kotlinLoggingVersion: String? by rootProject val apacheCommonsTextVersion: String? by rootProject val jacksonVersion: String? by rootProject -val ideType: String? by rootProject -val ideVersion: String by rootProject + +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject +val androidStudioPath: String? by rootProject + +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + val pythonCommunityPluginVersion: String? by rootProject val pythonUltimatePluginVersion: String? by rootProject val goPluginVersion: String? by rootProject +// https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file +val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" + +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + plugins { id("org.jetbrains.intellij") version "1.13.1" } -project.tasks.asMap["runIde"]?.enabled = false tasks { compileKotlin { @@ -46,10 +73,16 @@ intellij { val androidPlugins = listOf("org.jetbrains.android") - val jvmPlugins = listOf( + val jvmPlugins = mutableListOf( "java" ) + val kotlinPlugins = listOf( + "org.jetbrains.kotlin" + ) + + androidStudioPath?.let { jvmPlugins += androidPlugins } + val pythonCommunityPlugins = listOf( "PythonCore:${pythonCommunityPluginVersion}" ) @@ -66,13 +99,24 @@ intellij { "org.jetbrains.plugins.go:${goPluginVersion}" ) + val mavenUtilsPlugins = listOf( + "org.jetbrains.idea.maven" + ) + + val basePluginSet = jvmPlugins + kotlinPlugins + mavenUtilsPlugins + androidPlugins + plugins.set( - when (ideType) { - "IC" -> jvmPlugins + pythonCommunityPlugins + androidPlugins - "IU" -> jvmPlugins + pythonUltimatePlugins + jsPlugins + goPlugins + androidPlugins - "PC" -> pythonCommunityPlugins - "PY" -> pythonUltimatePlugins // something else, JS? - else -> jvmPlugins + when (projectType) { + communityEdition -> basePluginSet + pythonCommunityPlugins + ultimateEdition -> when (ideType) { + "IC" -> basePluginSet + pythonCommunityPlugins + "IU" -> basePluginSet + pythonUltimatePlugins + jsPlugins + goPlugins + "PC" -> pythonCommunityPlugins + "PY" -> pythonUltimatePlugins + jsPlugins + "GO" -> goPlugins + else -> basePluginSet + } + else -> basePluginSet } ) diff --git a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyClassItem.java b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyClassItem.java similarity index 93% rename from utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyClassItem.java rename to utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyClassItem.java index 5752c563f0..f49036a20a 100644 --- a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyClassItem.java +++ b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyClassItem.java @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.table; +package org.utbot.intellij.plugin.python.table; import com.intellij.icons.AllIcons; import com.jetbrains.python.psi.PyClass; diff --git a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyFunctionItem.java b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyFunctionItem.java similarity index 93% rename from utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyFunctionItem.java rename to utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyFunctionItem.java index d3c9fdf512..b5564512e7 100644 --- a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyFunctionItem.java +++ b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyFunctionItem.java @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.table; +package org.utbot.intellij.plugin.python.table; import com.intellij.icons.AllIcons; import com.jetbrains.python.psi.PyElement; diff --git a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyMemberSelectionTable.java b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyMemberSelectionTable.java similarity index 99% rename from utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyMemberSelectionTable.java rename to utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyMemberSelectionTable.java index f11d7a606a..26233b9dfe 100644 --- a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyMemberSelectionTable.java +++ b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyMemberSelectionTable.java @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.table; +package org.utbot.intellij.plugin.python.table; import com.intellij.openapi.actionSystem.BackgroundableDataProvider; import com.intellij.openapi.actionSystem.CommonDataKeys; diff --git a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyTableItem.java b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyTableItem.java similarity index 82% rename from utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyTableItem.java rename to utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyTableItem.java index 9d3da4e6f1..c1e413016a 100644 --- a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/UtPyTableItem.java +++ b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/UtPyTableItem.java @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.table; +package org.utbot.intellij.plugin.python.table; import com.jetbrains.python.psi.PyElement; diff --git a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/Utils.java b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/Utils.java similarity index 92% rename from utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/Utils.java rename to utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/Utils.java index 7667a77c50..0f23b1ba4c 100644 --- a/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/language/python/table/Utils.java +++ b/utbot-intellij-python/src/main/java/org/utbot/intellij/plugin/python/table/Utils.java @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.table; +package org.utbot.intellij.plugin.python.table; import java.util.HashSet; import java.util.List; diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/IntellijRequirementsInstaller.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/IntellijRequirementsInstaller.kt similarity index 98% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/IntellijRequirementsInstaller.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/IntellijRequirementsInstaller.kt index 2bea00fc73..08aa8110db 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/IntellijRequirementsInstaller.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/IntellijRequirementsInstaller.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python import com.intellij.notification.NotificationType import com.intellij.openapi.application.invokeLater diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogProcessor.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogProcessor.kt similarity index 95% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogProcessor.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogProcessor.kt index a962ecc1e3..86eb6b4d56 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogProcessor.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogProcessor.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.invokeLater @@ -23,16 +23,12 @@ import com.jetbrains.python.psi.PyClass import com.jetbrains.python.psi.PyElement import com.jetbrains.python.psi.PyFile import com.jetbrains.python.psi.PyFunction -import com.jetbrains.python.psi.resolve.QualifiedNameFinder import com.jetbrains.python.sdk.pythonSdk import mu.KotlinLogging -import org.jetbrains.kotlin.idea.base.util.module -import org.jetbrains.kotlin.idea.base.util.sdk import org.utbot.common.PathUtil.toPath import org.utbot.framework.plugin.api.util.LockFile import org.utbot.intellij.plugin.settings.Settings import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater -import org.utbot.intellij.plugin.ui.utils.testModules import org.utbot.python.PythonMethodHeader import org.utbot.python.PythonTestGenerationConfig import org.utbot.python.utils.RequirementsInstaller @@ -147,8 +143,6 @@ object PythonDialogProcessor { focusedElement: PyElement?, pythonPath: String, ): PythonDialogWindow { - val srcModules = findSrcModules(elementsToShow) - val testModules = srcModules.flatMap {it.testModules(project)} val focusedElements = focusedElement ?.let { setOf(focusedElement.toUtPyTableItem()).filterNotNull() } ?.toSet() @@ -156,8 +150,6 @@ object PythonDialogProcessor { return PythonDialogWindow( PythonTestsModel( project, - srcModules.first(), - testModules, elementsToShow, focusedElements, project.service().generationTimeoutInMillis, @@ -339,18 +331,10 @@ fun getPythonPath(project: Project): String? { return project.pythonSdk?.homePath } -fun findSrcModules(elements: Collection): List { - return elements.mapNotNull { it.module }.distinct() -} - fun getSrcModule(element: PyElement): Module { return ModuleUtilCore.findModuleForPsiElement(element) ?: error("Module for source class or function not found") } -fun getFullName(element: PyElement): String { - return QualifiedNameFinder.getQualifiedName(element) ?: error("Name for source class or function not found") -} - fun getContentFromPyFile(file: PyFile) = ReadAction.nonBlocking { file.viewProvider.contents.toString() diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogWindow.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogWindow.kt similarity index 90% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogWindow.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogWindow.kt index e675499ac7..550ab70748 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonDialogWindow.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogWindow.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python import com.intellij.openapi.components.service import com.intellij.openapi.ui.ComboBox @@ -16,19 +16,16 @@ import com.jetbrains.python.psi.PyClass import com.jetbrains.python.psi.PyFunction import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.TestFramework -import org.utbot.intellij.plugin.language.python.settings.PythonTestFrameworkMapper -import org.utbot.intellij.plugin.language.python.settings.loadStateFromModel -import org.utbot.intellij.plugin.language.python.table.UtPyClassItem -import org.utbot.intellij.plugin.language.python.table.UtPyFunctionItem -import org.utbot.intellij.plugin.language.python.table.UtPyMemberSelectionTable -import org.utbot.intellij.plugin.language.python.table.UtPyTableItem +import org.utbot.intellij.plugin.python.settings.PythonTestFrameworkMapper +import org.utbot.intellij.plugin.python.settings.loadStateFromModel +import org.utbot.intellij.plugin.python.table.UtPyClassItem +import org.utbot.intellij.plugin.python.table.UtPyFunctionItem +import org.utbot.intellij.plugin.python.table.UtPyMemberSelectionTable +import org.utbot.intellij.plugin.python.table.UtPyTableItem import org.utbot.intellij.plugin.settings.Settings import org.utbot.intellij.plugin.ui.components.TestSourceDirectoryChooser import org.utbot.intellij.plugin.ui.utils.createTestFrameworksRenderer -import java.awt.event.ActionEvent import java.util.concurrent.TimeUnit -import javax.swing.AbstractAction -import javax.swing.Action import javax.swing.DefaultComboBoxModel import javax.swing.JComponent @@ -113,7 +110,7 @@ class PythonDialogWindow(val model: PythonTestsModel) : DialogWrapper(model.proj val functionItems = functions .groupBy { it.containingClass } .flatMap { (_, pyFuncs) -> - pyFuncs.map {UtPyFunctionItem(it)} + pyFuncs.map { UtPyFunctionItem(it) } } val classItems = classes.map { UtPyClassItem(it) diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonIntellijProcessor.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonIntellijProcessor.kt similarity index 92% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonIntellijProcessor.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonIntellijProcessor.kt index 89f2c498ec..bb1408958f 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonIntellijProcessor.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonIntellijProcessor.kt @@ -1,12 +1,13 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python -import com.intellij.codeInsight.CodeInsightUtil import com.intellij.openapi.application.invokeLater import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.project.Project import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiFileFactory import com.jetbrains.python.psi.PyClass +import org.utbot.intellij.plugin.python.language.PythonLanguageAssistant import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import org.utbot.python.PythonTestGenerationConfig import org.utbot.python.PythonTestGenerationProcessor @@ -30,7 +31,7 @@ class PythonIntellijProcessor( testDir.findFile(testPsiFile.name)?.delete() testDir.add(testPsiFile) val file = testDir.findFile(testPsiFile.name)!! - CodeInsightUtil.positionCursor(model.project, file, file) + OpenFileDescriptor(project, file.virtualFile).navigate(true) } } } diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonTestsModel.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonTestsModel.kt similarity index 85% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonTestsModel.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonTestsModel.kt index f0d4ff007f..a0ce0e4984 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonTestsModel.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/PythonTestsModel.kt @@ -1,6 +1,5 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python -import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.jetbrains.python.psi.PyClass import com.jetbrains.python.psi.PyElement @@ -8,13 +7,11 @@ import com.jetbrains.python.psi.PyFile import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.services.language.CgLanguageAssistant -import org.utbot.intellij.plugin.language.python.table.UtPyTableItem +import org.utbot.intellij.plugin.python.table.UtPyTableItem import org.utbot.intellij.plugin.models.BaseTestsModel class PythonTestsModel( project: Project, - srcModule: Module, - potentialTestModules: List, val elementsToDisplay: Set, val focusedElements: Set?, var timeout: Long, @@ -24,8 +21,6 @@ class PythonTestsModel( val names: Map, PyElement>, ) : BaseTestsModel( project, - srcModule, - potentialTestModules ) { lateinit var testSourceRootPath: String lateinit var testFramework: TestFramework diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/Utils.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/Utils.kt similarity index 91% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/Utils.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/Utils.kt index e8b285afc6..783126ffcc 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/Utils.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/Utils.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectFileIndex @@ -9,9 +9,9 @@ import com.intellij.psi.PsiElement import com.jetbrains.python.psi.PyClass import com.jetbrains.python.psi.PyElement import com.jetbrains.python.psi.PyFunction -import org.utbot.intellij.plugin.language.python.table.UtPyClassItem -import org.utbot.intellij.plugin.language.python.table.UtPyFunctionItem -import org.utbot.intellij.plugin.language.python.table.UtPyTableItem +import org.utbot.intellij.plugin.python.table.UtPyClassItem +import org.utbot.intellij.plugin.python.table.UtPyFunctionItem +import org.utbot.intellij.plugin.python.table.UtPyTableItem import org.utbot.python.utils.RequirementsUtils import kotlin.random.Random diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonLanguageAssistant.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/language/PythonLanguageAssistant.kt similarity index 93% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonLanguageAssistant.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/language/PythonLanguageAssistant.kt index 84d304a8f4..8c8a9a3a82 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/PythonLanguageAssistant.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/language/PythonLanguageAssistant.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python +package org.utbot.intellij.plugin.python.language import com.intellij.lang.Language import com.intellij.openapi.actionSystem.AnActionEvent @@ -7,19 +7,16 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiDirectory -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiFileSystemItem +import com.intellij.psi.* import com.intellij.psi.util.PsiTreeUtil import com.jetbrains.python.psi.PyClass import com.jetbrains.python.psi.PyFile import com.jetbrains.python.psi.PyFunction -import org.jetbrains.kotlin.idea.core.util.toPsiDirectory -import org.jetbrains.kotlin.idea.core.util.toPsiFile import org.utbot.framework.plugin.api.util.LockFile import org.utbot.intellij.plugin.language.agnostic.LanguageAssistant +import org.utbot.intellij.plugin.python.* +@Suppress("unused") // is used in org.utbot.intellij.plugin.language.agnostic.LanguageAssistant via reflection object PythonLanguageAssistant : LanguageAssistant() { private const val pythonID = "Python" @@ -139,8 +136,12 @@ object PythonLanguageAssistant : LanguageAssistant() { } private fun getAllElements(project: Project, virtualFiles: Collection): Pair, Set> { - val psiFiles = virtualFiles.mapNotNull { it.toPsiFile(project) } - val psiDirectories = virtualFiles.mapNotNull { it.toPsiDirectory(project) } + val psiFiles = virtualFiles.mapNotNull { + PsiManager.getInstance(project).findFile(it) + } + val psiDirectories = virtualFiles.mapNotNull { + PsiManager.getInstance(project).findDirectory(it) + } val classes = psiFiles.flatMap { getClassesFromFile(it) }.toMutableSet() val functions = psiFiles.flatMap { getFunctionsFromFile(it) }.toMutableSet() diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/PythonTestFrameworkMapper.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/PythonTestFrameworkMapper.kt similarity index 95% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/PythonTestFrameworkMapper.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/PythonTestFrameworkMapper.kt index 57d8383441..0e2b60ac75 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/PythonTestFrameworkMapper.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/PythonTestFrameworkMapper.kt @@ -1,4 +1,4 @@ -package org.utbot.intellij.plugin.language.python.settings +package org.utbot.intellij.plugin.python.settings import org.utbot.framework.codegen.domain.TestFramework import org.utbot.intellij.plugin.settings.TestFrameworkMapper diff --git a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/Settings.kt b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/Settings.kt similarity index 84% rename from utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/Settings.kt rename to utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/Settings.kt index 5c46f4d53b..a61dfcb5f7 100644 --- a/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/language/python/settings/Settings.kt +++ b/utbot-intellij-python/src/main/kotlin/org/utbot/intellij/plugin/python/settings/Settings.kt @@ -1,7 +1,7 @@ -package org.utbot.intellij.plugin.language.python.settings +package org.utbot.intellij.plugin.python.settings import org.utbot.framework.codegen.domain.HangingTestsTimeout -import org.utbot.intellij.plugin.language.python.PythonTestsModel +import org.utbot.intellij.plugin.python.PythonTestsModel import org.utbot.intellij.plugin.settings.Settings fun loadStateFromModel(settings: Settings, model: PythonTestsModel) { diff --git a/utbot-intellij/build.gradle.kts b/utbot-intellij/build.gradle.kts index afd5662b64..8f0520b4a9 100644 --- a/utbot-intellij/build.gradle.kts +++ b/utbot-intellij/build.gradle.kts @@ -1,34 +1,49 @@ -val projectType: String by rootProject -val communityEdition: String by rootProject -val ultimateEdition: String by rootProject - val intellijPluginVersion: String? by rootProject val kotlinLoggingVersion: String? by rootProject val apacheCommonsTextVersion: String? by rootProject val jacksonVersion: String? by rootProject -val ideType: String? by rootProject -val ideVersion: String? by rootProject -val pythonCommunityPluginVersion: String? by rootProject -val pythonUltimatePluginVersion: String? by rootProject -val goPluginVersion: String? by rootProject - -val pythonIde: String? by rootProject -val jsIde: String? by rootProject -val goIde: String? by rootProject - val sootVersion: String? by rootProject val kryoVersion: String? by rootProject val rdVersion: String? by rootProject val semVer: String? by rootProject -val androidStudioPath: String? by rootProject val junit5Version: String by rootProject val junit4PlatformVersion: String by rootProject +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject +val androidStudioPath: String? by rootProject + +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + +val pythonCommunityPluginVersion: String? by rootProject +val pythonUltimatePluginVersion: String? by rootProject +val goPluginVersion: String? by rootProject + // https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + plugins { id("org.jetbrains.intellij") version "1.13.1" } @@ -41,7 +56,7 @@ intellij { "java" ) - val kotlinPlugins = mutableListOf( + val kotlinPlugins = listOf( "org.jetbrains.kotlin" ) @@ -76,7 +91,8 @@ intellij { "IC" -> basePluginSet + pythonCommunityPlugins "IU" -> basePluginSet + pythonUltimatePlugins + jsPlugins + goPlugins "PC" -> pythonCommunityPlugins - "PY" -> pythonUltimatePlugins // something else, JS? + "PY" -> pythonUltimatePlugins + jsPlugins + "GO" -> goPlugins else -> basePluginSet } else -> basePluginSet @@ -85,7 +101,6 @@ intellij { version.set(ideVersion) type.set(ideTypeOrAndroidStudio) - SettingsTemplateHelper.proceed(project) } val remoteRobotVersion = "0.11.16" @@ -164,26 +179,6 @@ dependencies { testApi(project(":utbot-framework")) implementation(project(":utbot-ui-commons")) - - //Family - - if (pythonIde?.split(',')?.contains(ideType) == true) { - implementation(project(":utbot-python")) - implementation(project(":utbot-intellij-python")) - } - - if (projectType == ultimateEdition) { - if (jsIde?.split(',')?.contains(ideType) == true) { - implementation(project(":utbot-js")) - implementation(project(":utbot-intellij-js")) - } - - if (goIde?.split(',')?.contains(ideType) == true) { - implementation(project(":utbot-go")) - implementation(project(":utbot-intellij-go")) - } - } - implementation(project(":utbot-android-studio")) testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion") 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 8c0e78c69d..550c366084 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 @@ -72,9 +72,6 @@ import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.codegen.tree.ututils.UtilClassKind.Companion.UT_UTILS_INSTANCE_NAME import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage -import org.utbot.framework.plugin.api.util.utContext -import org.utbot.framework.plugin.api.util.withUtContext -import org.utbot.framework.plugin.api.utils.ClassNameUtils.generateTestClassShortName import org.utbot.intellij.plugin.inspection.UnitTestBotInspectionManager import org.utbot.intellij.plugin.models.GenerateTestsModel import org.utbot.intellij.plugin.models.packageName @@ -90,7 +87,6 @@ import org.utbot.intellij.plugin.ui.WarningTestsReportNotifier import org.utbot.intellij.plugin.ui.utils.getOrCreateSarifReportsPath import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots -import org.utbot.intellij.plugin.util.IntelliJApiHelper import org.utbot.intellij.plugin.util.IntelliJApiHelper.Target.EDT_LATER import org.utbot.intellij.plugin.util.IntelliJApiHelper.Target.THREAD_POOL import org.utbot.intellij.plugin.util.IntelliJApiHelper.Target.WRITE_ACTION diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt index 1d43bd9163..94fed03ce8 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt @@ -576,7 +576,7 @@ object UtTestsDialogProcessor { val classpathList = pathsList.pathList Pair(classpath, classpathList) } - val pluginJarsPath = Paths.get(PathManager.getPluginsPath(), "utbot-intellij", "lib").toFile().listFiles() + val pluginJarsPath = Paths.get(PathManager.getPluginsPath(), "utbot-intellij-main", "lib").toFile().listFiles() ?: error("Can't find plugin folder.") return BuildPaths(buildDirs, classpath, classpathList, pluginJarsPath.map { it.path }) } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/language/JavaLanguage.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/language/JavaLanguage.kt index c1afd584aa..b755acd5f9 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/language/JavaLanguage.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/language/JavaLanguage.kt @@ -32,6 +32,7 @@ import org.utbot.intellij.plugin.ui.InvalidClassNotifier import org.utbot.intellij.plugin.language.agnostic.LanguageAssistant import org.utbot.intellij.plugin.util.findSdkVersionOrNull +@Suppress("unused") // is used in org.utbot.intellij.plugin.language.agnostic.LanguageAssistant via reflection object JvmLanguageAssistant : LanguageAssistant() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return @@ -100,7 +101,7 @@ object JvmLanguageAssistant : LanguageAssistant() { val memberInfoList = runReadAction> { it.extractFirstLevelMembers(false) } - if (memberInfoList.isNullOrEmpty()) + if (memberInfoList.isEmpty()) return null } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt index bf071056e4..3c23f56b51 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt @@ -8,12 +8,22 @@ import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.project.Project +import com.intellij.openapi.project.rootManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile +import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.PsiJavaFile +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.searches.AnnotatedElementsSearch import com.intellij.refactoring.util.classMembers.MemberInfo import org.jetbrains.concurrency.Promise +import org.jetbrains.kotlin.idea.util.projectStructure.allModules +import org.jetbrains.kotlin.idea.util.sourceRoot import org.jetbrains.kotlin.psi.KtFile +import org.utbot.common.PathUtil.fileExtension import org.utbot.framework.SummariesGenerationType import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.ClassId @@ -24,12 +34,29 @@ import org.utbot.framework.plugin.api.SpringTestType import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.util.ConflictTriggers import org.utbot.intellij.plugin.settings.Settings +import org.utbot.intellij.plugin.ui.utils.* +import org.utbot.intellij.plugin.util.binaryName +import java.nio.file.Files +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory +import kotlin.streams.asSequence + +const val HISTORY_LIMIT = 10 + +const val SPRINGBOOT_APPLICATION_FQN = "org.springframework.boot.autoconfigure.SpringBootApplication" +const val SPRINGBOOT_CONFIGURATION_FQN = "org.springframework.boot.SpringBootConfiguration" +const val SPRING_CONFIGURATION_ANNOTATION_FQN = "org.springframework.context.annotation.Configuration" +const val SPRING_TESTCONFIGURATION_ANNOTATION_FQN = "org.springframework.boot.test.context.TestConfiguration" + +const val SPRING_BEANS_SCHEMA_URL = "http://www.springframework.org/schema/beans" +const val SPRING_LOAD_DTD_GRAMMAR_PROPERTY = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar" +const val SPRING_LOAD_EXTERNAL_DTD_PROPERTY = "http://apache.org/xml/features/nonvalidating/load-external-dtd" class GenerateTestsModel( project: Project, - srcModule: Module, - potentialTestModules: List, - srcClasses: Set, + val srcModule: Module, + val potentialTestModules: List, + var srcClasses: Set, val extractMembersFromSrcClasses: Boolean, var selectedMembers: Set, var timeout: Long, @@ -37,10 +64,11 @@ class GenerateTestsModel( var fuzzingValue: Double = 0.05 ): BaseTestsModel( project, - srcModule, - potentialTestModules, - srcClasses ) { + // GenerateTestsModel is supposed to be created with non-empty list of potentialTestModules. + // Otherwise, the error window is supposed to be shown earlier. + var testModule: Module = potentialTestModules.firstOrNull() ?: error("Empty list of test modules in model") + override var sourceRootHistory = project.service().sourceRootHistory override var codegenLanguage = project.service().codegenLanguage @@ -65,6 +93,145 @@ class GenerateTestsModel( var runGeneratedTestsWithCoverage : Boolean = false var summariesGenerationType : SummariesGenerationType = UtSettings.summaryGenerationType + + fun setSourceRootAndFindTestModule(newTestSourceRoot: VirtualFile?) { + requireNotNull(newTestSourceRoot) + testSourceRoot = newTestSourceRoot + var target = newTestSourceRoot + while (target != null && target is FakeVirtualFile) { + target = target.parent + } + if (target == null) { + error("Could not find module for $newTestSourceRoot") + } + + testModule = ModuleUtil.findModuleForFile(target, project) + ?: error("Could not find module for $newTestSourceRoot") + } + + val isMultiPackage: Boolean by lazy { + srcClasses.map { it.packageName }.distinct().size != 1 + } + + fun getAllTestSourceRoots() : MutableList { + with(if (project.isBuildWithGradle) project.allModules() else potentialTestModules) { + return this.flatMap { it.suitableTestSourceRoots().toList() }.toMutableList().distinct().toMutableList() + } + } + + fun getSortedTestRoots(): MutableList = getSortedTestRoots( + getAllTestSourceRoots(), + sourceRootHistory, + srcModule.rootManager.sourceRoots.map { file: VirtualFile -> file.toNioPath().toString() }, + codegenLanguage + ) + + /** + * Finds @SpringBootApplication classes in Spring application. + * + * @see [getSortedAnnotatedClasses] + */ + fun getSortedSpringBootApplicationClasses(): Set = + getSortedAnnotatedClasses(SPRINGBOOT_CONFIGURATION_FQN) + + getSortedAnnotatedClasses(SPRINGBOOT_APPLICATION_FQN) + + /** + * Finds @TestConfiguration and @Configuration classes in Spring application. + * + * @see [getSortedAnnotatedClasses] + */ + fun getSortedSpringConfigurationClasses(): Set = + getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION_FQN) + + getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION_FQN) + + /** + * Finds classes annotated with given annotation in [srcModule] and [potentialTestModules]. + * + * Sorting order: + * - classes from test source roots (in the order provided by [getSortedTestRoots]) + * - classes from production source roots + */ + private fun getSortedAnnotatedClasses(annotationFqn: String): Set { + val searchScope = + potentialTestModules + .fold(GlobalSearchScope.moduleScope(srcModule)) { accScope, module -> + accScope.union(GlobalSearchScope.moduleScope(module)) + } + + val annotationClass = JavaPsiFacade + .getInstance(project) + .findClass(annotationFqn, GlobalSearchScope.allScope(project)) + ?: return emptySet() + + val testRootToIndex = + getSortedTestRoots() + .withIndex() + .associate { (i, root) -> root.dir to i } + + return AnnotatedElementsSearch + .searchPsiClasses(annotationClass, searchScope) + .findAll() + .sortedBy { testRootToIndex[it.containingFile.sourceRoot] ?: Int.MAX_VALUE } + .mapNotNullTo(mutableSetOf()) { it.binaryName } + } + + fun getSpringXMLConfigurationFiles(): Set { + val resourcesPaths = + buildList { + addAll(potentialTestModules) + add(srcModule) + }.distinct().flatMapTo(mutableSetOf()) { it.getResourcesPaths() } + val xmlFilePaths = resourcesPaths.flatMapTo(mutableListOf()) { path -> + Files.walk(path) + .asSequence() + .filter { it.fileExtension == ".xml" } + } + + val builder = customizeXmlBuilder() + return xmlFilePaths.mapNotNullTo(mutableSetOf()) { path -> + try { + val doc = builder.parse(path.toFile()) + + val hasBeanTagName = doc.documentElement.tagName == "beans" + val hasAttribute = doc.documentElement.getAttribute("xmlns") == SPRING_BEANS_SCHEMA_URL + when { + hasBeanTagName && hasAttribute -> path.toString() + else -> null + } + } catch (e: Exception) { + // `DocumentBuilder.parse` is an unpredictable operation, may have some side effects, we suppress them. + null + } + } + } + + /** + * Creates "safe" xml builder instance. + * + * Using standard `DocumentBuilderFactory.newInstance()` may lead to some problems like + * https://stackoverflow.com/questions/343383/unable-to-parse-xml-file-using-documentbuilder. + * + * We try to solve it in accordance with top-rated recommendation here + * https://stackoverflow.com/questions/155101/make-documentbuilder-parse-ignore-dtd-references. + */ + private fun customizeXmlBuilder(): DocumentBuilder { + val builderFactory = DocumentBuilderFactory.newInstance() + builderFactory.isNamespaceAware = true + + // See documentation https://xerces.apache.org/xerces2-j/features.html + builderFactory.setFeature(SPRING_LOAD_DTD_GRAMMAR_PROPERTY, false) + builderFactory.setFeature(SPRING_LOAD_EXTERNAL_DTD_PROPERTY, false) + + return builderFactory.newDocumentBuilder() + } + + fun updateSourceRootHistory(path: String) { + sourceRootHistory.apply { + remove(path)//Remove existing entry if any + add(path)//Add the most recent entry to the end to be brought first at sorting, see org.utbot.intellij.plugin.ui.utils.RootUtilsKt.getSortedTestRoots + while (size > HISTORY_LIMIT) removeFirst() + } + } } val PsiClass.packageName: String diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/JavaConfigurable.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/JavaConfigurable.kt new file mode 100644 index 0000000000..b22f57ce78 --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/JavaConfigurable.kt @@ -0,0 +1,23 @@ +package org.utbot.intellij.plugin.settings + +import com.intellij.openapi.options.SearchableConfigurable +import com.intellij.openapi.project.Project +import javax.swing.JComponent + +class JavaConfigurable(val project: Project) : SearchableConfigurable { + private val displayName: String = "UtBot Java Configuration" + private val id: String = "org.utbot.intellij.plugin.settings.UtBotSettingsConfigurableJava" + private val settingsWindow = SettingsWindow(project) + + override fun createComponent(): JComponent = settingsWindow.panel + + override fun isModified(): Boolean = settingsWindow.isModified() + + override fun apply() = settingsWindow.apply() + + override fun reset() = settingsWindow.reset() + + override fun getDisplayName(): String = displayName + + override fun getId(): String = id +} \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt index 06d17cbd99..4474e95217 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt @@ -16,8 +16,6 @@ import kotlin.reflect.KClass import org.utbot.framework.SummariesGenerationType import org.utbot.framework.UtSettings import org.utbot.framework.codegen.domain.ForceStaticMocking -import org.utbot.framework.codegen.domain.HangingTestsTimeout -import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.plugin.api.CodeGenerationSettingItem import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.JavaDocCommentStyle @@ -36,7 +34,6 @@ class SettingsWindow(val project: Project) { private lateinit var runInspectionAfterTestGenerationCheckBox: JCheckBox private lateinit var forceMockCheckBox: JCheckBox private lateinit var enableSummarizationGenerationCheckBox: JCheckBox - private lateinit var enableExperimentalLanguagesCheckBox: JCheckBox private fun Row.createCombo(loader: KClass<*>, values: Array<*>) { comboBox(DefaultComboBoxModel(values)) @@ -47,200 +44,164 @@ class SettingsWindow(val project: Project) { } val panel: JPanel = panel { - row("Generated test language:") { - codegenLanguageCombo = comboBox(DefaultComboBoxModel(CodegenLanguage.values())).gap(RightGap.COLUMNS) - .apply { - component.renderer = CodeGenerationSettingItemRenderer() - ContextHelpLabel.create("You can generate test methods in Java or Kotlin regardless of your source code language.") - }.bindItem( - getter = { settings.providerNameByServiceLoader(CodegenLanguage::class) as CodegenLanguage }, - setter = { - settings.setProviderByLoader( - CodegenLanguage::class, - it as CodeGenerationSettingItem - ) + group("Java Specific Settings") { + row("Generated test language:") { + codegenLanguageCombo = comboBox(DefaultComboBoxModel(CodegenLanguage.values())).gap(RightGap.COLUMNS) + .apply { + component.renderer = CodeGenerationSettingItemRenderer() + ContextHelpLabel.create("You can generate test methods in Java or Kotlin regardless of your source code language.") + }.bindItem( + getter = { settings.providerNameByServiceLoader(CodegenLanguage::class) as CodegenLanguage }, + setter = { + settings.setProviderByLoader( + CodegenLanguage::class, + it as CodeGenerationSettingItem + ) + } + ).component + codegenLanguageCombo.addActionListener { + if (!codegenLanguageCombo.item.isSummarizationCompatible()) { + enableSummarizationGenerationCheckBox.isSelected = false } - ).component - codegenLanguageCombo.addActionListener { - if (!codegenLanguageCombo.item.isSummarizationCompatible()) { - enableSummarizationGenerationCheckBox.isSelected = false } - } + }.bottomGap(BottomGap.MEDIUM) - enableExperimentalLanguagesCheckBox = checkBox("Experimental languages support") - .onApply { - settings.state.enableExperimentalLanguagesSupport = - enableExperimentalLanguagesCheckBox.isSelected - } - .onReset { - enableExperimentalLanguagesCheckBox.isSelected = - settings.experimentalLanguagesSupport == true - } - .onIsModified { enableExperimentalLanguagesCheckBox.isSelected xor settings.experimentalLanguagesSupport } - .component - contextHelp("Enable JavaScript and Python if IDE supports them") - }.bottomGap(BottomGap.MEDIUM) + row("Overflow detection:") { + createCombo(TreatOverflowAsError::class, TreatOverflowAsError.values()) + } - row("Tests with exceptions:") { - createCombo(RuntimeExceptionTestsBehaviour::class, RuntimeExceptionTestsBehaviour.values()) - } - row("Overflow detection:") { - createCombo(TreatOverflowAsError::class, TreatOverflowAsError.values()) - } - row { - useTaintAnalysisCheckBox = - checkBox("Enable taint analysis") + row { + useTaintAnalysisCheckBox = + checkBox("Enable taint analysis") + .onApply { + settings.state.useTaintAnalysis = useTaintAnalysisCheckBox.isSelected + } + .onReset { + useTaintAnalysisCheckBox.isSelected = settings.state.useTaintAnalysis + } + .onIsModified { + useTaintAnalysisCheckBox.isSelected xor settings.state.useTaintAnalysis + } + .component + contextHelp("Experimental taint analysis support") + } + row { + runInspectionAfterTestGenerationCheckBox = + checkBox("Display detected errors on the Problems tool window") + .onApply { + settings.state.runInspectionAfterTestGeneration = + runInspectionAfterTestGenerationCheckBox.isSelected + } + .onReset { + runInspectionAfterTestGenerationCheckBox.isSelected = + settings.state.runInspectionAfterTestGeneration + } + .onIsModified { + runInspectionAfterTestGenerationCheckBox.isSelected xor settings.state.runInspectionAfterTestGeneration + } + .component + contextHelp("Automatically run code inspection after test generation") + } + row { + enableSummarizationGenerationCheckBox = checkBox("Enable summaries generation") .onApply { - settings.state.useTaintAnalysis = useTaintAnalysisCheckBox.isSelected + settings.state.summariesGenerationType = + if (enableSummarizationGenerationCheckBox.isSelected) SummariesGenerationType.FULL else SummariesGenerationType.NONE } .onReset { - useTaintAnalysisCheckBox.isSelected = settings.state.useTaintAnalysis + enableSummarizationGenerationCheckBox.isSelected = + settings.state.summariesGenerationType != SummariesGenerationType.NONE } .onIsModified { - useTaintAnalysisCheckBox.isSelected xor settings.state.useTaintAnalysis - } + enableSummarizationGenerationCheckBox.isSelected xor (settings.state.summariesGenerationType != SummariesGenerationType.NONE) + }.enabledIf(codegenLanguageCombo.selectedValueMatches(CodegenLanguage?::isSummarizationCompatible)) .component - contextHelp("Experimental taint analysis support") - } - row { - runInspectionAfterTestGenerationCheckBox = - checkBox("Display detected errors on the Problems tool window") + } + indent { + row("Javadoc comment style:") { + createCombo(JavaDocCommentStyle::class, JavaDocCommentStyle.values()) + }.enabledIf(enableSummarizationGenerationCheckBox.selected).bottomGap(BottomGap.MEDIUM) + } + + row { + forceMockCheckBox = checkBox("Force mocking static methods") .onApply { - settings.state.runInspectionAfterTestGeneration = - runInspectionAfterTestGenerationCheckBox.isSelected - } - .onReset { - runInspectionAfterTestGenerationCheckBox.isSelected = - settings.state.runInspectionAfterTestGeneration - } - .onIsModified { - runInspectionAfterTestGenerationCheckBox.isSelected xor settings.state.runInspectionAfterTestGeneration + settings.state.forceStaticMocking = + if (forceMockCheckBox.isSelected) ForceStaticMocking.FORCE else ForceStaticMocking.DO_NOT_FORCE } + .onReset { forceMockCheckBox.isSelected = settings.forceStaticMocking == ForceStaticMocking.FORCE } + .onIsModified { forceMockCheckBox.isSelected xor (settings.forceStaticMocking != ForceStaticMocking.DO_NOT_FORCE) } .component - contextHelp("Automatically run code inspection after test generation") - } - row { - enableSummarizationGenerationCheckBox = checkBox("Enable summaries generation") - .onApply { - settings.state.summariesGenerationType = - if (enableSummarizationGenerationCheckBox.isSelected) SummariesGenerationType.FULL else SummariesGenerationType.NONE - } - .onReset { - enableSummarizationGenerationCheckBox.isSelected = - settings.state.summariesGenerationType != SummariesGenerationType.NONE - } - .onIsModified { - enableSummarizationGenerationCheckBox.isSelected xor (settings.state.summariesGenerationType != SummariesGenerationType.NONE) - }.enabledIf(codegenLanguageCombo.selectedValueMatches(CodegenLanguage?::isSummarizationCompatible)) - .component - } - indent { - row("Javadoc comment style:") { - createCombo(JavaDocCommentStyle::class, JavaDocCommentStyle.values()) - }.enabledIf(enableSummarizationGenerationCheckBox.selected).bottomGap(BottomGap.MEDIUM) - } - - row { - forceMockCheckBox = checkBox("Force mocking static methods") - .onApply { - settings.state.forceStaticMocking = - if (forceMockCheckBox.isSelected) ForceStaticMocking.FORCE else ForceStaticMocking.DO_NOT_FORCE - } - .onReset { forceMockCheckBox.isSelected = settings.forceStaticMocking == ForceStaticMocking.FORCE } - .onIsModified { forceMockCheckBox.isSelected xor (settings.forceStaticMocking != ForceStaticMocking.DO_NOT_FORCE) } - .component - contextHelp("Overrides other mocking settings") - } - row("Classes to be forcedly mocked:") {} - row { - val updater = Runnable { - UIUtil.setEnabled(excludeTable.component, forceMockCheckBox.isSelected, true) + contextHelp("Overrides other mocking settings") } - cell(excludeTable.component) - .align(Align.FILL) - .onApply { excludeTable.apply() } - .onReset { - excludeTable.reset() - updater.run() + row("Classes to be forcedly mocked:") {} + row { + val updater = Runnable { + UIUtil.setEnabled(excludeTable.component, forceMockCheckBox.isSelected, true) } - .onIsModified { excludeTable.isModified() } - - forceMockCheckBox.addActionListener { updater.run() } - }.bottomGap(BottomGap.MEDIUM) + cell(excludeTable.component) + .align(Align.FILL) + .onApply { excludeTable.apply() } + .onReset { + excludeTable.reset() + updater.run() + } + .onIsModified { excludeTable.isModified() } - row("Hanging test timeout:") { - spinner( - range = IntRange( - HangingTestsTimeout.MIN_TIMEOUT_MS.toInt(), - HangingTestsTimeout.MAX_TIMEOUT_MS.toInt() - ), - step = 50 - ).bindIntValue( - getter = { - settings.hangingTestsTimeout.timeoutMs - .coerceIn(HangingTestsTimeout.MIN_TIMEOUT_MS, HangingTestsTimeout.MAX_TIMEOUT_MS).toInt() - }, - setter = { - settings.hangingTestsTimeout = HangingTestsTimeout(it.toLong()) - } - ) + forceMockCheckBox.addActionListener { updater.run() } + }.bottomGap(BottomGap.MEDIUM) - label("milliseconds per method") - contextHelp( - "Set this timeout to define which test is \"hanging\". Increase it to test the " + - "time-consuming method or decrease if the execution speed is critical for you." - ) - } - val fuzzLabel = JBLabel("Fuzzing") - val symLabel = JBLabel("Symbolic execution") - row { - cell(BorderLayoutPanel().apply { - topGap(TopGap.SMALL) - addToLeft(JBLabel("Test generation method:").apply { verticalAlignment = SwingConstants.TOP }) - addToCenter(BorderLayoutPanel().apply { - val granularity = 20 - val slider = object : JSlider() { - val updater = Runnable() { - val fuzzingPercent = 100.0 * (granularity - value) / granularity - fuzzLabel.text = "Fuzzing %.0f %%".format(fuzzingPercent) - symLabel.text = "%.0f %% Symbolic execution".format(100.0 - fuzzingPercent) - } + val fuzzLabel = JBLabel("Fuzzing") + val symLabel = JBLabel("Symbolic execution") + row { + cell(BorderLayoutPanel().apply { + topGap(TopGap.SMALL) + addToLeft(JBLabel("Test generation method:").apply { verticalAlignment = SwingConstants.TOP }) + addToCenter(BorderLayoutPanel().apply { + val granularity = 20 + val slider = object : JSlider() { + val updater = Runnable() { + val fuzzingPercent = 100.0 * (granularity - value) / granularity + fuzzLabel.text = "Fuzzing %.0f %%".format(fuzzingPercent) + symLabel.text = "%.0f %% Symbolic execution".format(100.0 - fuzzingPercent) + } - override fun getValue() = ((1 - settings.fuzzingValue) * granularity).toInt() + override fun getValue() = ((1 - settings.fuzzingValue) * granularity).toInt() - override fun setValue(n: Int) { - val tmp = value - settings.fuzzingValue = 1 - n / granularity.toDouble() - if (tmp != n) { - updater.run() + override fun setValue(n: Int) { + val tmp = value + settings.fuzzingValue = 1 - n / granularity.toDouble() + if (tmp != n) { + updater.run() + } } } - } - UIUtil.setSliderIsFilled(slider, true) - slider.minimum = 0 - slider.maximum = granularity - slider.minorTickSpacing = 1 - slider.majorTickSpacing = granularity / 4 - slider.paintTicks = true - slider.paintTrack = true - slider.paintLabels = false - slider.toolTipText = - "While fuzzer \"guesses\" the values to enter as much execution paths as possible, symbolic executor tries to \"deduce\" them. Choose the proportion of generation time allocated for each of these methods within Test generation timeout. The slide has no effect for Spring Projects." - slider.updater.run() - addToTop(slider) - addToBottom(BorderLayoutPanel().apply { - addToLeft(fuzzLabel) - addToRight(symLabel) + UIUtil.setSliderIsFilled(slider, true) + slider.minimum = 0 + slider.maximum = granularity + slider.minorTickSpacing = 1 + slider.majorTickSpacing = granularity / 4 + slider.paintTicks = true + slider.paintTrack = true + slider.paintLabels = false + slider.toolTipText = + "While fuzzer \"guesses\" the values to enter as much execution paths as possible, symbolic executor tries to \"deduce\" them. Choose the proportion of generation time allocated for each of these methods within Test generation timeout. The slide has no effect for Spring Projects." + slider.updater.run() + addToTop(slider) + addToBottom(BorderLayoutPanel().apply { + addToLeft(fuzzLabel) + addToRight(symLabel) + }) }) - }) - }).align(Align.FILL) - }.enabled(UtSettings.useFuzzing) - if (!UtSettings.useFuzzing) { - row { - comment("Fuzzing is disabled in configuration file.") - link("Edit configuration") { - UIUtil.getWindow(fuzzLabel)?.dispose() - showSettingsEditor(project, "useFuzzing") + }).align(Align.FILL) + }.enabled(UtSettings.useFuzzing) + if (!UtSettings.useFuzzing) { + row { + comment("Fuzzing is disabled in configuration file.") + link("Edit configuration") { + UIUtil.getWindow(fuzzLabel)?.dispose() + showSettingsEditor(project, "useFuzzing") + } } } } diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt similarity index 91% rename from utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt rename to utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt index 618df2cf6c..14ce8db2e0 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/components/TestFolderComboWithBrowseButton.kt @@ -14,18 +14,19 @@ import com.intellij.ui.ColoredListCellRenderer import com.intellij.ui.SimpleTextAttributes import com.intellij.util.ArrayUtil import com.intellij.util.ui.UIUtil -import java.io.File -import javax.swing.DefaultComboBoxModel -import javax.swing.JList import org.utbot.common.PathUtil import org.utbot.intellij.plugin.models.BaseTestsModel +import org.utbot.intellij.plugin.models.GenerateTestsModel import org.utbot.intellij.plugin.ui.utils.ITestSourceRoot import org.utbot.intellij.plugin.ui.utils.addDedicatedTestRoot import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle +import java.io.File +import javax.swing.DefaultComboBoxModel +import javax.swing.JList private const val SET_TEST_FOLDER = "set test folder" -class TestFolderComboWithBrowseButton(private val model: BaseTestsModel) : +class TestFolderComboWithBrowseButton(private val model: GenerateTestsModel) : ComponentWithBrowseButton>(ComboBox(), null) { @@ -77,7 +78,7 @@ class TestFolderComboWithBrowseButton(private val model: BaseTestsModel) : } else { //Prepend and select newly added test root val testRootItems = linkedSetOf(it) - testRootItems += (0 until childComponent.itemCount).map { i -> childComponent.getItemAt(i) as VirtualFile} + testRootItems += (0 until childComponent.itemCount).map { i -> childComponent.getItemAt(i) as VirtualFile } newItemList(testRootItems) } } @@ -86,9 +87,12 @@ class TestFolderComboWithBrowseButton(private val model: BaseTestsModel) : private fun chooseTestRoot(model: BaseTestsModel): VirtualFile? = ReadAction.compute { - val desc = object:FileChooserDescriptor(false, true, false, false, false, false) { + val desc = object : FileChooserDescriptor(false, true, false, false, false, false) { override fun isFileSelectable(file: VirtualFile?): Boolean { - return file != null && ModuleUtil.findModuleForFile(file, model.project) != null && super.isFileSelectable(file) + return file != null && ModuleUtil.findModuleForFile( + file, + model.project + ) != null && super.isFileSelectable(file) } } val initialFile = model.project.guessProjectDir() diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt similarity index 99% rename from utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt rename to utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt index f9cf089061..5f18c2a0cb 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/ModuleUtils.kt @@ -148,7 +148,7 @@ fun Module.suitableTestSourceRoots(): List { .mapNotNull { it.testSourceRoot } } -private val SourceFolder.testSourceRoot:TestSourceRoot? +private val SourceFolder.testSourceRoot: TestSourceRoot? get() { val file = file val expectedLanguage = expectedLanguageForTests diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtils.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtils.kt similarity index 100% rename from utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtils.kt rename to utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtils.kt diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt similarity index 100% rename from utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt rename to utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt diff --git a/utbot-intellij/src/main/resources/META-INF/withJava.xml b/utbot-intellij/src/main/resources/META-INF/withJava.xml deleted file mode 100644 index 2ce2e82cc9..0000000000 --- a/utbot-intellij/src/main/resources/META-INF/withJava.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt b/utbot-intellij/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt similarity index 100% rename from utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt rename to utbot-intellij/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt diff --git a/utbot-ui-commons/build.gradle.kts b/utbot-ui-commons/build.gradle.kts index 76e484069e..10ab87140d 100644 --- a/utbot-ui-commons/build.gradle.kts +++ b/utbot-ui-commons/build.gradle.kts @@ -1,23 +1,47 @@ val kotlinLoggingVersion: String by rootProject -val ideType: String by rootProject -val ideVersion: String by rootProject val semVer: String? by rootProject val slf4jVersion: String by rootProject + +// === IDE settings === +val projectType: String by rootProject +val communityEdition: String by rootProject +val ultimateEdition: String by rootProject + +val ideType: String by rootProject val androidStudioPath: String? by rootProject +val ideaVersion: String? by rootProject +val pycharmVersion: String? by rootProject +val golandVersion: String? by rootProject + +val javaIde: String? by rootProject +val pythonIde: String? by rootProject +val jsIde: String? by rootProject +val goIde: String? by rootProject + +val ideVersion = when(ideType) { + "PC", "PY" -> pycharmVersion + "GO" -> golandVersion + else -> ideaVersion +} + +val pythonCommunityPluginVersion: String? by rootProject +val pythonUltimatePluginVersion: String? by rootProject +val goPluginVersion: String? by rootProject + +// https://plugins.jetbrains.com/docs/intellij/android-studio.html#configuring-the-plugin-pluginxml-file +val ideTypeOrAndroidStudio = if (androidStudioPath == null) ideType else "IC" + +project.tasks.asMap["runIde"]?.enabled = false +// === IDE settings === + plugins { id("org.jetbrains.intellij") version "1.13.1" } -project.tasks.asMap["runIde"]?.enabled = false intellij { version.set(ideVersion) type.set(ideType) - - plugins.set(listOf( - "java", - "org.jetbrains.android" - )) } tasks { @@ -37,7 +61,6 @@ tasks { runIde { jvmArgs("-Xmx2048m") jvmArgs("--add-exports", "java.desktop/sun.awt.windows=ALL-UNNAMED") - androidStudioPath?.let { ideDir.set(file(it)) } } patchPluginXml { diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/language/agnostic/LanguageAssistant.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/language/agnostic/LanguageAssistant.kt index 87d7314ee4..732feff717 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/language/agnostic/LanguageAssistant.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/language/agnostic/LanguageAssistant.kt @@ -11,8 +11,7 @@ import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileSystemItem -import org.jetbrains.kotlin.idea.core.util.toPsiDirectory -import org.jetbrains.kotlin.idea.core.util.toPsiFile +import com.intellij.psi.PsiManager private val logger = KotlinLogging.logger {} @@ -84,9 +83,12 @@ abstract class LanguageAssistant { } private fun findLanguageRecursively(project: Project, virtualFiles: Array): Language? { - val psiFiles = virtualFiles.mapNotNull { it.toPsiFile(project) } - val psiDirectories = virtualFiles.mapNotNull { it.toPsiDirectory(project) } - + val psiFiles = virtualFiles.mapNotNull { + PsiManager.getInstance(project).findFile(it) + } + val psiDirectories = virtualFiles.mapNotNull { + PsiManager.getInstance(project).findDirectory(it) + } val fileLanguage = psiFiles.firstNotNullOfOrNull { getLanguageFromFile(it) } return fileLanguage ?: psiDirectories.firstNotNullOfOrNull { findLanguageRecursively(it) } @@ -97,9 +99,9 @@ abstract class LanguageAssistant { private fun loadWithException(language: Language): Class<*>? { try { return when (language.id) { - "Python" -> Class.forName("org.utbot.intellij.plugin.language.python.PythonLanguageAssistant") - "ECMAScript 6" -> Class.forName("org.utbot.intellij.plugin.language.js.JsLanguageAssistant") - "go" -> Class.forName("org.utbot.intellij.plugin.language.go.GoLanguageAssistant") + "Python" -> Class.forName("org.utbot.intellij.plugin.python.language.PythonLanguageAssistant") + "ECMAScript 6" -> Class.forName("org.utbot.intellij.plugin.js.language.JsLanguageAssistant") + "go" -> Class.forName("org.utbot.intellij.plugin.go.language.GoLanguageAssistant") "JAVA", "kotlin" -> Class.forName("org.utbot.intellij.plugin.language.JvmLanguageAssistant") else -> error("Unknown language id: ${language.id}") } diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/models/BaseTestModel.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/models/BaseTestModel.kt index 321a2af4e9..c6d22c4530 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/models/BaseTestModel.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/models/BaseTestModel.kt @@ -1,197 +1,17 @@ package org.utbot.intellij.plugin.models -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiClass -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.search.searches.AnnotatedElementsSearch -import org.jetbrains.kotlin.idea.core.getPackage -import org.jetbrains.kotlin.idea.util.projectStructure.allModules -import org.jetbrains.kotlin.idea.util.rootManager -import org.jetbrains.kotlin.idea.util.sourceRoot -import org.utbot.common.PathUtil.fileExtension import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.plugin.api.CodegenLanguage -import org.utbot.intellij.plugin.ui.utils.ITestSourceRoot -import org.utbot.intellij.plugin.ui.utils.getResourcesPaths -import org.utbot.intellij.plugin.ui.utils.getSortedTestRoots -import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle -import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots -import org.utbot.intellij.plugin.util.binaryName -import java.nio.file.Files -import javax.xml.parsers.DocumentBuilder -import javax.xml.parsers.DocumentBuilderFactory -import kotlin.streams.asSequence -val PsiClass.packageName: String get() = this.containingFile.containingDirectory.getPackage()?.qualifiedName ?: "" -const val HISTORY_LIMIT = 10 - -const val SPRINGBOOT_APPLICATION_FQN = "org.springframework.boot.autoconfigure.SpringBootApplication" -const val SPRINGBOOT_CONFIGURATION_FQN = "org.springframework.boot.SpringBootConfiguration" -const val SPRING_CONFIGURATION_ANNOTATION_FQN = "org.springframework.context.annotation.Configuration" -const val SPRING_TESTCONFIGURATION_ANNOTATION_FQN = "org.springframework.boot.test.context.TestConfiguration" - -const val SPRING_BEANS_SCHEMA_URL = "http://www.springframework.org/schema/beans" -const val SPRING_LOAD_DTD_GRAMMAR_PROPERTY = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar" -const val SPRING_LOAD_EXTERNAL_DTD_PROPERTY = "http://apache.org/xml/features/nonvalidating/load-external-dtd" - open class BaseTestsModel( val project: Project, - val srcModule: Module, - val potentialTestModules: List, - var srcClasses: Set = emptySet(), ) { - // GenerateTestsModel is supposed to be created with non-empty list of potentialTestModules. - // Otherwise, the error window is supposed to be shown earlier. - var testModule: Module = potentialTestModules.firstOrNull() ?: error("Empty list of test modules in model") - var testSourceRoot: VirtualFile? = null var testPackageName: String? = null open var sourceRootHistory : MutableList = mutableListOf() open lateinit var codegenLanguage: CodegenLanguage open lateinit var projectType: ProjectType - - fun setSourceRootAndFindTestModule(newTestSourceRoot: VirtualFile?) { - requireNotNull(newTestSourceRoot) - testSourceRoot = newTestSourceRoot - var target = newTestSourceRoot - while (target != null && target is FakeVirtualFile) { - target = target.parent - } - if (target == null) { - error("Could not find module for $newTestSourceRoot") - } - - testModule = ModuleUtil.findModuleForFile(target, project) - ?: error("Could not find module for $newTestSourceRoot") - } - - val isMultiPackage: Boolean by lazy { - srcClasses.map { it.packageName }.distinct().size != 1 - } - - fun getAllTestSourceRoots() : MutableList { - with(if (project.isBuildWithGradle) project.allModules() else potentialTestModules) { - return this.flatMap { it.suitableTestSourceRoots().toList() }.toMutableList().distinct().toMutableList() - } - } - - fun getSortedTestRoots(): MutableList = getSortedTestRoots( - getAllTestSourceRoots(), - sourceRootHistory, - srcModule.rootManager.sourceRoots.map { file: VirtualFile -> file.toNioPath().toString() }, - codegenLanguage - ) - - /** - * Finds @SpringBootApplication classes in Spring application. - * - * @see [getSortedAnnotatedClasses] - */ - fun getSortedSpringBootApplicationClasses(): Set = - getSortedAnnotatedClasses(SPRINGBOOT_CONFIGURATION_FQN) + - getSortedAnnotatedClasses(SPRINGBOOT_APPLICATION_FQN) - - /** - * Finds @TestConfiguration and @Configuration classes in Spring application. - * - * @see [getSortedAnnotatedClasses] - */ - fun getSortedSpringConfigurationClasses(): Set = - getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION_FQN) + - getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION_FQN) - - /** - * Finds classes annotated with given annotation in [srcModule] and [potentialTestModules]. - * - * Sorting order: - * - classes from test source roots (in the order provided by [getSortedTestRoots]) - * - classes from production source roots - */ - private fun getSortedAnnotatedClasses(annotationFqn: String): Set { - val searchScope = - potentialTestModules - .fold(GlobalSearchScope.moduleScope(srcModule)) { accScope, module -> - accScope.union(GlobalSearchScope.moduleScope(module)) - } - - val annotationClass = JavaPsiFacade - .getInstance(project) - .findClass(annotationFqn, GlobalSearchScope.allScope(project)) - ?: return emptySet() - - val testRootToIndex = - getSortedTestRoots() - .withIndex() - .associate { (i, root) -> root.dir to i } - - return AnnotatedElementsSearch - .searchPsiClasses(annotationClass, searchScope) - .findAll() - .sortedBy { testRootToIndex[it.containingFile.sourceRoot] ?: Int.MAX_VALUE } - .mapNotNullTo(mutableSetOf()) { it.binaryName } - } - - fun getSpringXMLConfigurationFiles(): Set { - val resourcesPaths = - buildList { - addAll(potentialTestModules) - add(srcModule) - }.distinct().flatMapTo(mutableSetOf()) { it.getResourcesPaths() } - val xmlFilePaths = resourcesPaths.flatMapTo(mutableListOf()) { path -> - Files.walk(path) - .asSequence() - .filter { it.fileExtension == ".xml" } - } - - val builder = customizeXmlBuilder() - return xmlFilePaths.mapNotNullTo(mutableSetOf()) { path -> - try { - val doc = builder.parse(path.toFile()) - - val hasBeanTagName = doc.documentElement.tagName == "beans" - val hasAttribute = doc.documentElement.getAttribute("xmlns") == SPRING_BEANS_SCHEMA_URL - when { - hasBeanTagName && hasAttribute -> path.toString() - else -> null - } - } catch (e: Exception) { - // `DocumentBuilder.parse` is an unpredictable operation, may have some side effects, we suppress them. - null - } - } - } - - /** - * Creates "safe" xml builder instance. - * - * Using standard `DocumentBuilderFactory.newInstance()` may lead to some problems like - * https://stackoverflow.com/questions/343383/unable-to-parse-xml-file-using-documentbuilder. - * - * We try to solve it in accordance with top-rated recommendation here - * https://stackoverflow.com/questions/155101/make-documentbuilder-parse-ignore-dtd-references. - */ - private fun customizeXmlBuilder(): DocumentBuilder { - val builderFactory = DocumentBuilderFactory.newInstance() - builderFactory.isNamespaceAware = true - - // See documentation https://xerces.apache.org/xerces2-j/features.html - builderFactory.setFeature(SPRING_LOAD_DTD_GRAMMAR_PROPERTY, false) - builderFactory.setFeature(SPRING_LOAD_EXTERNAL_DTD_PROPERTY, false) - - return builderFactory.newDocumentBuilder() - } - - fun updateSourceRootHistory(path: String) { - sourceRootHistory.apply { - remove(path)//Remove existing entry if any - add(path)//Add the most recent entry to the end to be brought first at sorting, see org.utbot.intellij.plugin.ui.utils.RootUtilsKt.getSortedTestRoots - while (size > HISTORY_LIMIT) removeFirst() - } - } } diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/BaseSettingsWindow.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/BaseSettingsWindow.kt new file mode 100644 index 0000000000..8e95275aaf --- /dev/null +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/BaseSettingsWindow.kt @@ -0,0 +1,85 @@ +package org.utbot.intellij.plugin.settings + +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogPanel +import com.intellij.ui.dsl.builder.* +import javax.swing.* +import kotlin.reflect.KClass +import org.utbot.framework.codegen.domain.HangingTestsTimeout +import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour +import org.utbot.framework.plugin.api.CodeGenerationSettingItem +import org.utbot.intellij.plugin.ui.components.CodeGenerationSettingItemRenderer + +class BaseSettingsWindow(val project: Project) { + private val settings = project.service() + + private lateinit var enableExperimentalLanguagesCheckBox: JCheckBox + + private fun Row.createCombo(loader: KClass<*>, values: Array<*>) { + comboBox(DefaultComboBoxModel(values)) + .bindItem( + getter = { settings.providerNameByServiceLoader(loader) }, + setter = { settings.setProviderByLoader(loader, it as CodeGenerationSettingItem) }, + ).component.renderer = CodeGenerationSettingItemRenderer() + } + + val panel: JPanel = panel { + group("Common Settings") { + row("Tests with exceptions:") { + createCombo(RuntimeExceptionTestsBehaviour::class, RuntimeExceptionTestsBehaviour.values()) + } + + row("Hanging test timeout:") { + spinner( + range = IntRange( + HangingTestsTimeout.MIN_TIMEOUT_MS.toInt(), + HangingTestsTimeout.MAX_TIMEOUT_MS.toInt() + ), + step = 50 + ).bindIntValue( + getter = { + settings.hangingTestsTimeout.timeoutMs + .coerceIn(HangingTestsTimeout.MIN_TIMEOUT_MS, HangingTestsTimeout.MAX_TIMEOUT_MS).toInt() + }, + setter = { + settings.hangingTestsTimeout = HangingTestsTimeout(it.toLong()) + } + ) + + label("milliseconds per method") + contextHelp( + "Set this timeout to define which test is \"hanging\". Increase it to test the " + + "time-consuming method or decrease if the execution speed is critical for you." + ) + } + + row { + enableExperimentalLanguagesCheckBox = checkBox("Experimental languages support") + .onApply { + settings.state.enableExperimentalLanguagesSupport = + enableExperimentalLanguagesCheckBox.isSelected + } + .onReset { + enableExperimentalLanguagesCheckBox.isSelected = + settings.experimentalLanguagesSupport == true + } + .onIsModified { enableExperimentalLanguagesCheckBox.isSelected xor settings.experimentalLanguagesSupport } + .component + contextHelp("Enable JavaScript and Python if IDE supports them") + }.bottomGap(BottomGap.MEDIUM) + } + } + + fun isModified(): Boolean { + return (panel as DialogPanel).isModified() + } + + fun apply() { + (panel as DialogPanel).apply() + } + + fun reset() { + (panel as DialogPanel).reset() + } +} diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/CommonSettings.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/CommonSettings.kt index e6ed028959..2fc63f8e77 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/CommonSettings.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/CommonSettings.kt @@ -71,7 +71,7 @@ class Settings(val project: Project) : PersistentStateComponent var commentStyle: JavaDocCommentStyle = JavaDocCommentStyle.defaultItem, var summariesGenerationType: SummariesGenerationType = UtSettings.summaryGenerationType, var generationTimeoutInMillis: Long = UtSettings.utBotGenerationTimeoutInMillis, - var enableExperimentalLanguagesSupport: Boolean = false, + var enableExperimentalLanguagesSupport: Boolean = true, var isSpringHandled: Boolean = false, ) { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt similarity index 92% rename from utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt rename to utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt index 7a41ff805a..3c09b84ea2 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/settings/Configurable.kt @@ -7,7 +7,7 @@ import javax.swing.JComponent class Configurable(val project: Project) : SearchableConfigurable { private val displayName: String = "UtBot Configuration" private val id: String = "org.utbot.intellij.plugin.settings.UtBotSettingsConfigurable" - private val settingsWindow = SettingsWindow(project) + private val settingsWindow = BaseSettingsWindow(project) override fun createComponent(): JComponent = settingsWindow.panel