From a2d8378cc73aba100e5a3eaf51185a37072161d6 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Fri, 30 Jun 2023 19:15:55 +0300 Subject: [PATCH 1/8] Use binaryName instead of canonicalName for Spring configurations --- .../generated/EngineProcessModel.Generated.kt | 96 +++++++++---------- .../generator/UtTestsDialogProcessor.kt | 38 +++----- .../intellij/plugin/process/EngineProcess.kt | 4 +- .../plugin/ui/GenerateTestsDialogWindow.kt | 8 +- .../plugin/util/SpringConfigurationsHelper.kt | 28 ++++-- .../intellij/plugin/models/BaseTestModel.kt | 14 +-- .../intellij/plugin/util/PsiClassUtil.kt | 21 ++++ 7 files changed, 113 insertions(+), 96 deletions(-) create mode 100644 utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt index ed2db61f68..781f47138b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt @@ -75,7 +75,7 @@ class EngineProcessModel private constructor( } - const val serializationHash = 2605460374173973135L + const val serializationHash = 4955072258757490759L } override val serializersOwner: ISerializersOwner get() = EngineProcessModel @@ -182,7 +182,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel /** - * #### Generated from [EngineProcessModel.kt:132] + * #### Generated from [EngineProcessModel.kt:134] */ data class BeanAdditionalData ( val factoryMethodName: String, @@ -190,10 +190,10 @@ data class BeanAdditionalData ( val configClassFqn: String ) : IPrintable { //companion - + companion object : IMarshaller { override val _type: KClass = BeanAdditionalData::class - + @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): BeanAdditionalData { val factoryMethodName = buffer.readString() @@ -201,14 +201,14 @@ data class BeanAdditionalData ( val configClassFqn = buffer.readString() return BeanAdditionalData(factoryMethodName, parameterTypes, configClassFqn) } - + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: BeanAdditionalData) { buffer.writeString(value.factoryMethodName) buffer.writeList(value.parameterTypes) { v -> buffer.writeString(v) } buffer.writeString(value.configClassFqn) } - - + + } //fields //methods @@ -218,13 +218,13 @@ data class BeanAdditionalData ( override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || other::class != this::class) return false - + other as BeanAdditionalData - + if (factoryMethodName != other.factoryMethodName) return false if (parameterTypes != other.parameterTypes) return false if (configClassFqn != other.configClassFqn) return false - + return true } //hash code trait @@ -251,7 +251,7 @@ data class BeanAdditionalData ( /** - * #### Generated from [EngineProcessModel.kt:137] + * #### Generated from [EngineProcessModel.kt:139] */ data class BeanDefinitionData ( val beanName: String, @@ -259,10 +259,10 @@ data class BeanDefinitionData ( val additionalData: BeanAdditionalData? ) : IPrintable { //companion - + companion object : IMarshaller { override val _type: KClass = BeanDefinitionData::class - + @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): BeanDefinitionData { val beanName = buffer.readString() @@ -270,14 +270,14 @@ data class BeanDefinitionData ( val additionalData = buffer.readNullable { BeanAdditionalData.read(ctx, buffer) } return BeanDefinitionData(beanName, beanTypeFqn, additionalData) } - + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: BeanDefinitionData) { buffer.writeString(value.beanName) buffer.writeString(value.beanTypeFqn) buffer.writeNullable(value.additionalData) { BeanAdditionalData.write(ctx, buffer, it) } } - - + + } //fields //methods @@ -287,13 +287,13 @@ data class BeanDefinitionData ( override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || other::class != this::class) return false - + other as BeanDefinitionData - + if (beanName != other.beanName) return false if (beanTypeFqn != other.beanTypeFqn) return false if (additionalData != other.additionalData) return false - + return true } //hash code trait @@ -320,7 +320,7 @@ data class BeanDefinitionData ( /** - * #### Generated from [EngineProcessModel.kt:106] + * #### Generated from [EngineProcessModel.kt:108] */ data class FindMethodParamNamesArguments ( val classId: ByteArray, @@ -383,7 +383,7 @@ data class FindMethodParamNamesArguments ( /** - * #### Generated from [EngineProcessModel.kt:110] + * #### Generated from [EngineProcessModel.kt:112] */ data class FindMethodParamNamesResult ( val paramNames: ByteArray @@ -440,7 +440,7 @@ data class FindMethodParamNamesResult ( /** - * #### Generated from [EngineProcessModel.kt:99] + * #### Generated from [EngineProcessModel.kt:101] */ data class FindMethodsInClassMatchingSelectedArguments ( val classId: ByteArray, @@ -503,7 +503,7 @@ data class FindMethodsInClassMatchingSelectedArguments ( /** - * #### Generated from [EngineProcessModel.kt:103] + * #### Generated from [EngineProcessModel.kt:105] */ data class FindMethodsInClassMatchingSelectedResult ( val executableIds: ByteArray @@ -630,7 +630,7 @@ data class GenerateParams ( if (fuzzingValue != other.fuzzingValue) return false if (searchDirectory != other.searchDirectory) return false if (taintConfigPath != other.taintConfigPath) return false - + return true } //hash code trait @@ -734,7 +734,7 @@ data class GenerateResult ( /** - * #### Generated from [EngineProcessModel.kt:118] + * #### Generated from [EngineProcessModel.kt:120] */ data class GenerateTestReportArgs ( val eventLogMessage: String?, @@ -827,7 +827,7 @@ data class GenerateTestReportArgs ( /** - * #### Generated from [EngineProcessModel.kt:127] + * #### Generated from [EngineProcessModel.kt:129] */ data class GenerateTestReportResult ( val notifyMessage: String, @@ -896,7 +896,7 @@ data class GenerateTestReportResult ( /** - * #### Generated from [EngineProcessModel.kt:88] + * #### Generated from [EngineProcessModel.kt:90] */ data class GetSpringBeanDefinitions ( val classpath: Array, @@ -905,10 +905,10 @@ data class GetSpringBeanDefinitions ( val profileExpression: String? ) : IPrintable { //companion - + companion object : IMarshaller { override val _type: KClass = GetSpringBeanDefinitions::class - + @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): GetSpringBeanDefinitions { val classpath = buffer.readArray {buffer.readString()} @@ -917,15 +917,15 @@ data class GetSpringBeanDefinitions ( val profileExpression = buffer.readNullable { buffer.readString() } return GetSpringBeanDefinitions(classpath, config, fileStorage, profileExpression) } - + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: GetSpringBeanDefinitions) { buffer.writeArray(value.classpath) { buffer.writeString(it) } buffer.writeString(value.config) buffer.writeArray(value.fileStorage) { buffer.writeString(it) } buffer.writeNullable(value.profileExpression) { buffer.writeString(it) } } - - + + } //fields //methods @@ -935,14 +935,14 @@ data class GetSpringBeanDefinitions ( override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || other::class != this::class) return false - + other as GetSpringBeanDefinitions - + if (!(classpath contentDeepEquals other.classpath)) return false if (config != other.config) return false if (!(fileStorage contentDeepEquals other.fileStorage)) return false if (profileExpression != other.profileExpression) return false - + return true } //hash code trait @@ -1034,7 +1034,7 @@ data class JdkInfo ( /** - * #### Generated from [EngineProcessModel.kt:94] + * #### Generated from [EngineProcessModel.kt:96] */ data class MethodDescription ( val name: String, @@ -1256,7 +1256,7 @@ data class RenderParams ( /** - * #### Generated from [EngineProcessModel.kt:81] + * #### Generated from [EngineProcessModel.kt:83] */ data class RenderResult ( val generatedCode: String, @@ -1319,7 +1319,7 @@ data class RenderResult ( /** - * #### Generated from [EngineProcessModel.kt:85] + * #### Generated from [EngineProcessModel.kt:87] */ data class SetupContextParams ( val classpathForUrlsClassloader: List @@ -1376,27 +1376,27 @@ data class SetupContextParams ( /** - * #### Generated from [EngineProcessModel.kt:142] + * #### Generated from [EngineProcessModel.kt:144] */ data class SpringAnalyzerResult ( val beanDefinitions: Array ) : IPrintable { //companion - + companion object : IMarshaller { override val _type: KClass = SpringAnalyzerResult::class - + @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): SpringAnalyzerResult { val beanDefinitions = buffer.readArray {BeanDefinitionData.read(ctx, buffer)} return SpringAnalyzerResult(beanDefinitions) } - + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: SpringAnalyzerResult) { buffer.writeArray(value.beanDefinitions) { BeanDefinitionData.write(ctx, buffer, it) } } - - + + } //fields //methods @@ -1406,11 +1406,11 @@ data class SpringAnalyzerResult ( override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || other::class != this::class) return false - + other as SpringAnalyzerResult - + if (!(beanDefinitions contentDeepEquals other.beanDefinitions)) return false - + return true } //hash code trait @@ -1514,7 +1514,7 @@ data class TestGeneratorParams ( /** - * #### Generated from [EngineProcessModel.kt:113] + * #### Generated from [EngineProcessModel.kt:115] */ data class WriteSarifReportArguments ( val testSetsId: Long, 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 3f98dd22b9..1c7e4b7d48 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 @@ -62,7 +62,6 @@ import org.utbot.framework.plugin.services.JdkInfoService import org.utbot.framework.plugin.services.WorkingDirService import org.utbot.intellij.plugin.generator.CodeGenerationController.generateTests import org.utbot.intellij.plugin.models.GenerateTestsModel -import org.utbot.intellij.plugin.models.packageName import org.utbot.intellij.plugin.process.EngineProcess import org.utbot.intellij.plugin.process.RdTestGenerationResult import org.utbot.intellij.plugin.settings.Settings @@ -73,6 +72,7 @@ import org.utbot.intellij.plugin.ui.utils.testModules import org.utbot.intellij.plugin.util.IntelliJApiHelper import org.utbot.intellij.plugin.util.PsiClassHelper import org.utbot.intellij.plugin.util.isAbstract +import org.utbot.intellij.plugin.util.binaryName import org.utbot.intellij.plugin.util.PluginJdkInfoProvider import org.utbot.intellij.plugin.util.PluginWorkingDirProvider import org.utbot.intellij.plugin.util.assertIsNonDispatchThread @@ -178,7 +178,9 @@ object UtTestsDialogProcessor { DoNotReplace -> null is ReplaceIfPossible -> approach.config.takeUnless { it.endsWith(".xml") }?.let { - PsiClassHelper.findClass(it, project) ?: error("Cannot find configuration class $it.") + // Converting binary name to canonical name + val canonicalName = it.replace("$", ".") + PsiClassHelper.findClass(canonicalName, project) ?: error("Cannot find configuration class $it.") } } @@ -236,7 +238,7 @@ object UtTestsDialogProcessor { val totalClasses = model.srcClasses.size val classNameToPath = runReadAction { model.srcClasses.associate { psiClass -> - psiClass.canonicalName to psiClass.containingFile.virtualFile.canonicalPath + psiClass.binaryName() to psiClass.containingFile.virtualFile.canonicalPath } } @@ -310,12 +312,12 @@ object UtTestsDialogProcessor { } val (methods, classNameForLog) = process.executeWithTimeoutSuspended { - var canonicalName = "" + var binaryName = "" var srcMethods: List = emptyList() var srcNameForLog: String? = null DumbService.getInstance(project) .runReadActionInSmartMode(Computable { - canonicalName = srcClass.canonicalName + binaryName = srcClass.binaryName() srcNameForLog = srcClass.name srcMethods = if (model.extractMembersFromSrcClasses) { val chosenMethods = @@ -329,7 +331,7 @@ object UtTestsDialogProcessor { srcClass.extractClassMethodsIncludingNested(false) } }) - val classId = process.obtainClassId(canonicalName) + val classId = process.obtainClassId(binaryName) psi2KClass[srcClass] = classId process.findMethodsInClassMatchingSelected( classId, @@ -465,26 +467,6 @@ object UtTestsDialogProcessor { return if (path != null && path.toFile().exists()) path else null } - private val PsiClass.canonicalName: String - /* - This method calculates exactly name that is used by compiler convention, - i.e. result is the exact name of .class file for provided PsiClass. - This value is used to provide classes to engine process - follow usages for clarification. - Equivalent for Class.getCanonicalName. - P.S. We cannot load project class in IDEA jvm - */ - get() { - return if (packageName.isEmpty()) { - qualifiedName?.replace(".", "$") ?: "" - } else { - val name = qualifiedName - ?.substringAfter("$packageName.") - ?.replace(".", "$") - ?: error("Unable to get canonical name for $this") - "$packageName.$name" - } - } - private fun clarifyBeanDefinitionReturnTypes(beanDefinitions: List, project: Project) = beanDefinitions.map { bean -> // Here we extract a real return type. @@ -496,8 +478,10 @@ object UtTestsDialogProcessor { val beanType = runReadAction { val additionalData = bean.additionalData ?: return@runReadAction null + // Converting binary name to canonical name + val canonicalName = additionalData.configClassFqn.replace("$", ".") val configPsiClass = - PsiClassHelper.findClass(additionalData.configClassFqn, project) ?: return@runReadAction null + PsiClassHelper.findClass(canonicalName, project) ?: return@runReadAction null .also { logger.warn("Cannot find configuration class ${additionalData.configClassFqn}.") } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt index 2dbc7f9ef4..f6aab3f931 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt @@ -197,9 +197,9 @@ class EngineProcess private constructor(val project: Project, private val classN engineModel.createTestGenerator.startBlocking(params) } - fun obtainClassId(canonicalName: String): ClassId { + fun obtainClassId(binaryName: String): ClassId { assertReadAccessNotAllowed() - return kryoHelper.readObject(engineModel.obtainClassId.startBlocking(canonicalName)) + return kryoHelper.readObject(engineModel.obtainClassId.startBlocking(binaryName)) } fun findMethodsInClassMatchingSelected(clazzId: ClassId, srcMethods: List): List { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index 69e70a1153..8a78a259b4 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -136,12 +136,13 @@ import org.utbot.intellij.plugin.util.IntelliJApiHelper import org.utbot.intellij.plugin.util.SpringConfigurationsHelper import org.utbot.intellij.plugin.util.extractFirstLevelMembers import org.utbot.intellij.plugin.util.findSdkVersion +import org.utbot.intellij.plugin.util.SpringConfigurationType +import org.utbot.intellij.plugin.util.findSdkVersionOrNull import java.awt.BorderLayout import java.awt.Color import java.awt.Component import java.awt.Dimension import java.awt.event.ActionEvent -import java.io.File import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -160,7 +161,6 @@ import javax.swing.JList import javax.swing.JSpinner import javax.swing.text.DefaultFormatter import kotlin.io.path.notExists -import org.utbot.intellij.plugin.util.findSdkVersionOrNull private const val RECENTS_KEY = "org.utbot.recents" @@ -198,8 +198,8 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m private val codegenLanguages = createComboBox(CodegenLanguage.values()) private val testFrameworks = createComboBox(TestFramework.allItems.toTypedArray()) - private val javaConfigurationHelper = SpringConfigurationsHelper(".") - private val xmlConfigurationHelper = SpringConfigurationsHelper(File.separator) + private val javaConfigurationHelper = SpringConfigurationsHelper(SpringConfigurationType.ClassConfiguration) + private val xmlConfigurationHelper = SpringConfigurationsHelper(SpringConfigurationType.FileConfiguration) private val mockStrategies = createComboBox(MockStrategyApi.values()) private val staticsMocking = JCheckBox("Mock static methods") diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt index b5ed2ee1ad..103e73f8c6 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt @@ -1,5 +1,7 @@ package org.utbot.intellij.plugin.util +import java.io.File + /** * This class is a converter between full Spring configuration names and shortened versions. * @@ -13,7 +15,7 @@ package org.utbot.intellij.plugin.util * -> * [["web.WebConfig", "web2.WebConfig", "AnotherConfig"]] */ -class SpringConfigurationsHelper(val separator: String) { +class SpringConfigurationsHelper(val configType: SpringConfigurationType) { private val nameToInfo = mutableMapOf() @@ -21,7 +23,7 @@ class SpringConfigurationsHelper(val separator: String) { val shortenedName: String get() = innerShortName - private val pathFragments: MutableList = fullName.split(separator).toMutableList() + private val pathFragments: MutableList = fullName.split(*configType.separatorsToSplitBy).toMutableList() private var innerShortName = pathFragments.removeLast() fun enlargeShortName(): Boolean { @@ -30,7 +32,7 @@ class SpringConfigurationsHelper(val separator: String) { } val lastElement = pathFragments.removeLast() - innerShortName = "${lastElement}$separator$innerShortName" + innerShortName = "${lastElement}${configType.separatorToConcatenateBy}$innerShortName" return true } } @@ -51,7 +53,7 @@ class SpringConfigurationsHelper(val separator: String) { nameInfoCollection = nameInfoCollection.sortedBy { it.shortenedName }.toMutableList() var index = 0 - while(index < nameInfoCollection.size){ + while (index < nameInfoCollection.size) { val curShortenedPath = nameInfoCollection[index].shortenedName // here we search a block of shortened paths that are equivalent @@ -60,8 +62,7 @@ class SpringConfigurationsHelper(val separator: String) { while (maxIndexWithSamePath < nameInfoCollection.size) { if (nameInfoCollection[maxIndexWithSamePath].shortenedName == curShortenedPath) { maxIndexWithSamePath++ - } - else { + } else { break } } @@ -89,4 +90,19 @@ class SpringConfigurationsHelper(val separator: String) { private fun collectShortenedNames() = nameToInfo.values.associate { it.fullName to it.shortenedName } +} + +enum class SpringConfigurationType( + val separatorsToSplitBy: Array, + val separatorToConcatenateBy: String, +) { + ClassConfiguration( + separatorsToSplitBy = arrayOf(".", "$"), + separatorToConcatenateBy = ".", + ), + + FileConfiguration( + separatorsToSplitBy = arrayOf(File.separator), + separatorToConcatenateBy = File.separator, + ), } \ No newline at end of file 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 fa9aa46931..c72ebd18b6 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,10 +1,8 @@ package org.utbot.intellij.plugin.models import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.TestModuleProperties import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile import com.intellij.psi.JavaPsiFacade @@ -23,12 +21,10 @@ 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 java.io.IOException -import java.io.StringReader +import org.utbot.intellij.plugin.util.binaryName import java.nio.file.Files import javax.xml.parsers.DocumentBuilder import javax.xml.parsers.DocumentBuilderFactory -import javax.xml.parsers.ParserConfigurationException import kotlin.streams.asSequence @@ -37,8 +33,8 @@ 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 = "org.springframework.context.annotation.Configuration" -const val SPRING_TESTCONFIGURATION_ANNOTATION = "org.springframework.boot.test.context.TestConfiguration" +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" @@ -106,7 +102,7 @@ open class BaseTestsModel( * @see [getSortedAnnotatedClasses] */ fun getSortedSpringConfigurationClasses(): Set = - getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION) + getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION) + getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION_FQN) + getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION_FQN) /** * Finds classes annotated with given annotation in [srcModule] and [potentialTestModules]. @@ -130,7 +126,7 @@ open class BaseTestsModel( .searchPsiClasses(annotationClass, searchScope) .findAll() .sortedBy { testRootToIndex[it.containingFile.sourceRoot] ?: Int.MAX_VALUE } - .mapNotNullTo(mutableSetOf()) { it.qualifiedName } + .mapNotNullTo(mutableSetOf()) { it.binaryName() } } fun getSpringXMLConfigurationFiles(): Set { diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt new file mode 100644 index 0000000000..249fad7337 --- /dev/null +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt @@ -0,0 +1,21 @@ +package org.utbot.intellij.plugin.util + +import com.intellij.psi.PsiClass +import org.utbot.intellij.plugin.models.packageName + + +/** + * Used to build binary name from canonical name. + * E.g. ```org.example.OuterClass.InnerClass.InnerInnerClass``` -> ```org.example.OuterClass$InnerClass$InnerInnerClass``` + */ +fun PsiClass.binaryName(): String = + if (packageName.isEmpty()) { + qualifiedName?.replace(".", "$") ?: "" + } else { + val name = + qualifiedName + ?.substringAfter("$packageName.") + ?.replace(".", "$") + ?: error("Binary name construction failed: unable to get qualified name for $this") + "$packageName.$name" + } \ No newline at end of file From b22a9b2baa7fda9b8e572a7ec72731fd5185b76e Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Mon, 3 Jul 2023 15:47:43 +0300 Subject: [PATCH 2/8] Refactoring --- .../org/utbot/framework/plugin/api/Api.kt | 16 +++++++---- .../org/utbot/engine/UtBotSymbolicEngine.kt | 2 +- .../framework/process/EngineProcessMain.kt | 4 +-- .../generated/EngineProcessModel.Generated.kt | 16 +++++------ .../SpringUtExecutionInstrumentation.kt | 2 +- .../InstrumentedProcessModel.Generated.kt | 2 +- .../generator/UtTestsDialogProcessor.kt | 28 +++++++++++-------- .../intellij/plugin/process/EngineProcess.kt | 10 +++++-- .../plugin/util/SpringConfigurationsHelper.kt | 2 +- .../org/utbot/rd/models/EngineProcessModel.kt | 2 +- .../SpringAnalyzerProcessModel.Generated.kt | 2 +- .../intellij/plugin/models/BaseTestModel.kt | 22 ++++++++++----- .../intellij/plugin/util/PsiClassUtil.kt | 8 ++++-- 13 files changed, 70 insertions(+), 46 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index b7a9db87ac..3f032f9fa7 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1436,10 +1436,10 @@ class SpringApplicationContext( private val springInjectedClasses: Set get() { if (!areInjectedClassesInitialized) { - // TODO: use more info from SpringBeanDefinitionData than beanTypeFqn offers here - for (beanFqn in beanDefinitions.map { it.beanTypeFqn }) { + // TODO: use more info from SpringBeanDefinitionData than beanTypeName offers here + for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { try { - val beanClass = utContext.classLoader.loadClass(beanFqn) + val beanClass = utContext.classLoader.loadClass(beanTypeName) if (!beanClass.isAbstract && !beanClass.isInterface && !beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) { springInjectedClassesStorage += beanClass.id @@ -1449,7 +1449,7 @@ class SpringApplicationContext( // it is possible to have problems with classes loading. when (e) { is ClassNotFoundException, is NoClassDefFoundError, is IllegalAccessError -> - logger.warn { "Failed to load bean class for $beanFqn (${e.message})" } + logger.warn { "Failed to load bean class for $beanTypeName (${e.message})" } else -> throw e } @@ -1530,10 +1530,12 @@ enum class SpringTestsType( * Describes information about beans obtained from Spring analysis process. * * Contains the name of the bean, its type (class or interface) and optional additional data. + * + * @param beanTypeName a name in a form obtained by [java.lang.Class.getName] method. */ data class BeanDefinitionData( val beanName: String, - val beanTypeFqn: String, + val beanTypeName: String, val additionalData: BeanAdditionalData?, ) @@ -1542,11 +1544,13 @@ data class BeanDefinitionData( * * Sometimes the actual type of the bean can not be obtained from bean definition. * Then we try to recover it by method and class defining bean (e.g. using Psi elements). + * + * @param configClassName a name in a form obtained by [java.lang.Class.getName] method. */ data class BeanAdditionalData( val factoryMethodName: String, val parameterTypes: List, - val configClassFqn: String, + val configClassName: String, ) val RefType.isAbstractType diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 405e71996c..fab753b288 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -412,7 +412,7 @@ class UtBotSymbolicEngine( defaultIdGenerator, beanNameProvider = { classId -> (applicationContext as SpringApplicationContext).beanDefinitions - .filter { it.beanTypeFqn == classId.name } + .filter { it.beanTypeName == classId.name } .map { it.beanName } }, relevantRepositories = relevantRepositories diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt index 45f9eaf582..e0a428eab8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt @@ -160,8 +160,8 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch RenderResult(it.generatedCode, it.utilClassKind?.javaClass?.simpleName) } } - watchdog.measureTimeForActiveCall(obtainClassId, "Obtain class id in UtContext") { canonicalName -> - kryoHelper.writeObject(UtContext.currentContext()!!.classLoader.loadClass(canonicalName).id) + watchdog.measureTimeForActiveCall(obtainClassId, "Obtain class id in UtContext") { binaryName -> + kryoHelper.writeObject(UtContext.currentContext()!!.classLoader.loadClass(binaryName).id) } watchdog.measureTimeForActiveCall(findMethodsInClassMatchingSelected, "Find methods in Class") { params -> val classId = kryoHelper.readObject(params.classId) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt index 781f47138b..8f75c385e4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt @@ -75,7 +75,7 @@ class EngineProcessModel private constructor( } - const val serializationHash = 4955072258757490759L + const val serializationHash = -7418312653824196007L } override val serializersOwner: ISerializersOwner get() = EngineProcessModel @@ -187,7 +187,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel data class BeanAdditionalData ( val factoryMethodName: String, val parameterTypes: List, - val configClassFqn: String + val configClassName: String ) : IPrintable { //companion @@ -198,14 +198,14 @@ data class BeanAdditionalData ( override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): BeanAdditionalData { val factoryMethodName = buffer.readString() val parameterTypes = buffer.readList { buffer.readString() } - val configClassFqn = buffer.readString() - return BeanAdditionalData(factoryMethodName, parameterTypes, configClassFqn) + val configClassName = buffer.readString() + return BeanAdditionalData(factoryMethodName, parameterTypes, configClassName) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: BeanAdditionalData) { buffer.writeString(value.factoryMethodName) buffer.writeList(value.parameterTypes) { v -> buffer.writeString(v) } - buffer.writeString(value.configClassFqn) + buffer.writeString(value.configClassName) } @@ -223,7 +223,7 @@ data class BeanAdditionalData ( if (factoryMethodName != other.factoryMethodName) return false if (parameterTypes != other.parameterTypes) return false - if (configClassFqn != other.configClassFqn) return false + if (configClassName != other.configClassName) return false return true } @@ -232,7 +232,7 @@ data class BeanAdditionalData ( var __r = 0 __r = __r*31 + factoryMethodName.hashCode() __r = __r*31 + parameterTypes.hashCode() - __r = __r*31 + configClassFqn.hashCode() + __r = __r*31 + configClassName.hashCode() return __r } //pretty print @@ -241,7 +241,7 @@ data class BeanAdditionalData ( printer.indent { print("factoryMethodName = "); factoryMethodName.print(printer); println() print("parameterTypes = "); parameterTypes.print(printer); println() - print("configClassFqn = "); configClassFqn.print(printer); println() + print("configClassName = "); configClassName.print(printer); println() } printer.print(")") } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt index 5f68de1c07..da44800b9a 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt @@ -83,7 +83,7 @@ class SpringUtExecutionInstrumentation( private fun getRelevantBeans(clazz: Class<*>): Set = relatedBeansCache.getOrPut(clazz) { beanDefinitions - .filter { it.beanTypeFqn == clazz.name } + .filter { it.beanTypeName == clazz.name } // forces `getBean()` to load Spring classes, // otherwise execution of method under test may fail with timeout .onEach { springApi.getBean(it.beanName) } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt index bd36a1903f..175bbff366 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/generated/InstrumentedProcessModel.Generated.kt @@ -113,7 +113,7 @@ class InstrumentedProcessModel private constructor( val getSpringBean: RdCall get() = _getSpringBean /** - * Get Spring repositories by bean names (requires Spring instrumentation) + * Gets a list of [SpringRepositoryId]s that class specified by the [ClassId] (possibly indirectly) depends on (requires Spring instrumentation) */ val getRelevantSpringRepositories: RdCall get() = _getRelevantSpringRepositories //methods 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 1c7e4b7d48..0fed3d2cb4 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 @@ -178,9 +178,11 @@ object UtTestsDialogProcessor { DoNotReplace -> null is ReplaceIfPossible -> approach.config.takeUnless { it.endsWith(".xml") }?.let { - // Converting binary name to canonical name - val canonicalName = it.replace("$", ".") - PsiClassHelper.findClass(canonicalName, project) ?: error("Cannot find configuration class $it.") + // Converting binary name to fqn name + val fqnName = it.replace("$", ".") + PsiClassHelper + .findClass(fqnName, project) + ?: error("Cannot find configuration class $it with $fqnName name.") } } @@ -478,13 +480,15 @@ object UtTestsDialogProcessor { val beanType = runReadAction { val additionalData = bean.additionalData ?: return@runReadAction null - // Converting binary name to canonical name - val canonicalName = additionalData.configClassFqn.replace("$", ".") + // Converting binary name to fqn name + val fqnName = additionalData.configClassName.replace("$", ".") val configPsiClass = - PsiClassHelper.findClass(canonicalName, project) ?: return@runReadAction null - .also { - logger.warn("Cannot find configuration class ${additionalData.configClassFqn}.") - } + PsiClassHelper + .findClass(fqnName, project) + ?: return@runReadAction null + .also { + logger.warn("Cannot find configuration class ${additionalData.configClassName} with $fqnName name.") + } val beanPsiMethod = configPsiClass @@ -504,7 +508,7 @@ object UtTestsDialogProcessor { .also { logger.warn( "Several similar methods named ${bean.beanName} " + - "were found in ${additionalData.configClassFqn} configuration class." + "were found in ${additionalData.configClassName} configuration class." ) } @@ -513,12 +517,12 @@ object UtTestsDialogProcessor { .findReturnStatements(beanPsiMethod) .mapNotNullTo(mutableSetOf()) { stmt -> stmt.returnValue?.type?.canonicalText } - beanTypes.singleOrNull() ?: bean.beanTypeFqn + beanTypes.singleOrNull() ?: bean.beanTypeName } ?: return@map bean BeanDefinitionData( beanName = bean.beanName, - beanTypeFqn = beanType, + beanTypeName = beanType, additionalData = bean.additionalData ) } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt index f6aab3f931..e5ffdef0dc 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt @@ -156,9 +156,15 @@ class EngineProcess private constructor(val project: Project, private val classN .map { data -> BeanDefinitionData( beanName = data.beanName, - beanTypeFqn = data.beanTypeFqn, + beanTypeName = data.beanTypeFqn, additionalData = data.additionalData - ?.let { BeanAdditionalData(it.factoryMethodName, it.parameterTypes, it.configClassFqn) } + ?.let { + BeanAdditionalData( + it.factoryMethodName, + it.parameterTypes, + it.configClassName + ) + } ) } } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt index 103e73f8c6..ba9981ae4d 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt @@ -42,7 +42,7 @@ class SpringConfigurationsHelper(val configType: SpringConfigurationType) { .values .singleOrNull { it.shortenedName == shortenedName } ?.fullName - ?: error("Full name of configuration file cannot be restored by shortened name $shortenedName") + ?: error("Full name of configuration file cannot be restored with shortened name $shortenedName") fun shortenSpringConfigNames(fullNames: Set): Map { fullNames.forEach { nameToInfo[it] = NameInfo(it) } diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt index 8b6825d969..1affc2c124 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt @@ -134,7 +134,7 @@ object EngineProcessModel : Ext(EngineProcessRoot) { val beanAdditionalData = structdef { field("factoryMethodName", PredefinedType.string) field("parameterTypes", immutableList(PredefinedType.string)) - field("configClassFqn", PredefinedType.string) + field("configClassName", PredefinedType.string) } val beanDefinitionData = structdef { field("beanName", PredefinedType.string) diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt index 0688b8047b..324bbe5055 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt @@ -224,7 +224,7 @@ data class BeanDefinitionData ( printer.println("BeanDefinitionData (") printer.indent { print("beanName = "); beanName.print(printer); println() - print("beanTypeFqn = "); beanTypeFqn.print(printer); println() + print("beanTypeName = "); beanTypeFqn.print(printer); println() print("additionalData = "); additionalData.print(printer); println() } printer.print(")") 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 c72ebd18b6..20b3f9b5d8 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 @@ -94,7 +94,8 @@ open class BaseTestsModel( * @see [getSortedAnnotatedClasses] */ fun getSortedSpringBootApplicationClasses(): Set = - getSortedAnnotatedClasses(SPRINGBOOT_CONFIGURATION_FQN) + getSortedAnnotatedClasses(SPRINGBOOT_APPLICATION_FQN) + getSortedAnnotatedClasses(SPRINGBOOT_CONFIGURATION_FQN) + + getSortedAnnotatedClasses(SPRINGBOOT_APPLICATION_FQN) /** * Finds @TestConfiguration and @Configuration classes in Spring application. @@ -102,7 +103,8 @@ open class BaseTestsModel( * @see [getSortedAnnotatedClasses] */ fun getSortedSpringConfigurationClasses(): Set = - getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION_FQN) + getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION_FQN) + getSortedAnnotatedClasses(SPRING_TESTCONFIGURATION_ANNOTATION_FQN) + + getSortedAnnotatedClasses(SPRING_CONFIGURATION_ANNOTATION_FQN) /** * Finds classes annotated with given annotation in [srcModule] and [potentialTestModules]. @@ -112,15 +114,21 @@ open class BaseTestsModel( * - 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 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() + .findClass(annotationFqn, GlobalSearchScope.allScope(project)) + ?: return emptySet() - val testRootToIndex = getSortedTestRoots().withIndex().associate { (i, root) -> root.dir to i } + val testRootToIndex = + getSortedTestRoots() + .withIndex() + .associate { (i, root) -> root.dir to i } return AnnotatedElementsSearch .searchPsiClasses(annotationClass, searchScope) diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt index 249fad7337..973d88596e 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt @@ -5,7 +5,9 @@ import org.utbot.intellij.plugin.models.packageName /** - * Used to build binary name from canonical name. + * Used to build binary name from canonical name + * in a similar form which could be obtained by [java.lang.Class.getName] method. + * * E.g. ```org.example.OuterClass.InnerClass.InnerInnerClass``` -> ```org.example.OuterClass$InnerClass$InnerInnerClass``` */ fun PsiClass.binaryName(): String = @@ -16,6 +18,6 @@ fun PsiClass.binaryName(): String = qualifiedName ?.substringAfter("$packageName.") ?.replace(".", "$") - ?: error("Binary name construction failed: unable to get qualified name for $this") + ?: error("Binary name construction failed: unable to get qualified name of $this") "$packageName.$name" - } \ No newline at end of file + } From e5c19a964eab6354a32ddff8312efee1eb243777 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Wed, 5 Jul 2023 19:31:24 +0300 Subject: [PATCH 3/8] Introduce SpringSettings --- .../org/utbot/framework/plugin/api/Api.kt | 48 ++++---- .../plugin/api/util/SpringModelUtils.kt | 3 + .../org/utbot/engine/UtBotSymbolicEngine.kt | 2 +- .../codegen/domain/models/TestClassModel.kt | 7 +- .../codegen/generator/SpringCodeGenerator.kt | 14 ++- ...CgSpringIntegrationTestClassConstructor.kt | 35 ++++-- .../framework/plugin/api/TestCaseGenerator.kt | 24 ++-- .../framework/process/EngineProcessMain.kt | 104 ++++++++++-------- .../generated/EngineProcessModel.Generated.kt | 68 ++++++------ .../SpringUtExecutionInstrumentation.kt | 5 +- .../mock/SpringInstrumentationContext.kt | 0 .../generator/CodeGenerationController.kt | 19 ++-- .../generator/UtTestsDialogProcessor.kt | 51 +++++---- .../plugin/models/GenerateTestsModel.kt | 18 +-- .../intellij/plugin/process/EngineProcess.kt | 85 ++++++++------ .../intellij/plugin/settings/Settings.kt | 2 +- .../plugin/ui/GenerateTestsDialogWindow.kt | 90 ++++++++------- .../org/utbot/rd/models/EngineProcessModel.kt | 7 +- .../utbot/rd/models/SpringAnalyzerModel.kt | 2 +- .../org/utbot/spring/api/ApplicationData.kt | 3 +- .../SpringAnalyzerProcessModel.Generated.kt | 14 +-- .../spring/process/SpringAnalyzerProcess.kt | 2 +- .../process/SpringAnalyzerProcessMain.kt | 5 +- .../org/utbot/spring/utils/SourceFinder.kt | 36 +++--- .../plugin/settings/CommonSettings.kt | 10 +- 25 files changed, 354 insertions(+), 300 deletions(-) create mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 3f032f9fa7..20ee5a2104 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1323,6 +1323,13 @@ enum class TypeReplacementMode { NoImplementors, } +interface CodeGenerationContext + +interface SpringCodeGenerationContext : CodeGenerationContext { + val springTestType: SpringTestType + val springSettings: SpringSettings? +} + /** * A context to use when no specific data is required. * @@ -1332,7 +1339,7 @@ enum class TypeReplacementMode { open class ApplicationContext( val mockFrameworkInstalled: Boolean = true, staticsMockingIsConfigured: Boolean = true, -) { +) : CodeGenerationContext { var staticsMockingIsConfigured = staticsMockingIsConfigured private set @@ -1384,23 +1391,16 @@ open class ApplicationContext( ): Boolean = field.isFinal || !field.isPublic } -sealed class TypeReplacementApproach { - /** - * Do not replace interfaces and abstract classes with concrete implementors. - * Use mocking instead of it. - */ - object DoNotReplace : TypeReplacementApproach() - - /** - * Try to replace interfaces and abstract classes with concrete implementors - * obtained from bean definitions. - * If it is impossible, use mocking. - * - * Currently used in Spring applications only. - */ - class ReplaceIfPossible(val config: String) : TypeReplacementApproach() +sealed interface SpringConfiguration { + class JavaConfiguration(val classBinaryName: String) : SpringConfiguration + class XMLConfiguration(val absolutePath: String) : SpringConfiguration } +class SpringSettings( + val configuration: SpringConfiguration, + val profileExpression: String +) + /** * Data we get from Spring application context * to manage engine and code generator behaviour. @@ -1422,9 +1422,9 @@ class SpringApplicationContext( staticsMockingIsConfigured: Boolean, val beanDefinitions: List = emptyList(), private val shouldUseImplementors: Boolean, - val typeReplacementApproach: TypeReplacementApproach, - val testType: SpringTestsType -): ApplicationContext(mockInstalled, staticsMockingIsConfigured) { + override val springTestType: SpringTestType, + override val springSettings: SpringSettings?, +): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext { companion object { private val logger = KotlinLogging.logger {} @@ -1500,19 +1500,19 @@ class SpringApplicationContext( ): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.declaringClass.id !in springInjectedClasses } -enum class SpringTestsType( +enum class SpringTestType( override val id: String, override val displayName: String, override val description: String, // Integration tests generation requires spring test framework being installed var frameworkInstalled: Boolean = false, ) : CodeGenerationSettingItem { - UNIT_TESTS( + UNIT_TEST( "Unit tests", "Unit tests", "Generate unit tests mocking other classes" ), - INTEGRATION_TESTS( + INTEGRATION_TEST( "Integration tests", "Integration tests", "Generate integration tests autowiring real instance" @@ -1521,8 +1521,8 @@ enum class SpringTestsType( override fun toString() = id companion object : CodeGenerationSettingBox { - override val defaultItem = UNIT_TESTS - override val allItems: List = values().toList() + override val defaultItem = UNIT_TEST + override val allItems: List = values().toList() } } diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt index 9befad4bf4..b4a890d797 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt @@ -31,6 +31,9 @@ object SpringModelUtils { val springBootTestContextBootstrapperClassId = ClassId("org.springframework.boot.test.context.SpringBootTestContextBootstrapper") + val activeProfilesClassId = ClassId("org.springframework.test.context.ActiveProfiles") + val contextConfigurationClassId = ClassId("org.springframework.test.context.ContextConfiguration") + // most likely only one persistent library is on the classpath, but we need to be able to work with either of them private val persistentLibraries = listOf("javax.persistence", "jakarta.persistence") diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index fab753b288..0715126fbb 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -388,7 +388,7 @@ class UtBotSymbolicEngine( var testEmittedByFuzzer = 0 val valueProviders = ValueProvider.of(defaultValueProviders(defaultIdGenerator)) .letIf(applicationContext is SpringApplicationContext - && applicationContext.typeReplacementApproach is TypeReplacementApproach.ReplaceIfPossible + && applicationContext.springSettings != null ) { provider -> val relevantRepositories = concreteExecutor.getRelevantSpringRepositories(methodUnderTest.classId) logger.info { "Detected relevant repositories for class ${methodUnderTest.classId}: $relevantRepositories" } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt index aabb89803a..d613d7e2d0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt @@ -30,9 +30,8 @@ class SpringTestClassModel( val springSpecificInformation: SpringSpecificInformation, ): TestClassModel(classUnderTest, methodTestSets, nestedClasses) - class SpringSpecificInformation( - val thisInstanceModels: TypedModelWrappers = mapOf(), - val thisInstanceDependentMocks: TypedModelWrappers = mapOf(), - val autowiredFromContextModels: TypedModelWrappers = mapOf(), + val thisInstanceModels: TypedModelWrappers, + val thisInstanceDependentMocks: TypedModelWrappers, + val autowiredFromContextModels: TypedModelWrappers, ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt index fca9b79b19..5e4aaa3b0b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt @@ -17,12 +17,13 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.MockFramework -import org.utbot.framework.plugin.api.SpringTestsType +import org.utbot.framework.plugin.api.SpringTestType +import org.utbot.framework.plugin.api.SpringCodeGenerationContext class SpringCodeGenerator( - private val springTestsType: SpringTestsType = SpringTestsType.defaultItem, val classUnderTest: ClassId, val projectType: ProjectType, + val codeGenerationContext: SpringCodeGenerationContext, paramNames: MutableMap> = mutableMapOf(), generateUtilClassFile: Boolean = false, testFramework: TestFramework = TestFramework.defaultItem, @@ -59,9 +60,12 @@ class SpringCodeGenerator( val testClassModel = SpringTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) logger.info { "Code generation phase started at ${now()}" } - val astConstructor = when (springTestsType) { - SpringTestsType.UNIT_TESTS -> CgSpringUnitTestClassConstructor(context) - SpringTestsType.INTEGRATION_TESTS -> CgSpringIntegrationTestClassConstructor(context) + val astConstructor = when (codeGenerationContext.springTestType) { + SpringTestType.UNIT_TEST -> CgSpringUnitTestClassConstructor(context) + SpringTestType.INTEGRATION_TEST -> + codeGenerationContext.springSettings + ?.let { CgSpringIntegrationTestClassConstructor(context, it) } + ?: error("Error text.") } val testClassFile = astConstructor.construct(testClassModel) logger.info { "Code generation phase finished at ${now()}" } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt index b089bbfe6e..2038688469 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt @@ -8,11 +8,14 @@ import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.* import org.utbot.framework.codegen.domain.models.AnnotationTarget.* import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.CodegenLanguage +import org.utbot.framework.plugin.api.SpringConfiguration +import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.util.SpringModelUtils +import org.utbot.framework.plugin.api.util.SpringModelUtils.activeProfilesClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.autoConfigureTestDbClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.autowiredClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.bootstrapWithClassId +import org.utbot.framework.plugin.api.util.SpringModelUtils.contextConfigurationClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.dirtiesContextClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.dirtiesContextClassModeClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.springBootTestContextBootstrapperClassId @@ -20,20 +23,25 @@ import org.utbot.framework.plugin.api.util.SpringModelUtils.springExtensionClass import org.utbot.framework.plugin.api.util.SpringModelUtils.transactionalClassId import org.utbot.framework.plugin.api.util.utContext -class CgSpringIntegrationTestClassConstructor(context: CgContext) : CgAbstractSpringTestClassConstructor(context) { +class CgSpringIntegrationTestClassConstructor( + context: CgContext, + private val springSettings: SpringSettings +) : CgAbstractSpringTestClassConstructor(context) { override fun constructTestClass(testClassModel: SpringTestClassModel): CgClass { - collectSpringSpecificAnnotations() + addNecessarySpringSpecificAnnotations() return super.constructTestClass(testClassModel) } override fun constructClassFields(testClassModel: SpringTestClassModel): List { - val autowiredFromContextModels = testClassModel.springSpecificInformation.autowiredFromContextModels + val autowiredFromContextModels = + testClassModel.springSpecificInformation.autowiredFromContextModels return constructFieldsWithAnnotation(autowiredClassId, autowiredFromContextModels) } - override fun constructAdditionalMethods() = CgMethodsCluster(header = null, content = emptyList()) + override fun constructAdditionalMethods() = + CgMethodsCluster(header = null, content = emptyList()) - private fun collectSpringSpecificAnnotations() { + private fun addNecessarySpringSpecificAnnotations() { val springRunnerType = when (testFramework) { Junit4 -> SpringModelUtils.runWithClassId Junit5 -> SpringModelUtils.extendWithClassId @@ -41,17 +49,26 @@ class CgSpringIntegrationTestClassConstructor(context: CgContext) : CgAbstractSp else -> error("Trying to generate tests for Spring project with non-JVM framework") } - statementConstructor.addAnnotation( + addAnnotation( classId = springRunnerType, argument = createGetClassExpression(springExtensionClassId, codegenLanguage), target = Class, ) - statementConstructor.addAnnotation( + addAnnotation( classId = bootstrapWithClassId, argument = createGetClassExpression(springBootTestContextBootstrapperClassId, codegenLanguage), target = Class, ) - + addAnnotation( + classId = activeProfilesClassId, + argument = springSettings.profileExpression, // TODO: separate by comma + target = Class, + ) + addAnnotation( + classId = contextConfigurationClassId, + argument = (springSettings.configuration as SpringConfiguration.JavaConfiguration).classBinaryName, // TODO: unpacking + target = Class, + ) addAnnotation( classId = dirtiesContextClassId, namedArguments = listOf( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt index 41c067adc8..090cb66666 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt @@ -69,19 +69,19 @@ open class TestCaseGenerator( private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout") private val executionInstrumentation by lazy { when (applicationContext) { - is SpringApplicationContext -> when (val approach = applicationContext.typeReplacementApproach) { - is TypeReplacementApproach.ReplaceIfPossible -> - when (applicationContext.testType) { - SpringTestsType.UNIT_TESTS -> UtExecutionInstrumentation - SpringTestsType.INTEGRATION_TESTS -> SpringUtExecutionInstrumentation( - UtExecutionInstrumentation, - approach.config, - applicationContext.beanDefinitions, - buildDirs.map { it.toURL() }.toTypedArray(), - ) - } - is TypeReplacementApproach.DoNotReplace -> UtExecutionInstrumentation + is SpringApplicationContext -> when (val springSettings = applicationContext.springSettings) { + null -> UtExecutionInstrumentation + else -> when (applicationContext.springTestType) { + SpringTestType.UNIT_TEST -> UtExecutionInstrumentation + SpringTestType.INTEGRATION_TEST -> SpringUtExecutionInstrumentation( + UtExecutionInstrumentation, + springSettings, + applicationContext.beanDefinitions, + buildDirs.map { it.toURL() }.toTypedArray(), + ) + } } + else -> UtExecutionInstrumentation } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt index e0a428eab8..0863807662 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt @@ -83,7 +83,7 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch val springAnalyzerProcess = SpringAnalyzerProcess.createBlocking(params.classpath.toList()) val result = springAnalyzerProcess.terminateOnException { _ -> springAnalyzerProcess.getBeanDefinitions( - params.config, + params.configuration, params.fileStorage, params.profileExpression, ) @@ -152,8 +152,7 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch } } watchdog.measureTimeForActiveCall(render, "Rendering tests") { params -> - val projectType = ProjectType.valueOf(params.projectType) - val codeGenerator = projectType.createCodeGenerator(kryoHelper, params) + val codeGenerator = createCodeGenerator(kryoHelper, params) codeGenerator.generateAsStringWithTestReport(testSets[params.testSetsId]!!).let { testGenerationReports.add(it.testsGenerationReport) @@ -292,56 +291,71 @@ private fun destinationWarningMessage(testPackageName: String?, classUnderTestPa } } -private fun ProjectType.createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams): AbstractCodeGenerator { +private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams): AbstractCodeGenerator { with(params) { val classUnderTest: ClassId = kryoHelper.readObject(classUnderTest) val paramNames: MutableMap> = kryoHelper.readObject(paramNames) val testFramework = testFrameworkByName(testFramework) val staticMocking = if (staticsMocking.startsWith("No")) NoStaticMocking else MockitoStaticMocking val forceStaticMocking: ForceStaticMocking = kryoHelper.readObject(forceStaticMocking) + val projectType = ProjectType.valueOf(projectType) + val codeGenerationContext: CodeGenerationContext = kryoHelper.readObject(codeGenerationContext) - return when (this@createCodeGenerator) { - ProjectType.PureJvm -> CodeGenerator( - classUnderTest = classUnderTest, - projectType = ProjectType.valueOf(projectType), - generateUtilClassFile = generateUtilClassFile, - paramNames = paramNames, - testFramework = testFramework, - mockFramework = MockFramework.valueOf(mockFramework), - codegenLanguage = CodegenLanguage.valueOf(codegenLanguage), - cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(CodegenLanguage.valueOf(codegenLanguage)), - parameterizedTestSource = ParametrizedTestSource.valueOf(parameterizedTestSource), - staticsMocking = staticMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = generateWarningsForStaticMocking, - runtimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.valueOf(runtimeExceptionTestsBehaviour), - hangingTestsTimeout = HangingTestsTimeout(hangingTestsTimeout), - enableTestsTimeout = enableTestsTimeout, - testClassPackageName = testClassPackageName, - ) - - ProjectType.Spring -> SpringCodeGenerator( - springTestsType = SpringTestsType.valueOf(springTestsType), - classUnderTest = classUnderTest, - projectType = ProjectType.valueOf(projectType), - generateUtilClassFile = generateUtilClassFile, - paramNames = paramNames, - testFramework = testFramework, - mockFramework = MockFramework.valueOf(mockFramework), - codegenLanguage = CodegenLanguage.valueOf(codegenLanguage), - cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(CodegenLanguage.valueOf(codegenLanguage)), - parameterizedTestSource = ParametrizedTestSource.valueOf(parameterizedTestSource), - staticsMocking = staticMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = generateWarningsForStaticMocking, - runtimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.valueOf(runtimeExceptionTestsBehaviour), - hangingTestsTimeout = HangingTestsTimeout(hangingTestsTimeout), - enableTestsTimeout = enableTestsTimeout, - testClassPackageName = testClassPackageName, - ) + return when (codeGenerationContext) { + is SpringCodeGenerationContext -> { + SpringCodeGenerator( + classUnderTest = classUnderTest, + projectType = projectType, + codeGenerationContext = codeGenerationContext, + generateUtilClassFile = generateUtilClassFile, + paramNames = paramNames, + testFramework = testFramework, + mockFramework = MockFramework.valueOf(mockFramework), + codegenLanguage = CodegenLanguage.valueOf(codegenLanguage), + cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage( + CodegenLanguage.valueOf( + codegenLanguage + ) + ), + parameterizedTestSource = ParametrizedTestSource.valueOf(parameterizedTestSource), + staticsMocking = staticMocking, + forceStaticMocking = forceStaticMocking, + generateWarningsForStaticMocking = generateWarningsForStaticMocking, + runtimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.valueOf( + runtimeExceptionTestsBehaviour + ), + hangingTestsTimeout = HangingTestsTimeout(hangingTestsTimeout), + enableTestsTimeout = enableTestsTimeout, + testClassPackageName = testClassPackageName, + ) + } - ProjectType.Python -> error("Python code generator can not be created in Engine process") - ProjectType.JavaScript -> error("JavaScript code generator can not be created in Engine process") + else -> { + CodeGenerator( + classUnderTest = classUnderTest, + projectType = projectType, + generateUtilClassFile = generateUtilClassFile, + paramNames = paramNames, + testFramework = testFramework, + mockFramework = MockFramework.valueOf(mockFramework), + codegenLanguage = CodegenLanguage.valueOf(codegenLanguage), + cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage( + CodegenLanguage.valueOf( + codegenLanguage + ) + ), + parameterizedTestSource = ParametrizedTestSource.valueOf(parameterizedTestSource), + staticsMocking = staticMocking, + forceStaticMocking = forceStaticMocking, + generateWarningsForStaticMocking = generateWarningsForStaticMocking, + runtimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.valueOf( + runtimeExceptionTestsBehaviour + ), + hangingTestsTimeout = HangingTestsTimeout(hangingTestsTimeout), + enableTestsTimeout = enableTestsTimeout, + testClassPackageName = testClassPackageName, + ) + } } } } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt index 8f75c385e4..915e4aad46 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt @@ -75,7 +75,7 @@ class EngineProcessModel private constructor( } - const val serializationHash = -7418312653824196007L + const val serializationHash = -1921561018844578859L } override val serializersOwner: ISerializersOwner get() = EngineProcessModel @@ -182,7 +182,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel /** - * #### Generated from [EngineProcessModel.kt:134] + * #### Generated from [EngineProcessModel.kt:133] */ data class BeanAdditionalData ( val factoryMethodName: String, @@ -251,7 +251,7 @@ data class BeanAdditionalData ( /** - * #### Generated from [EngineProcessModel.kt:139] + * #### Generated from [EngineProcessModel.kt:138] */ data class BeanDefinitionData ( val beanName: String, @@ -320,7 +320,7 @@ data class BeanDefinitionData ( /** - * #### Generated from [EngineProcessModel.kt:108] + * #### Generated from [EngineProcessModel.kt:107] */ data class FindMethodParamNamesArguments ( val classId: ByteArray, @@ -383,7 +383,7 @@ data class FindMethodParamNamesArguments ( /** - * #### Generated from [EngineProcessModel.kt:112] + * #### Generated from [EngineProcessModel.kt:111] */ data class FindMethodParamNamesResult ( val paramNames: ByteArray @@ -440,7 +440,7 @@ data class FindMethodParamNamesResult ( /** - * #### Generated from [EngineProcessModel.kt:101] + * #### Generated from [EngineProcessModel.kt:100] */ data class FindMethodsInClassMatchingSelectedArguments ( val classId: ByteArray, @@ -503,7 +503,7 @@ data class FindMethodsInClassMatchingSelectedArguments ( /** - * #### Generated from [EngineProcessModel.kt:105] + * #### Generated from [EngineProcessModel.kt:104] */ data class FindMethodsInClassMatchingSelectedResult ( val executableIds: ByteArray @@ -560,7 +560,7 @@ data class FindMethodsInClassMatchingSelectedResult ( /** - * #### Generated from [EngineProcessModel.kt:44] + * #### Generated from [EngineProcessModel.kt:43] */ data class GenerateParams ( val methods: ByteArray, @@ -671,7 +671,7 @@ data class GenerateParams ( /** - * #### Generated from [EngineProcessModel.kt:60] + * #### Generated from [EngineProcessModel.kt:59] */ data class GenerateResult ( val notEmptyCases: Int, @@ -734,7 +734,7 @@ data class GenerateResult ( /** - * #### Generated from [EngineProcessModel.kt:120] + * #### Generated from [EngineProcessModel.kt:119] */ data class GenerateTestReportArgs ( val eventLogMessage: String?, @@ -827,7 +827,7 @@ data class GenerateTestReportArgs ( /** - * #### Generated from [EngineProcessModel.kt:129] + * #### Generated from [EngineProcessModel.kt:128] */ data class GenerateTestReportResult ( val notifyMessage: String, @@ -896,11 +896,11 @@ data class GenerateTestReportResult ( /** - * #### Generated from [EngineProcessModel.kt:90] + * #### Generated from [EngineProcessModel.kt:89] */ data class GetSpringBeanDefinitions ( val classpath: Array, - val config: String, + val configuration: ByteArray, val fileStorage: Array, val profileExpression: String? ) : IPrintable { @@ -912,15 +912,15 @@ data class GetSpringBeanDefinitions ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): GetSpringBeanDefinitions { val classpath = buffer.readArray {buffer.readString()} - val config = buffer.readString() + val configuration = buffer.readByteArray() val fileStorage = buffer.readArray {buffer.readString()} val profileExpression = buffer.readNullable { buffer.readString() } - return GetSpringBeanDefinitions(classpath, config, fileStorage, profileExpression) + return GetSpringBeanDefinitions(classpath, configuration, fileStorage, profileExpression) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: GetSpringBeanDefinitions) { buffer.writeArray(value.classpath) { buffer.writeString(it) } - buffer.writeString(value.config) + buffer.writeByteArray(value.configuration) buffer.writeArray(value.fileStorage) { buffer.writeString(it) } buffer.writeNullable(value.profileExpression) { buffer.writeString(it) } } @@ -939,7 +939,7 @@ data class GetSpringBeanDefinitions ( other as GetSpringBeanDefinitions if (!(classpath contentDeepEquals other.classpath)) return false - if (config != other.config) return false + if (!(configuration contentEquals other.configuration)) return false if (!(fileStorage contentDeepEquals other.fileStorage)) return false if (profileExpression != other.profileExpression) return false @@ -949,7 +949,7 @@ data class GetSpringBeanDefinitions ( override fun hashCode(): Int { var __r = 0 __r = __r*31 + classpath.contentDeepHashCode() - __r = __r*31 + config.hashCode() + __r = __r*31 + configuration.contentHashCode() __r = __r*31 + fileStorage.contentDeepHashCode() __r = __r*31 + if (profileExpression != null) profileExpression.hashCode() else 0 return __r @@ -959,7 +959,7 @@ data class GetSpringBeanDefinitions ( printer.println("GetSpringBeanDefinitions (") printer.indent { print("classpath = "); classpath.print(printer); println() - print("config = "); config.print(printer); println() + print("configuration = "); configuration.print(printer); println() print("fileStorage = "); fileStorage.print(printer); println() print("profileExpression = "); profileExpression.print(printer); println() } @@ -1034,7 +1034,7 @@ data class JdkInfo ( /** - * #### Generated from [EngineProcessModel.kt:96] + * #### Generated from [EngineProcessModel.kt:95] */ data class MethodDescription ( val name: String, @@ -1103,10 +1103,9 @@ data class MethodDescription ( /** - * #### Generated from [EngineProcessModel.kt:64] + * #### Generated from [EngineProcessModel.kt:63] */ data class RenderParams ( - val springTestsType: String, val testSetsId: Long, val classUnderTest: ByteArray, val projectType: String, @@ -1122,7 +1121,8 @@ data class RenderParams ( val runtimeExceptionTestsBehaviour: String, val hangingTestsTimeout: Long, val enableTestsTimeout: Boolean, - val testClassPackageName: String + val testClassPackageName: String, + val codeGenerationContext: ByteArray ) : IPrintable { //companion @@ -1131,7 +1131,6 @@ data class RenderParams ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): RenderParams { - val springTestsType = buffer.readString() val testSetsId = buffer.readLong() val classUnderTest = buffer.readByteArray() val projectType = buffer.readString() @@ -1148,11 +1147,11 @@ data class RenderParams ( val hangingTestsTimeout = buffer.readLong() val enableTestsTimeout = buffer.readBool() val testClassPackageName = buffer.readString() - return RenderParams(springTestsType, testSetsId, classUnderTest, projectType, paramNames, generateUtilClassFile, testFramework, mockFramework, codegenLanguage, parameterizedTestSource, staticsMocking, forceStaticMocking, generateWarningsForStaticMocking, runtimeExceptionTestsBehaviour, hangingTestsTimeout, enableTestsTimeout, testClassPackageName) + val codeGenerationContext = buffer.readByteArray() + return RenderParams(testSetsId, classUnderTest, projectType, paramNames, generateUtilClassFile, testFramework, mockFramework, codegenLanguage, parameterizedTestSource, staticsMocking, forceStaticMocking, generateWarningsForStaticMocking, runtimeExceptionTestsBehaviour, hangingTestsTimeout, enableTestsTimeout, testClassPackageName, codeGenerationContext) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: RenderParams) { - buffer.writeString(value.springTestsType) buffer.writeLong(value.testSetsId) buffer.writeByteArray(value.classUnderTest) buffer.writeString(value.projectType) @@ -1169,6 +1168,7 @@ data class RenderParams ( buffer.writeLong(value.hangingTestsTimeout) buffer.writeBool(value.enableTestsTimeout) buffer.writeString(value.testClassPackageName) + buffer.writeByteArray(value.codeGenerationContext) } @@ -1184,7 +1184,6 @@ data class RenderParams ( other as RenderParams - if (springTestsType != other.springTestsType) return false if (testSetsId != other.testSetsId) return false if (!(classUnderTest contentEquals other.classUnderTest)) return false if (projectType != other.projectType) return false @@ -1201,13 +1200,13 @@ data class RenderParams ( if (hangingTestsTimeout != other.hangingTestsTimeout) return false if (enableTestsTimeout != other.enableTestsTimeout) return false if (testClassPackageName != other.testClassPackageName) return false + if (!(codeGenerationContext contentEquals other.codeGenerationContext)) return false return true } //hash code trait override fun hashCode(): Int { var __r = 0 - __r = __r*31 + springTestsType.hashCode() __r = __r*31 + testSetsId.hashCode() __r = __r*31 + classUnderTest.contentHashCode() __r = __r*31 + projectType.hashCode() @@ -1224,13 +1223,13 @@ data class RenderParams ( __r = __r*31 + hangingTestsTimeout.hashCode() __r = __r*31 + enableTestsTimeout.hashCode() __r = __r*31 + testClassPackageName.hashCode() + __r = __r*31 + codeGenerationContext.contentHashCode() return __r } //pretty print override fun print(printer: PrettyPrinter) { printer.println("RenderParams (") printer.indent { - print("springTestsType = "); springTestsType.print(printer); println() print("testSetsId = "); testSetsId.print(printer); println() print("classUnderTest = "); classUnderTest.print(printer); println() print("projectType = "); projectType.print(printer); println() @@ -1247,6 +1246,7 @@ data class RenderParams ( print("hangingTestsTimeout = "); hangingTestsTimeout.print(printer); println() print("enableTestsTimeout = "); enableTestsTimeout.print(printer); println() print("testClassPackageName = "); testClassPackageName.print(printer); println() + print("codeGenerationContext = "); codeGenerationContext.print(printer); println() } printer.print(")") } @@ -1256,7 +1256,7 @@ data class RenderParams ( /** - * #### Generated from [EngineProcessModel.kt:83] + * #### Generated from [EngineProcessModel.kt:82] */ data class RenderResult ( val generatedCode: String, @@ -1319,7 +1319,7 @@ data class RenderResult ( /** - * #### Generated from [EngineProcessModel.kt:87] + * #### Generated from [EngineProcessModel.kt:86] */ data class SetupContextParams ( val classpathForUrlsClassloader: List @@ -1376,7 +1376,7 @@ data class SetupContextParams ( /** - * #### Generated from [EngineProcessModel.kt:144] + * #### Generated from [EngineProcessModel.kt:143] */ data class SpringAnalyzerResult ( val beanDefinitions: Array @@ -1433,7 +1433,7 @@ data class SpringAnalyzerResult ( /** - * #### Generated from [EngineProcessModel.kt:37] + * #### Generated from [EngineProcessModel.kt:36] */ data class TestGeneratorParams ( val buildDir: Array, @@ -1514,7 +1514,7 @@ data class TestGeneratorParams ( /** - * #### Generated from [EngineProcessModel.kt:115] + * #### Generated from [EngineProcessModel.kt:114] */ data class WriteSarifReportArguments ( val testSetsId: Long, diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt index da44800b9a..9709220657 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt @@ -7,6 +7,7 @@ import org.utbot.common.hasOnClasspath import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringRepositoryId +import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.util.jClass import org.utbot.instrumentation.instrumentation.ArgumentList import org.utbot.instrumentation.instrumentation.Instrumentation @@ -19,11 +20,11 @@ import java.net.URLClassLoader import java.security.ProtectionDomain /** - * UtExecutionInstrumentation wrapper that is aware of Spring config and initialises Spring context + * UtExecutionInstrumentation wrapper that is aware of Spring configuration and profiles and initialises Spring context */ class SpringUtExecutionInstrumentation( private val delegateInstrumentation: UtExecutionInstrumentation, - private val springConfig: String, + private val springSettings: SpringSettings, private val beanDefinitions: List, private val buildDirs: Array, ) : Instrumentation by delegateInstrumentation { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt new file mode 100644 index 0000000000..e69de29bb2 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 f35c1ae026..f4dcca809b 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 @@ -71,6 +71,7 @@ import org.utbot.framework.codegen.domain.StaticImport 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.CodeGenerationContext import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.intellij.plugin.inspection.UnitTestBotInspectionManager import org.utbot.intellij.plugin.models.GenerateTestsModel @@ -115,6 +116,7 @@ object CodeGenerationController { fun generateTests( model: GenerateTestsModel, + codeGenerationContext: CodeGenerationContext, classesWithTests: Map, psi2KClass: Map, process: EngineProcess, @@ -161,6 +163,7 @@ object CodeGenerationController { testFilePointer, srcClassPathToSarifReport, model, + codeGenerationContext, latch, utilClassListener, indicator @@ -664,6 +667,7 @@ object CodeGenerationController { filePointer: SmartPsiElementPointer, srcClassPathToSarifReport: MutableMap, model: GenerateTestsModel, + codeGenerationContext: CodeGenerationContext, reportsCountDown: CountDownLatch, utilClassListener: UtilClassListener, indicator: ProgressIndicator @@ -684,23 +688,14 @@ object CodeGenerationController { return@run } proc.render( - model.springTestsType, + model, testSetsId, classUnderTest, - model.projectType, paramNames.toMutableMap(), generateUtilClassFile = true, - model.testFramework, - model.mockFramework, - model.staticsMocking, - model.forceStaticMocking, - model.generateWarningsForStaticMocking, - model.codegenLanguage, - model.parametrizedTestSource, - model.runtimeExceptionTestsBehaviour, - model.hangingTestsTimeout, enableTestsTimeout = true, - testPackageName + testPackageName, + codeGenerationContext ) } catch (e: Exception) { logger.warn(e) { "Cannot render test class ${testClass.name}" } 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 0fed3d2cb4..ef1548c215 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 @@ -49,13 +49,13 @@ import org.utbot.framework.CancellationStrategyType.NONE import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS import org.utbot.framework.UtSettings import org.utbot.framework.codegen.domain.ProjectType.* -import org.utbot.framework.plugin.api.TypeReplacementApproach.* import org.utbot.framework.plugin.api.ApplicationContext +import org.utbot.framework.plugin.api.SpringConfiguration.* +import org.utbot.framework.plugin.api.SpringTestType.* import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.JavaDocCommentStyle import org.utbot.framework.plugin.api.SpringApplicationContext -import org.utbot.framework.plugin.api.SpringTestsType import org.utbot.framework.plugin.api.util.LockFile import org.utbot.framework.plugin.api.util.withStaticsSubstitutionRequired import org.utbot.framework.plugin.services.JdkInfoService @@ -174,17 +174,18 @@ object UtTestsDialogProcessor { } private fun createTests(project: Project, model: GenerateTestsModel) { - val springConfigClass = when (val approach = model.typeReplacementApproach) { - DoNotReplace -> null - is ReplaceIfPossible -> - approach.config.takeUnless { it.endsWith(".xml") }?.let { + val springConfigClass = + when (val config = model.springSettings?.configuration) { + is JavaConfiguration -> { // Converting binary name to fqn name - val fqnName = it.replace("$", ".") + val fqnName = config.classBinaryName.replace("$", ".") PsiClassHelper .findClass(fqnName, project) - ?: error("Cannot find configuration class $it with $fqnName name.") + ?: error("Cannot find configuration class $fqnName.") } - } + + else -> null + } val filesToCompile = (model.srcClasses + listOfNotNull(springConfigClass)) .map { it.containingFile.virtualFile } @@ -255,9 +256,9 @@ object UtTestsDialogProcessor { val applicationContext = when (model.projectType) { Spring -> { val beanDefinitions = - when (val approach = model.typeReplacementApproach) { - DoNotReplace -> emptyList() - is ReplaceIfPossible -> { + when (val approach = model.springSettings) { + null -> emptyList() + else -> { val contentRoots = runReadAction { listOfNotNull( model.srcModule, @@ -270,9 +271,9 @@ object UtTestsDialogProcessor { val fileStorage = contentRoots.map { root -> root.url }.toTypedArray() process.getSpringBeanDefinitions( classpathForClassLoader, - approach.config, + approach.configuration, + approach.profileExpression, fileStorage, - model.profileNames, ) } } @@ -286,8 +287,8 @@ object UtTestsDialogProcessor { staticMockingConfigured, clarifiedBeanDefinitions, shouldUseImplementors, - model.typeReplacementApproach, - model.springTestsType + model.springTestType, + model.springSettings, ) } else -> ApplicationContext(mockFrameworkInstalled, staticMockingConfigured) @@ -380,20 +381,18 @@ object UtTestsDialogProcessor { }, 0, 500, TimeUnit.MILLISECONDS) try { val useEngine = when (model.projectType) { - Spring -> when (model.springTestsType) { - SpringTestsType.UNIT_TESTS -> true - SpringTestsType.INTEGRATION_TESTS -> false + Spring -> when (model.springTestType) { + UNIT_TEST -> true + INTEGRATION_TEST -> false } else -> true } val useFuzzing = when (model.projectType) { - Spring -> when (model.springTestsType) { - SpringTestsType.UNIT_TESTS -> when (model.typeReplacementApproach) { - DoNotReplace -> true - is ReplaceIfPossible -> false - } - SpringTestsType.INTEGRATION_TESTS -> true + Spring -> when (model.springTestType) { + UNIT_TEST -> model.springSettings == null + INTEGRATION_TEST -> true } + else -> UtSettings.useFuzzing } val rdGenerateResult = process.generate( @@ -449,7 +448,7 @@ object UtTestsDialogProcessor { // indicator.checkCanceled() invokeLater { - generateTests(model, testSetsByClass, psi2KClass, process, indicator) + generateTests(model, applicationContext, testSetsByClass, psi2KClass, process, indicator) logger.info { "Generation complete" } } } 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 1bc2e481fc..c8ea64cdd7 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 @@ -7,9 +7,6 @@ import org.utbot.framework.codegen.domain.ParametrizedTestSource import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.MockFramework -import org.utbot.framework.plugin.api.MockStrategyApi import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.psi.PsiClass @@ -19,9 +16,12 @@ import org.jetbrains.concurrency.Promise import org.jetbrains.kotlin.psi.KtFile import org.utbot.framework.SummariesGenerationType import org.utbot.framework.UtSettings -import org.utbot.framework.plugin.api.TypeReplacementApproach +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.MockFramework +import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.framework.plugin.api.JavaDocCommentStyle -import org.utbot.framework.plugin.api.SpringTestsType +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 @@ -44,7 +44,7 @@ class GenerateTestsModel( override var sourceRootHistory = project.service().sourceRootHistory override var codegenLanguage = project.service().codegenLanguage - lateinit var springTestsType: SpringTestsType + lateinit var springTestType: SpringTestType lateinit var testFramework: TestFramework lateinit var mockStrategy: MockStrategyApi @@ -59,8 +59,10 @@ class GenerateTestsModel( lateinit var chosenClassesToMockAlways: Set lateinit var commentStyle: JavaDocCommentStyle - lateinit var typeReplacementApproach: TypeReplacementApproach - lateinit var profileNames: String + /** + * TODO: Null when there is no configuration provided. + */ + var springSettings: SpringSettings? = null val conflictTriggers: ConflictTriggers = ConflictTriggers() val preCompilePromises: MutableList> = mutableListOf() diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt index e5ffdef0dc..9cf157b446 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt @@ -15,7 +15,6 @@ import kotlinx.coroutines.runBlocking import mu.KotlinLogging import org.utbot.common.* import org.utbot.framework.UtSettings -import org.utbot.framework.codegen.domain.* import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.BeanAdditionalData @@ -145,12 +144,18 @@ class EngineProcess private constructor(val project: Project, private val classN fun getSpringBeanDefinitions( classpathList: List, - config: String, + configuration: SpringConfiguration, + profileExpression: String?, fileStorage: Array, - profileExpression: String?): List { + ): List { assertReadAccessNotAllowed() val result = engineModel.getSpringBeanDefinitions.startBlocking( - GetSpringBeanDefinitions(classpathList.toTypedArray(), config, fileStorage, profileExpression) + GetSpringBeanDefinitions( + classpathList.toTypedArray(), + kryoHelper.writeObject(configuration), + fileStorage, + profileExpression + ) ) return result.beanDefinitions .map { data -> @@ -280,55 +285,67 @@ class EngineProcess private constructor(val project: Project, private val classN } fun render( - springTestsType: SpringTestsType, + model: GenerateTestsModel, testSetsId: Long, classUnderTest: ClassId, - projectType: ProjectType, paramNames: MutableMap>, generateUtilClassFile: Boolean, - testFramework: TestFramework, - mockFramework: MockFramework, - staticsMocking: StaticsMocking, - forceStaticMocking: ForceStaticMocking, - generateWarningsForStaticsMocking: Boolean, - codegenLanguage: CodegenLanguage, - parameterizedTestSource: ParametrizedTestSource, - runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour, - hangingTestSource: HangingTestsTimeout, enableTestsTimeout: Boolean, - testClassPackageName: String + testClassPackageName: String, + codeGenerationContext: CodeGenerationContext, ): Pair { assertReadAccessNotAllowed() - val params = RenderParams( - springTestsType.name, + val params = makeParams( + model, testSetsId, - kryoHelper.writeObject(classUnderTest), - projectType.toString(), - kryoHelper.writeObject(paramNames), + classUnderTest, + paramNames, generateUtilClassFile, - testFramework.id.lowercase(), - mockFramework.name, - codegenLanguage.name, - parameterizedTestSource.name, - staticsMocking.id, - kryoHelper.writeObject(forceStaticMocking), - generateWarningsForStaticsMocking, - runtimeExceptionTestsBehaviour.name, - hangingTestSource.timeoutMs, enableTestsTimeout, - testClassPackageName + testClassPackageName, + codeGenerationContext, ) val result = engineModel.render.startBlocking(params) val realUtilClassKind = result.utilClassKind?.let { - if (UtilClassKind.RegularUtUtils(codegenLanguage).javaClass.simpleName == it) - UtilClassKind.RegularUtUtils(codegenLanguage) + if (UtilClassKind.RegularUtUtils(model.codegenLanguage).javaClass.simpleName == it) + UtilClassKind.RegularUtUtils(model.codegenLanguage) else - UtilClassKind.UtUtilsWithMockito(codegenLanguage) + UtilClassKind.UtUtilsWithMockito(model.codegenLanguage) } return result.generatedCode to realUtilClassKind } + private fun makeParams( + model: GenerateTestsModel, + testSetsId: Long, + classUnderTest: ClassId, + paramNames: MutableMap>, + generateUtilClassFile: Boolean, + enableTestsTimeout: Boolean, + testClassPackageName: String, + codeGenerationContext: CodeGenerationContext, + ): RenderParams = + RenderParams( + testSetsId, + kryoHelper.writeObject(classUnderTest), + model.projectType.toString(), + kryoHelper.writeObject(paramNames), + generateUtilClassFile, + model.testFramework.id.lowercase(), + model.mockFramework.name, + model.codegenLanguage.name, + model.parametrizedTestSource.name, + model.staticsMocking.id, + kryoHelper.writeObject(model.forceStaticMocking), + model.generateWarningsForStaticMocking, + model.runtimeExceptionTestsBehaviour.name, + model.hangingTestsTimeout.timeoutMs, + enableTestsTimeout, + testClassPackageName, + kryoHelper.writeObject(codeGenerationContext), + ) + private fun getSourceFile(params: SourceStrategyMethodArgs): String? = DumbService.getInstance(project).runReadActionInSmartMode { sourceFindingStrategies[params.testSetId]!!.getSourceFile( diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Settings.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Settings.kt index d012b0d3bd..4de8b70089 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Settings.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Settings.kt @@ -24,7 +24,7 @@ private fun fromGenerateTestsModel(model: GenerateTestsModel): Settings.State { forceStaticMocking = model.forceStaticMocking, parametrizedTestSource = model.parametrizedTestSource, classesToMockAlways = model.chosenClassesToMockAlways.mapTo(mutableSetOf()) { it.name }.toTypedArray(), - springTestsType = model.springTestsType, + springTestType = model.springTestType, fuzzingValue = model.fuzzingValue, runGeneratedTestsWithCoverage = model.runGeneratedTestsWithCoverage, commentStyle = model.commentStyle, diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index 8a78a259b4..bbf51d760b 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -90,15 +90,16 @@ import org.utbot.framework.codegen.domain.SpringBoot import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.domain.TestNg -import org.utbot.framework.plugin.api.CodeGenerationSettingItem -import org.utbot.framework.plugin.api.CodegenLanguage -import org.utbot.framework.plugin.api.MockFramework -import org.utbot.framework.plugin.api.MockFramework.MOCKITO import org.utbot.framework.plugin.api.MockStrategyApi -import org.utbot.framework.plugin.api.SpringTestsType -import org.utbot.framework.plugin.api.SpringTestsType.* import org.utbot.framework.plugin.api.TreatOverflowAsError -import org.utbot.framework.plugin.api.TypeReplacementApproach +import org.utbot.framework.plugin.api.MockFramework.MOCKITO +import org.utbot.framework.plugin.api.SpringTestType +import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.MockFramework +import org.utbot.framework.plugin.api.CodegenLanguage +import org.utbot.framework.plugin.api.CodeGenerationSettingItem +import org.utbot.framework.plugin.api.SpringConfiguration +import org.utbot.framework.plugin.api.SpringTestType.* import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FILE_CONTENT import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FOLDER import org.utbot.framework.plugin.api.utils.MOCKITO_MOCKMAKER_FILE_NAME @@ -204,7 +205,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m private val mockStrategies = createComboBox(MockStrategyApi.values()) private val staticsMocking = JCheckBox("Mock static methods") - private val springTestsType = createComboBox(SpringTestsType.values()) + private val springTestType = createComboBox(SpringTestType.values()) private val springConfig = createComboBoxWithSeparatorsForSpringConfigs(shortenConfigurationNames()) private val profileNames = JBTextField(23).apply { emptyText.text = DEFAULT_SPRING_PROFILE_NAME } @@ -374,7 +375,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m else -> null } installedDiFramework?.let { - INTEGRATION_TESTS.frameworkInstalled = findDependencyInjectionTestLibrary(model.testModule, it) != null + INTEGRATION_TEST.frameworkInstalled = findDependencyInjectionTestLibrary(model.testModule, it) != null } model.projectType = if (installedDiFramework != null) ProjectType.Spring else ProjectType.PureJvm @@ -422,7 +423,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m ) } row("Tests type:") { - cell(springTestsType) + cell(springTestType) contextHelp( "Unit tests do not initialize ApplicationContext
" + "and do not autowire beans, while integration tests do." @@ -699,23 +700,28 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.timeout = TimeUnit.SECONDS.toMillis(timeoutSpinner.number.toLong()) model.testSourceRoot?.apply { model.updateSourceRootHistory(this.toNioPath().toString()) } - model.typeReplacementApproach = - when (springConfig.item) { - NO_SPRING_CONFIGURATION_OPTION -> TypeReplacementApproach.DoNotReplace - else -> { - val shortConfigName = springConfig.item.toString() - //TODO: avoid this check on xml here, merge two helpers into one - val fullConfigName = if (isXmlSpringConfigUsed()) { - xmlConfigurationHelper.restoreFullName(shortConfigName) - } else { - javaConfigurationHelper.restoreFullName(shortConfigName) - } - - TypeReplacementApproach.ReplaceIfPossible(fullConfigName) + when (springConfig.item) { + NO_SPRING_CONFIGURATION_OPTION -> null + else -> { + val shortConfigName = springConfig.item.toString() + //TODO: avoid this check on xml here, merge two helpers into one + if (isXmlSpringConfigUsed()) { + val absolutePath = xmlConfigurationHelper.restoreFullName(shortConfigName) + SpringConfiguration.XMLConfiguration(absolutePath) + } else { + val classBinaryName = javaConfigurationHelper.restoreFullName(shortConfigName) + SpringConfiguration.JavaConfiguration(classBinaryName) } } - model.profileNames = profileNames.text.let { it.ifEmpty { DEFAULT_SPRING_PROFILE_NAME } } - model.springTestsType = springTestsType.item + }?.let { + model.springSettings = + SpringSettings( + configuration = it, + profileExpression = profileNames.text.let { text -> text.ifEmpty { DEFAULT_SPRING_PROFILE_NAME } } + ) + } + + model.springTestType = springTestType.item val settings = model.project.service() with(settings) { @@ -876,10 +882,10 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m updateParametrizationEnabled() } ProjectType.Spring -> { - springTestsType.item = - if (isSpringConfigSelected()) settings.springTestsType else SpringTestsType.defaultItem + springTestType.item = + if (isSpringConfigSelected()) settings.springTestType else SpringTestType.defaultItem updateSpringSettings() - updateTestFrameworkList(settings.springTestsType) + updateTestFrameworkList(settings.springTestType) } ProjectType.Python, ProjectType.JavaScript -> { } @@ -938,7 +944,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } private fun configureSpringTestFrameworkIfRequired() { - if (springTestsType.item == INTEGRATION_TESTS) { + if (springTestType.item == INTEGRATION_TEST) { val framework = when { SpringBoot.isInstalled -> SpringBoot @@ -995,7 +1001,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.preCompilePromises += addDependency(model.testModule, libraryDescriptor) } - INTEGRATION_TESTS.frameworkInstalled = true + INTEGRATION_TEST.frameworkInstalled = true } private fun configureMockFramework() { @@ -1145,7 +1151,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m springTestsType.item = SpringTestsType.defaultItem } - if (springTestsType.item == UNIT_TESTS) { + if (springTestsType.item == UNIT_TEST) { mockStrategies.item = MockStrategyApi.springDefaultItem } } else { @@ -1162,17 +1168,17 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m updateControlsEnabledStatus() } - springTestsType.addActionListener { event -> + springTestType.addActionListener { event -> val comboBox = event.source as ComboBox<*> - val item = comboBox.item as SpringTestsType + val item = comboBox.item as SpringTestType updateTestFrameworkList(item) when (item) { - UNIT_TESTS -> { + UNIT_TEST -> { mockStrategies.item = MockStrategyApi.springDefaultItem } - INTEGRATION_TESTS -> { + INTEGRATION_TEST -> { mockStrategies.item = MockStrategyApi.springIntegrationTestItem } } @@ -1207,11 +1213,11 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m updateTestFrameworkList(enabledTestFrameworks, defaultItem) } - private fun updateTestFrameworkList(springTestsType: SpringTestsType) { + private fun updateTestFrameworkList(springTestType: SpringTestType) { // We do not support Spring integration tests for TestNg - val enabledTestFrameworks = when (springTestsType) { - UNIT_TESTS -> TestFramework.allItems - INTEGRATION_TESTS -> TestFramework.allItems.filterNot { it == TestNg } + val enabledTestFrameworks = when (springTestType) { + UNIT_TEST -> TestFramework.allItems + INTEGRATION_TEST -> TestFramework.allItems.filterNot { it == TestNg } } updateTestFrameworkList(enabledTestFrameworks) @@ -1274,13 +1280,13 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m // We check for > 1 because there is already extra-dummy NO_SPRING_CONFIGURATION_OPTION option springConfig.isEnabled = model.projectType == ProjectType.Spring && springConfig.itemCount > 1 - springTestsType.renderer = object : ColoredListCellRenderer() { + springTestType.renderer = object : ColoredListCellRenderer() { override fun customizeCellRenderer( - list: JList, value: SpringTestsType, + list: JList, value: SpringTestType, index: Int, selected: Boolean, hasFocus: Boolean ) { this.append(value.displayName, SimpleTextAttributes.REGULAR_ATTRIBUTES) - if (value == INTEGRATION_TESTS && !INTEGRATION_TESTS.frameworkInstalled) { + if (value == INTEGRATION_TEST && !INTEGRATION_TEST.frameworkInstalled) { val additionalText = when { SpringBoot.isInstalled -> " (spring-boot-test will be installed)" SpringBeans.isInstalled -> " (spring-test will be installed)" diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt index 1affc2c124..eba3618af9 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt @@ -33,7 +33,6 @@ object EngineProcessModel : Ext(EngineProcessRoot) { field("path", PredefinedType.string) field("version", PredefinedType.int) } - val testGeneratorParams = structdef { field("buildDir", array(PredefinedType.string)) field("classpath", PredefinedType.string.nullable) @@ -62,7 +61,6 @@ object EngineProcessModel : Ext(EngineProcessRoot) { field("testSetsId", PredefinedType.long) } val renderParams = structdef { - field("springTestsType", PredefinedType.string) field("testSetsId", PredefinedType.long) field("classUnderTest", array(PredefinedType.byte)) field("projectType", PredefinedType.string) @@ -79,6 +77,7 @@ object EngineProcessModel : Ext(EngineProcessRoot) { field("hangingTestsTimeout", PredefinedType.long) field("enableTestsTimeout", PredefinedType.bool) field("testClassPackageName", PredefinedType.string) + field("codeGenerationContext", array(PredefinedType.byte)) } val renderResult = structdef { field("generatedCode", PredefinedType.string) @@ -89,9 +88,9 @@ object EngineProcessModel : Ext(EngineProcessRoot) { } val getSpringBeanDefinitions = structdef { field("classpath", array(PredefinedType.string)) - field("config", PredefinedType.string) + field("configuration", array(PredefinedType.byte)) field("fileStorage", array(PredefinedType.string)) - field("profileExpression", PredefinedType.string.nullable) + field("profileExpression", PredefinedType.string.nullable) // TODO: why nullable? } val methodDescription = structdef { field("name", PredefinedType.string) diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt index 02bdc5321e..7c23f14be1 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt @@ -7,7 +7,7 @@ object SpringAnalyzerRoot : Root() object SpringAnalyzerProcessModel : Ext(SpringAnalyzerRoot) { val springAnalyzerParams = structdef { - field("configuration", PredefinedType.string) + field("configuration", array(PredefinedType.byte)) field("fileStorage", array(PredefinedType.string)) field("profileExpression", PredefinedType.string.nullable) } diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt index a2423019b2..2ba1c63dcd 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt @@ -1,9 +1,10 @@ package org.utbot.spring.api +import org.utbot.framework.plugin.api.SpringConfiguration import java.net.URL class ApplicationData( - val configurationFile: String, + val configurationFile: SpringConfiguration, val fileStorage: List, val profileExpression: String?, ) diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt index 324bbe5055..825bbaeffe 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt @@ -50,7 +50,7 @@ class SpringAnalyzerProcessModel private constructor( } - const val serializationHash = 8934866731594302609L + const val serializationHash = -6862945874536334699L } override val serializersOwner: ISerializersOwner get() = SpringAnalyzerProcessModel @@ -224,7 +224,7 @@ data class BeanDefinitionData ( printer.println("BeanDefinitionData (") printer.indent { print("beanName = "); beanName.print(printer); println() - print("beanTypeName = "); beanTypeFqn.print(printer); println() + print("beanTypeFqn = "); beanTypeFqn.print(printer); println() print("additionalData = "); additionalData.print(printer); println() } printer.print(")") @@ -238,7 +238,7 @@ data class BeanDefinitionData ( * #### Generated from [SpringAnalyzerModel.kt:9] */ data class SpringAnalyzerParams ( - val configuration: String, + val configuration: ByteArray, val fileStorage: Array, val profileExpression: String? ) : IPrintable { @@ -249,14 +249,14 @@ data class SpringAnalyzerParams ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): SpringAnalyzerParams { - val configuration = buffer.readString() + val configuration = buffer.readByteArray() val fileStorage = buffer.readArray {buffer.readString()} val profileExpression = buffer.readNullable { buffer.readString() } return SpringAnalyzerParams(configuration, fileStorage, profileExpression) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: SpringAnalyzerParams) { - buffer.writeString(value.configuration) + buffer.writeByteArray(value.configuration) buffer.writeArray(value.fileStorage) { buffer.writeString(it) } buffer.writeNullable(value.profileExpression) { buffer.writeString(it) } } @@ -274,7 +274,7 @@ data class SpringAnalyzerParams ( other as SpringAnalyzerParams - if (configuration != other.configuration) return false + if (!(configuration contentEquals other.configuration)) return false if (!(fileStorage contentDeepEquals other.fileStorage)) return false if (profileExpression != other.profileExpression) return false @@ -283,7 +283,7 @@ data class SpringAnalyzerParams ( //hash code trait override fun hashCode(): Int { var __r = 0 - __r = __r*31 + configuration.hashCode() + __r = __r*31 + configuration.contentHashCode() __r = __r*31 + fileStorage.contentDeepHashCode() __r = __r*31 + if (profileExpression != null) profileExpression.hashCode() else 0 return __r diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt index 7c5bc6ff03..9bd5e92a7f 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt @@ -88,7 +88,7 @@ class SpringAnalyzerProcess private constructor( private val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel } fun getBeanDefinitions( - configuration: String, + configuration: ByteArray, fileStorage: Array, profileExpression: String?, ): SpringAnalyzerResult { diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt index 2475780f42..37c17bf365 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt @@ -7,6 +7,7 @@ import com.jetbrains.rd.util.info import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.reactive.adviseOnce import org.utbot.common.AbstractSettings +import org.utbot.framework.process.kryo.KryoHelper import org.utbot.rd.ClientProtocolBuilder import org.utbot.rd.IdleWatchdog import org.utbot.rd.RdSettingsContainerFactory @@ -40,9 +41,11 @@ suspend fun main(args: Array) = } private fun SpringAnalyzerProcessModel.setup(watchdog: IdleWatchdog, realProtocol: IProtocol) { + val kryoHelper = KryoHelper(realProtocol.lifetime) + watchdog.measureTimeForActiveCall(analyze, "Analyzing Spring Application") { params -> val applicationData = ApplicationData( - params.configuration, + kryoHelper.readObject(params.configuration), params.fileStorage.map { File(it).toURI().toURL() }, params.profileExpression, ) diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt index a9601e6d6b..9c865f615a 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt @@ -7,7 +7,6 @@ import org.utbot.common.patchAnnotation import org.utbot.spring.api.ApplicationData import org.utbot.spring.config.TestApplicationConfiguration import org.utbot.spring.configurators.ApplicationConfigurationType -import java.io.File import java.nio.file.Path import kotlin.io.path.Path @@ -18,29 +17,24 @@ class SourceFinder( ) { private val classLoader: ClassLoader = this::class.java.classLoader - fun findSources(): Array> = when (configurationType) { - ApplicationConfigurationType.XmlConfiguration -> { - logger.info { "Using xml Spring configuration" } + fun findSources(): Array> = + when (val config = applicationData.configurationFile) { + is SpringConfiguration.JavaConfiguration -> { + logger.info { "Using java Spring configuration" } + arrayOf( + TestApplicationConfiguration::class.java, + classLoader.loadClass(config.classBinaryName) + ) + } - // Put `applicationData.configurationFile` in `@ImportResource` of `TestApplicationConfiguration` - patchImportResourceAnnotation(Path(applicationData.configurationFile).fileName) + is SpringConfiguration.XMLConfiguration -> { + logger.info { "Using xml Spring configuration" } - arrayOf(TestApplicationConfiguration::class.java) - } - - ApplicationConfigurationType.JavaConfiguration -> { - logger.info { "Using java Spring configuration" } - arrayOf( - TestApplicationConfiguration::class.java, - classLoader.loadClass(applicationData.configurationFile) - ) - } - } + // Put `applicationData.configurationFile` in `@ImportResource` of `TestApplicationConfiguration` + patchImportResourceAnnotation(Path(config.absolutePath).fileName) - private val configurationType: ApplicationConfigurationType - get() = when (File(applicationData.configurationFile).extension) { - "xml" -> ApplicationConfigurationType.XmlConfiguration - else -> ApplicationConfigurationType.JavaConfiguration + arrayOf(TestApplicationConfiguration::class.java) + } } private fun patchImportResourceAnnotation(userXmlFilePath: Path) = 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 3f34246e8e..4f8d9573bc 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 @@ -37,7 +37,7 @@ import kotlin.reflect.KClass import org.utbot.common.isWindows import org.utbot.framework.SummariesGenerationType import org.utbot.framework.codegen.domain.UnknownTestFramework -import org.utbot.framework.plugin.api.SpringTestsType +import org.utbot.framework.plugin.api.SpringTestType import org.utbot.framework.plugin.api.isSummarizationCompatible @State( @@ -63,7 +63,7 @@ class Settings(val project: Project) : PersistentStateComponent var treatOverflowAsError: TreatOverflowAsError = TreatOverflowAsError.defaultItem, var parametrizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem, var classesToMockAlways: Array = Mocker.defaultSuperClassesToMockAlwaysNames.toTypedArray(), - var springTestsType: SpringTestsType = SpringTestsType.defaultItem, + var springTestType: SpringTestType = SpringTestType.defaultItem, var fuzzingValue: Double = 0.05, var runGeneratedTestsWithCoverage: Boolean = false, var commentStyle: JavaDocCommentStyle = JavaDocCommentStyle.defaultItem, @@ -92,7 +92,7 @@ class Settings(val project: Project) : PersistentStateComponent if (treatOverflowAsError != other.treatOverflowAsError) return false if (parametrizedTestSource != other.parametrizedTestSource) return false if (!classesToMockAlways.contentEquals(other.classesToMockAlways)) return false - if (springTestsType != other.springTestsType) return false + if (springTestType != other.springTestType) return false if (fuzzingValue != other.fuzzingValue) return false if (runGeneratedTestsWithCoverage != other.runGeneratedTestsWithCoverage) return false if (commentStyle != other.commentStyle) return false @@ -116,7 +116,7 @@ class Settings(val project: Project) : PersistentStateComponent result = 31 * result + treatOverflowAsError.hashCode() result = 31 * result + parametrizedTestSource.hashCode() result = 31 * result + classesToMockAlways.contentHashCode() - result = 31 * result + springTestsType.hashCode() + result = 31 * result + springTestType.hashCode() result = 31 * result + fuzzingValue.hashCode() result = 31 * result + if (runGeneratedTestsWithCoverage) 1 else 0 result = 31 * result + summariesGenerationType.hashCode() @@ -165,7 +165,7 @@ class Settings(val project: Project) : PersistentStateComponent val classesToMockAlways: Set get() = state.classesToMockAlways.toSet() - val springTestsType: SpringTestsType get() = state.springTestsType + val springTestType: SpringTestType get() = state.springTestType val javaDocCommentStyle: JavaDocCommentStyle get() = state.commentStyle From 7c86f3db9d30c8f1d9b1c759044a9ae0cc303611 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Wed, 5 Jul 2023 20:09:53 +0300 Subject: [PATCH 4/8] Replace PsiClassHelper.kt --- .../generator/UtTestsDialogProcessor.kt | 4 ++-- .../intellij/plugin/models/BaseTestModel.kt | 2 +- .../intellij/plugin/util/PsiClassHelper.kt | 20 ++++++++++++++++ .../intellij/plugin/util/PsiClassUtil.kt | 23 ------------------- 4 files changed, 23 insertions(+), 26 deletions(-) rename {utbot-intellij => utbot-ui-commons}/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt (84%) delete mode 100644 utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt 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 ef1548c215..22de1e0be4 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 @@ -241,7 +241,7 @@ object UtTestsDialogProcessor { val totalClasses = model.srcClasses.size val classNameToPath = runReadAction { model.srcClasses.associate { psiClass -> - psiClass.binaryName() to psiClass.containingFile.virtualFile.canonicalPath + psiClass.binaryName to psiClass.containingFile.virtualFile.canonicalPath } } @@ -320,7 +320,7 @@ object UtTestsDialogProcessor { var srcNameForLog: String? = null DumbService.getInstance(project) .runReadActionInSmartMode(Computable { - binaryName = srcClass.binaryName() + binaryName = srcClass.binaryName srcNameForLog = srcClass.name srcMethods = if (model.extractMembersFromSrcClasses) { val chosenMethods = 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 20b3f9b5d8..321a2af4e9 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 @@ -134,7 +134,7 @@ open class BaseTestsModel( .searchPsiClasses(annotationClass, searchScope) .findAll() .sortedBy { testRootToIndex[it.containingFile.sourceRoot] ?: Int.MAX_VALUE } - .mapNotNullTo(mutableSetOf()) { it.binaryName() } + .mapNotNullTo(mutableSetOf()) { it.binaryName } } fun getSpringXMLConfigurationFiles(): Set { diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt similarity index 84% rename from utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt rename to utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt index 83ad3a1a5f..7cf10ef1f8 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt @@ -17,6 +17,26 @@ import org.jetbrains.kotlin.asJava.elements.isSetter import org.jetbrains.kotlin.psi.KtClass import org.utbot.common.filterWhen import org.utbot.framework.UtSettings +import org.utbot.intellij.plugin.models.packageName + +/** + * Used to build binary name from canonical name + * in a similar form which could be obtained by [java.lang.Class.getName] method. + * + * E.g. ```org.example.OuterClass.InnerClass.InnerInnerClass``` -> ```org.example.OuterClass$InnerClass$InnerInnerClass``` + */ +val PsiClass.binaryName: String + get() = + if (packageName.isEmpty()) { + qualifiedName?.replace(".", "$") ?: "" + } else { + val name = + qualifiedName + ?.substringAfter("$packageName.") + ?.replace(".", "$") + ?: error("Binary name construction failed: unable to get qualified name of $this") + "$packageName.$name" + } val PsiMember.isAbstract: Boolean get() = modifierList?.hasModifierProperty(PsiModifier.ABSTRACT)?: false diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt deleted file mode 100644 index 973d88596e..0000000000 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassUtil.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.utbot.intellij.plugin.util - -import com.intellij.psi.PsiClass -import org.utbot.intellij.plugin.models.packageName - - -/** - * Used to build binary name from canonical name - * in a similar form which could be obtained by [java.lang.Class.getName] method. - * - * E.g. ```org.example.OuterClass.InnerClass.InnerInnerClass``` -> ```org.example.OuterClass$InnerClass$InnerInnerClass``` - */ -fun PsiClass.binaryName(): String = - if (packageName.isEmpty()) { - qualifiedName?.replace(".", "$") ?: "" - } else { - val name = - qualifiedName - ?.substringAfter("$packageName.") - ?.replace(".", "$") - ?: error("Binary name construction failed: unable to get qualified name of $this") - "$packageName.$name" - } From 33093e5239bacb1cc223ac3ad8e1e9b49b6938df Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Wed, 5 Jul 2023 20:44:19 +0300 Subject: [PATCH 5/8] Apply comment suggestions --- .../plugin/generator/UtTestsDialogProcessor.kt | 12 ++++-------- .../plugin/util/SpringConfigurationsHelper.kt | 5 +++-- .../utbot/intellij/plugin/util/PsiClassHelper.kt | 14 +++++++++++--- 3 files changed, 18 insertions(+), 13 deletions(-) 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 22de1e0be4..8f32df94db 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 @@ -177,11 +177,9 @@ object UtTestsDialogProcessor { val springConfigClass = when (val config = model.springSettings?.configuration) { is JavaConfiguration -> { - // Converting binary name to fqn name - val fqnName = config.classBinaryName.replace("$", ".") PsiClassHelper - .findClass(fqnName, project) - ?: error("Cannot find configuration class $fqnName.") + .findClass(config.classBinaryName, project) + ?: error("Cannot find configuration class ${config.classBinaryName}.") } else -> null @@ -479,14 +477,12 @@ object UtTestsDialogProcessor { val beanType = runReadAction { val additionalData = bean.additionalData ?: return@runReadAction null - // Converting binary name to fqn name - val fqnName = additionalData.configClassName.replace("$", ".") val configPsiClass = PsiClassHelper - .findClass(fqnName, project) + .findClass(additionalData.configClassName, project) ?: return@runReadAction null .also { - logger.warn("Cannot find configuration class ${additionalData.configClassName} with $fqnName name.") + logger.warn("Cannot find configuration class ${additionalData.configClassName}.") } val beanPsiMethod = diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt index ba9981ae4d..c952295602 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt @@ -42,7 +42,7 @@ class SpringConfigurationsHelper(val configType: SpringConfigurationType) { .values .singleOrNull { it.shortenedName == shortenedName } ?.fullName - ?: error("Full name of configuration file cannot be restored with shortened name $shortenedName") + ?: error("Full name of configuration file cannot be restored from shortened name $shortenedName") fun shortenSpringConfigNames(fullNames: Set): Map { fullNames.forEach { nameToInfo[it] = NameInfo(it) } @@ -92,12 +92,13 @@ class SpringConfigurationsHelper(val configType: SpringConfigurationType) { } +@Deprecated("To be deleted") enum class SpringConfigurationType( val separatorsToSplitBy: Array, val separatorToConcatenateBy: String, ) { ClassConfiguration( - separatorsToSplitBy = arrayOf(".", "$"), + separatorsToSplitBy = arrayOf("."), separatorToConcatenateBy = ".", ), diff --git a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt index 7cf10ef1f8..26cd770797 100644 --- a/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt +++ b/utbot-ui-commons/src/main/kotlin/org/utbot/intellij/plugin/util/PsiClassHelper.kt @@ -109,8 +109,16 @@ val PsiClass.isVisible: Boolean get() = generateSequence(this) { it.containingClass }.none { it.isPrivateOrProtected } object PsiClassHelper { - fun findClass(name: String, project: Project): PsiClass? = - JavaPsiFacade + /** + * Finds [PsiClass]. + * + * @param name binary name which is converted to canonical name. + */ + fun findClass(name: String, project: Project): PsiClass? { + // Converting name to canonical name + val canonicalName = name.replace("$", ".") + return JavaPsiFacade .getInstance(project) - .findClass(name, GlobalSearchScope.projectScope(project)) + .findClass(canonicalName, GlobalSearchScope.projectScope(project)) + } } \ No newline at end of file From b91f0d01a089a1b9397cbf026d438d66a20802a6 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:12:39 +0300 Subject: [PATCH 6/8] Refactoring --- .../org/utbot/framework/plugin/api/Api.kt | 18 +++-- .../plugin/api/util/UtSettingsUtil.kt | 2 +- .../org/utbot/engine/UtBotSymbolicEngine.kt | 3 +- .../codegen/generator/SpringCodeGenerator.kt | 8 ++- ...CgSpringIntegrationTestClassConstructor.kt | 10 +-- .../framework/plugin/api/TestCaseGenerator.kt | 14 ++-- .../framework/process/EngineProcessMain.kt | 9 +-- .../generated/EngineProcessModel.Generated.kt | 66 +++++++------------ .../SpringUtExecutionInstrumentation.kt | 6 +- .../context/SpringInstrumentationContext.kt | 14 +++- .../generator/CodeGenerationController.kt | 1 - .../generator/UtTestsDialogProcessor.kt | 51 ++++++-------- .../plugin/models/GenerateTestsModel.kt | 5 +- .../intellij/plugin/process/EngineProcess.kt | 13 +--- .../plugin/ui/GenerateTestsDialogWindow.kt | 55 +++++++--------- .../plugin/util/SpringConfigurationsHelper.kt | 17 +++++ .../org/utbot/rd/models/EngineProcessModel.kt | 5 +- .../utbot/rd/models/SpringAnalyzerModel.kt | 4 +- .../analyzer/SpringApplicationAnalyzer.kt | 3 +- .../org/utbot/spring/api/ApplicationData.kt | 7 +- .../SpringAnalyzerProcessModel.Generated.kt | 34 ++++------ .../spring/process/SpringAnalyzerProcess.kt | 6 +- .../process/SpringAnalyzerProcessMain.kt | 4 +- .../org/utbot/spring/utils/SourceFinder.kt | 7 +- .../spring/api/context/ContextWrapper.kt | 0 .../api/instantiator/InstantiationSettings.kt | 2 +- .../kotlin/org/utbot/spring/SpringApiImpl.kt | 19 +----- .../spring/environment/EnvironmentFactory.kt | 0 28 files changed, 167 insertions(+), 216 deletions(-) create mode 100644 utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt create mode 100644 utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 20ee5a2104..aa7b10a8ba 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1327,7 +1327,7 @@ interface CodeGenerationContext interface SpringCodeGenerationContext : CodeGenerationContext { val springTestType: SpringTestType - val springSettings: SpringSettings? + val springSettings: SpringSettings } /** @@ -1396,10 +1396,16 @@ sealed interface SpringConfiguration { class XMLConfiguration(val absolutePath: String) : SpringConfiguration } -class SpringSettings( - val configuration: SpringConfiguration, - val profileExpression: String -) +sealed interface SpringSettings { + class AbsentSpringSettings : SpringSettings { + // Denotes no configuration and no profile setting + } + + class PresentSpringSettings( + val configuration: SpringConfiguration, + val profiles: Array + ) : SpringSettings +} /** * Data we get from Spring application context @@ -1423,7 +1429,7 @@ class SpringApplicationContext( val beanDefinitions: List = emptyList(), private val shouldUseImplementors: Boolean, override val springTestType: SpringTestType, - override val springSettings: SpringSettings?, + override val springSettings: SpringSettings, ): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext { companion object { diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/UtSettingsUtil.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/UtSettingsUtil.kt index 2c3117d81d..a0585ca383 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/UtSettingsUtil.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/UtSettingsUtil.kt @@ -14,4 +14,4 @@ inline fun withStaticsSubstitutionRequired(condition: Boolean, block: () -> } finally { UtSettings.substituteStaticsWithSymbolicVariable = standardSubstitutionSetting } -} \ No newline at end of file +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 0715126fbb..d84e80a123 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -39,6 +39,7 @@ import org.utbot.framework.plugin.api.util.* import org.utbot.framework.util.convertToAssemble import org.utbot.framework.util.graph import org.utbot.framework.util.sootMethod +import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.fuzzer.* import org.utbot.fuzzing.* import org.utbot.fuzzing.providers.FieldValueProvider @@ -388,7 +389,7 @@ class UtBotSymbolicEngine( var testEmittedByFuzzer = 0 val valueProviders = ValueProvider.of(defaultValueProviders(defaultIdGenerator)) .letIf(applicationContext is SpringApplicationContext - && applicationContext.springSettings != null + && applicationContext.springSettings is PresentSpringSettings ) { provider -> val relevantRepositories = concreteExecutor.getRelevantSpringRepositories(methodUnderTest.classId) logger.info { "Detected relevant repositories for class ${methodUnderTest.classId}: $relevantRepositories" } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt index 5e4aaa3b0b..3dbcedf3b7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/SpringCodeGenerator.kt @@ -19,6 +19,7 @@ import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.MockFramework import org.utbot.framework.plugin.api.SpringTestType import org.utbot.framework.plugin.api.SpringCodeGenerationContext +import org.utbot.framework.plugin.api.SpringSettings.* class SpringCodeGenerator( val classUnderTest: ClassId, @@ -63,9 +64,10 @@ class SpringCodeGenerator( val astConstructor = when (codeGenerationContext.springTestType) { SpringTestType.UNIT_TEST -> CgSpringUnitTestClassConstructor(context) SpringTestType.INTEGRATION_TEST -> - codeGenerationContext.springSettings - ?.let { CgSpringIntegrationTestClassConstructor(context, it) } - ?: error("Error text.") + when (val settings = codeGenerationContext.springSettings) { + is PresentSpringSettings -> CgSpringIntegrationTestClassConstructor(context, settings) + is AbsentSpringSettings -> error("No Spring settings were provided for Spring integration test generation.") + } } val testClassFile = astConstructor.construct(testClassModel) logger.info { "Code generation phase finished at ${now()}" } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt index 2038688469..5ec31e5ccb 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt @@ -8,8 +8,8 @@ import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.* import org.utbot.framework.codegen.domain.models.AnnotationTarget.* import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.SpringConfiguration -import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.SpringSettings.* +import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.framework.plugin.api.util.SpringModelUtils import org.utbot.framework.plugin.api.util.SpringModelUtils.activeProfilesClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.autoConfigureTestDbClassId @@ -25,7 +25,7 @@ import org.utbot.framework.plugin.api.util.utContext class CgSpringIntegrationTestClassConstructor( context: CgContext, - private val springSettings: SpringSettings + private val springSettings: PresentSpringSettings ) : CgAbstractSpringTestClassConstructor(context) { override fun constructTestClass(testClassModel: SpringTestClassModel): CgClass { addNecessarySpringSpecificAnnotations() @@ -61,12 +61,12 @@ class CgSpringIntegrationTestClassConstructor( ) addAnnotation( classId = activeProfilesClassId, - argument = springSettings.profileExpression, // TODO: separate by comma + argument = springSettings.profiles.first(), // TODO: andrey target = Class, ) addAnnotation( classId = contextConfigurationClassId, - argument = (springSettings.configuration as SpringConfiguration.JavaConfiguration).classBinaryName, // TODO: unpacking + argument = (springSettings.configuration as JavaConfiguration).classBinaryName, // TODO: andrey target = Class, ) addAnnotation( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt index 090cb66666..e7e2e5a65c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt @@ -34,6 +34,8 @@ import org.utbot.framework.util.ConflictTriggers import org.utbot.framework.util.SootUtils import org.utbot.framework.util.jimpleBody import org.utbot.framework.util.toModel +import org.utbot.framework.plugin.api.SpringSettings.* +import org.utbot.framework.plugin.api.SpringTestType.* import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.instrumentation.execution.SpringUtExecutionInstrumentation import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation @@ -69,13 +71,13 @@ open class TestCaseGenerator( private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout") private val executionInstrumentation by lazy { when (applicationContext) { - is SpringApplicationContext -> when (val springSettings = applicationContext.springSettings) { - null -> UtExecutionInstrumentation - else -> when (applicationContext.springTestType) { - SpringTestType.UNIT_TEST -> UtExecutionInstrumentation - SpringTestType.INTEGRATION_TEST -> SpringUtExecutionInstrumentation( + is SpringApplicationContext -> when (val settings = applicationContext.springSettings) { + is AbsentSpringSettings -> UtExecutionInstrumentation + is PresentSpringSettings -> when (applicationContext.springTestType) { + UNIT_TEST -> UtExecutionInstrumentation + INTEGRATION_TEST -> SpringUtExecutionInstrumentation( UtExecutionInstrumentation, - springSettings, + settings, applicationContext.beanDefinitions, buildDirs.map { it.toURL() }.toTypedArray(), ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt index 0863807662..8059ddeb3d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt @@ -83,9 +83,7 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch val springAnalyzerProcess = SpringAnalyzerProcess.createBlocking(params.classpath.toList()) val result = springAnalyzerProcess.terminateOnException { _ -> springAnalyzerProcess.getBeanDefinitions( - params.configuration, - params.fileStorage, - params.profileExpression, + params.springSettings ) } springAnalyzerProcess.terminate() @@ -152,7 +150,7 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch } } watchdog.measureTimeForActiveCall(render, "Rendering tests") { params -> - val codeGenerator = createCodeGenerator(kryoHelper, params) + val codeGenerator = createCodeGenerator(kryoHelper, params, testGenerator.applicationContext) codeGenerator.generateAsStringWithTestReport(testSets[params.testSetsId]!!).let { testGenerationReports.add(it.testsGenerationReport) @@ -291,7 +289,7 @@ private fun destinationWarningMessage(testPackageName: String?, classUnderTestPa } } -private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams): AbstractCodeGenerator { +private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, codeGenerationContext: CodeGenerationContext): AbstractCodeGenerator { with(params) { val classUnderTest: ClassId = kryoHelper.readObject(classUnderTest) val paramNames: MutableMap> = kryoHelper.readObject(paramNames) @@ -299,7 +297,6 @@ private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams): A val staticMocking = if (staticsMocking.startsWith("No")) NoStaticMocking else MockitoStaticMocking val forceStaticMocking: ForceStaticMocking = kryoHelper.readObject(forceStaticMocking) val projectType = ProjectType.valueOf(projectType) - val codeGenerationContext: CodeGenerationContext = kryoHelper.readObject(codeGenerationContext) return when (codeGenerationContext) { is SpringCodeGenerationContext -> { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt index 915e4aad46..d98a214ce0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt @@ -75,7 +75,7 @@ class EngineProcessModel private constructor( } - const val serializationHash = -1921561018844578859L + const val serializationHash = -3702497121699333502L } override val serializersOwner: ISerializersOwner get() = EngineProcessModel @@ -182,7 +182,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel /** - * #### Generated from [EngineProcessModel.kt:133] + * #### Generated from [EngineProcessModel.kt:130] */ data class BeanAdditionalData ( val factoryMethodName: String, @@ -251,7 +251,7 @@ data class BeanAdditionalData ( /** - * #### Generated from [EngineProcessModel.kt:138] + * #### Generated from [EngineProcessModel.kt:135] */ data class BeanDefinitionData ( val beanName: String, @@ -320,7 +320,7 @@ data class BeanDefinitionData ( /** - * #### Generated from [EngineProcessModel.kt:107] + * #### Generated from [EngineProcessModel.kt:104] */ data class FindMethodParamNamesArguments ( val classId: ByteArray, @@ -383,7 +383,7 @@ data class FindMethodParamNamesArguments ( /** - * #### Generated from [EngineProcessModel.kt:111] + * #### Generated from [EngineProcessModel.kt:108] */ data class FindMethodParamNamesResult ( val paramNames: ByteArray @@ -440,7 +440,7 @@ data class FindMethodParamNamesResult ( /** - * #### Generated from [EngineProcessModel.kt:100] + * #### Generated from [EngineProcessModel.kt:97] */ data class FindMethodsInClassMatchingSelectedArguments ( val classId: ByteArray, @@ -503,7 +503,7 @@ data class FindMethodsInClassMatchingSelectedArguments ( /** - * #### Generated from [EngineProcessModel.kt:104] + * #### Generated from [EngineProcessModel.kt:101] */ data class FindMethodsInClassMatchingSelectedResult ( val executableIds: ByteArray @@ -734,7 +734,7 @@ data class GenerateResult ( /** - * #### Generated from [EngineProcessModel.kt:119] + * #### Generated from [EngineProcessModel.kt:116] */ data class GenerateTestReportArgs ( val eventLogMessage: String?, @@ -827,7 +827,7 @@ data class GenerateTestReportArgs ( /** - * #### Generated from [EngineProcessModel.kt:128] + * #### Generated from [EngineProcessModel.kt:125] */ data class GenerateTestReportResult ( val notifyMessage: String, @@ -896,13 +896,11 @@ data class GenerateTestReportResult ( /** - * #### Generated from [EngineProcessModel.kt:89] + * #### Generated from [EngineProcessModel.kt:88] */ data class GetSpringBeanDefinitions ( val classpath: Array, - val configuration: ByteArray, - val fileStorage: Array, - val profileExpression: String? + val springSettings: ByteArray ) : IPrintable { //companion @@ -912,17 +910,13 @@ data class GetSpringBeanDefinitions ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): GetSpringBeanDefinitions { val classpath = buffer.readArray {buffer.readString()} - val configuration = buffer.readByteArray() - val fileStorage = buffer.readArray {buffer.readString()} - val profileExpression = buffer.readNullable { buffer.readString() } - return GetSpringBeanDefinitions(classpath, configuration, fileStorage, profileExpression) + val springSettings = buffer.readByteArray() + return GetSpringBeanDefinitions(classpath, springSettings) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: GetSpringBeanDefinitions) { buffer.writeArray(value.classpath) { buffer.writeString(it) } - buffer.writeByteArray(value.configuration) - buffer.writeArray(value.fileStorage) { buffer.writeString(it) } - buffer.writeNullable(value.profileExpression) { buffer.writeString(it) } + buffer.writeByteArray(value.springSettings) } @@ -939,9 +933,7 @@ data class GetSpringBeanDefinitions ( other as GetSpringBeanDefinitions if (!(classpath contentDeepEquals other.classpath)) return false - if (!(configuration contentEquals other.configuration)) return false - if (!(fileStorage contentDeepEquals other.fileStorage)) return false - if (profileExpression != other.profileExpression) return false + if (!(springSettings contentEquals other.springSettings)) return false return true } @@ -949,9 +941,7 @@ data class GetSpringBeanDefinitions ( override fun hashCode(): Int { var __r = 0 __r = __r*31 + classpath.contentDeepHashCode() - __r = __r*31 + configuration.contentHashCode() - __r = __r*31 + fileStorage.contentDeepHashCode() - __r = __r*31 + if (profileExpression != null) profileExpression.hashCode() else 0 + __r = __r*31 + springSettings.contentHashCode() return __r } //pretty print @@ -959,9 +949,7 @@ data class GetSpringBeanDefinitions ( printer.println("GetSpringBeanDefinitions (") printer.indent { print("classpath = "); classpath.print(printer); println() - print("configuration = "); configuration.print(printer); println() - print("fileStorage = "); fileStorage.print(printer); println() - print("profileExpression = "); profileExpression.print(printer); println() + print("springSettings = "); springSettings.print(printer); println() } printer.print(")") } @@ -1034,7 +1022,7 @@ data class JdkInfo ( /** - * #### Generated from [EngineProcessModel.kt:95] + * #### Generated from [EngineProcessModel.kt:92] */ data class MethodDescription ( val name: String, @@ -1121,8 +1109,7 @@ data class RenderParams ( val runtimeExceptionTestsBehaviour: String, val hangingTestsTimeout: Long, val enableTestsTimeout: Boolean, - val testClassPackageName: String, - val codeGenerationContext: ByteArray + val testClassPackageName: String ) : IPrintable { //companion @@ -1147,8 +1134,7 @@ data class RenderParams ( val hangingTestsTimeout = buffer.readLong() val enableTestsTimeout = buffer.readBool() val testClassPackageName = buffer.readString() - val codeGenerationContext = buffer.readByteArray() - return RenderParams(testSetsId, classUnderTest, projectType, paramNames, generateUtilClassFile, testFramework, mockFramework, codegenLanguage, parameterizedTestSource, staticsMocking, forceStaticMocking, generateWarningsForStaticMocking, runtimeExceptionTestsBehaviour, hangingTestsTimeout, enableTestsTimeout, testClassPackageName, codeGenerationContext) + return RenderParams(testSetsId, classUnderTest, projectType, paramNames, generateUtilClassFile, testFramework, mockFramework, codegenLanguage, parameterizedTestSource, staticsMocking, forceStaticMocking, generateWarningsForStaticMocking, runtimeExceptionTestsBehaviour, hangingTestsTimeout, enableTestsTimeout, testClassPackageName) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: RenderParams) { @@ -1168,7 +1154,6 @@ data class RenderParams ( buffer.writeLong(value.hangingTestsTimeout) buffer.writeBool(value.enableTestsTimeout) buffer.writeString(value.testClassPackageName) - buffer.writeByteArray(value.codeGenerationContext) } @@ -1200,7 +1185,6 @@ data class RenderParams ( if (hangingTestsTimeout != other.hangingTestsTimeout) return false if (enableTestsTimeout != other.enableTestsTimeout) return false if (testClassPackageName != other.testClassPackageName) return false - if (!(codeGenerationContext contentEquals other.codeGenerationContext)) return false return true } @@ -1223,7 +1207,6 @@ data class RenderParams ( __r = __r*31 + hangingTestsTimeout.hashCode() __r = __r*31 + enableTestsTimeout.hashCode() __r = __r*31 + testClassPackageName.hashCode() - __r = __r*31 + codeGenerationContext.contentHashCode() return __r } //pretty print @@ -1246,7 +1229,6 @@ data class RenderParams ( print("hangingTestsTimeout = "); hangingTestsTimeout.print(printer); println() print("enableTestsTimeout = "); enableTestsTimeout.print(printer); println() print("testClassPackageName = "); testClassPackageName.print(printer); println() - print("codeGenerationContext = "); codeGenerationContext.print(printer); println() } printer.print(")") } @@ -1256,7 +1238,7 @@ data class RenderParams ( /** - * #### Generated from [EngineProcessModel.kt:82] + * #### Generated from [EngineProcessModel.kt:81] */ data class RenderResult ( val generatedCode: String, @@ -1319,7 +1301,7 @@ data class RenderResult ( /** - * #### Generated from [EngineProcessModel.kt:86] + * #### Generated from [EngineProcessModel.kt:85] */ data class SetupContextParams ( val classpathForUrlsClassloader: List @@ -1376,7 +1358,7 @@ data class SetupContextParams ( /** - * #### Generated from [EngineProcessModel.kt:143] + * #### Generated from [EngineProcessModel.kt:140] */ data class SpringAnalyzerResult ( val beanDefinitions: Array @@ -1514,7 +1496,7 @@ data class TestGeneratorParams ( /** - * #### Generated from [EngineProcessModel.kt:114] + * #### Generated from [EngineProcessModel.kt:111] */ data class WriteSarifReportArguments ( val testSetsId: Long, diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt index 9709220657..0e6df14e34 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt @@ -7,7 +7,7 @@ import org.utbot.common.hasOnClasspath import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringRepositoryId -import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.util.jClass import org.utbot.instrumentation.instrumentation.ArgumentList import org.utbot.instrumentation.instrumentation.Instrumentation @@ -24,7 +24,7 @@ import java.security.ProtectionDomain */ class SpringUtExecutionInstrumentation( private val delegateInstrumentation: UtExecutionInstrumentation, - private val springSettings: SpringSettings, + private val springSettings: PresentSpringSettings, private val beanDefinitions: List, private val buildDirs: Array, ) : Instrumentation by delegateInstrumentation { @@ -56,7 +56,7 @@ class SpringUtExecutionInstrumentation( ) userSourcesClassLoader = URLClassLoader(buildDirs, null) - instrumentationContext = SpringInstrumentationContext(springConfig, delegateInstrumentation.instrumentationContext) + instrumentationContext = SpringInstrumentationContext(springSettings, delegateInstrumentation.instrumentationContext) delegateInstrumentation.instrumentationContext = instrumentationContext delegateInstrumentation.init(pathsToUserClasses) springApi.beforeTestClass() diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SpringInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SpringInstrumentationContext.kt index 4ecac5fc69..4a6625949b 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SpringInstrumentationContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SpringInstrumentationContext.kt @@ -1,5 +1,7 @@ package org.utbot.instrumentation.instrumentation.execution.context +import org.utbot.framework.plugin.api.SpringSettings.* +import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtSpringContextModel @@ -9,7 +11,7 @@ import org.utbot.spring.api.instantiator.SpringApiProviderFacade import org.utbot.spring.api.instantiator.InstantiationSettings class SpringInstrumentationContext( - private val springConfig: String, + private val springSettings: PresentSpringSettings, private val delegateInstrumentationContext: InstrumentationContext, ) : InstrumentationContext by delegateInstrumentationContext { // TODO: recreate context/app every time whenever we change method under test @@ -19,9 +21,15 @@ class SpringInstrumentationContext( val instantiationSettings = InstantiationSettings( configurationClasses = arrayOf( - classLoader.loadClass(springConfig), + // TODO: for now we prohibit generating integration tests with XML configuration supplied, + // so we expect JavaConfigurations only. + // After fix rewrite the following. + classLoader.loadClass( + (springSettings.configuration as? JavaConfiguration)?.classBinaryName + ?: error("JavaConfiguration was expected, but ${springSettings.configuration.javaClass.name} was provided.") + ) ), - profileExpression = null, // TODO pass profile expression here + profiles = springSettings.profiles, ) SpringApiProviderFacade 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 f4dcca809b..9399ae1279 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 @@ -695,7 +695,6 @@ object CodeGenerationController { generateUtilClassFile = true, enableTestsTimeout = true, testPackageName, - codeGenerationContext ) } catch (e: Exception) { logger.warn(e) { "Cannot render test class ${testClass.name}" } 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 8f32df94db..14fbe938c6 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 @@ -49,13 +49,10 @@ import org.utbot.framework.CancellationStrategyType.NONE import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS import org.utbot.framework.UtSettings import org.utbot.framework.codegen.domain.ProjectType.* -import org.utbot.framework.plugin.api.ApplicationContext +import org.utbot.framework.plugin.api.* +import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.framework.plugin.api.SpringTestType.* -import org.utbot.framework.plugin.api.BeanDefinitionData -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.JavaDocCommentStyle -import org.utbot.framework.plugin.api.SpringApplicationContext import org.utbot.framework.plugin.api.util.LockFile import org.utbot.framework.plugin.api.util.withStaticsSubstitutionRequired import org.utbot.framework.plugin.services.JdkInfoService @@ -175,14 +172,19 @@ object UtTestsDialogProcessor { private fun createTests(project: Project, model: GenerateTestsModel) { val springConfigClass = - when (val config = model.springSettings?.configuration) { - is JavaConfiguration -> { - PsiClassHelper - .findClass(config.classBinaryName, project) - ?: error("Cannot find configuration class ${config.classBinaryName}.") - } - - else -> null + when (val settings = model.springSettings) { + is AbsentSpringSettings -> null + is PresentSpringSettings -> + when (val config = settings.configuration) { + is JavaConfiguration -> { + PsiClassHelper + .findClass(config.classBinaryName, project) + ?: error("Cannot find configuration class ${config.classBinaryName}.") + } + // TODO: for XML config we also need to compile module containing, + // since it may reference classes from that module + is XMLConfiguration -> null + } } val filesToCompile = (model.srcClasses + listOfNotNull(springConfigClass)) @@ -254,27 +256,16 @@ object UtTestsDialogProcessor { val applicationContext = when (model.projectType) { Spring -> { val beanDefinitions = - when (val approach = model.springSettings) { - null -> emptyList() - else -> { - val contentRoots = runReadAction { - listOfNotNull( - model.srcModule, - springConfigClass?.module - ).distinct().flatMap { module -> - ModuleRootManager.getInstance(module).contentRoots.toList() - } - } - - val fileStorage = contentRoots.map { root -> root.url }.toTypedArray() + when (val settings = model.springSettings) { + is AbsentSpringSettings -> emptyList() + is PresentSpringSettings -> { process.getSpringBeanDefinitions( classpathForClassLoader, - approach.configuration, - approach.profileExpression, - fileStorage, + settings ) } } + val shouldUseImplementors = beanDefinitions.isNotEmpty() val clarifiedBeanDefinitions = @@ -387,7 +378,7 @@ object UtTestsDialogProcessor { } val useFuzzing = when (model.projectType) { Spring -> when (model.springTestType) { - UNIT_TEST -> model.springSettings == null + UNIT_TEST -> model.springSettings is AbsentSpringSettings INTEGRATION_TEST -> true } 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 c8ea64cdd7..a7df31e701 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 @@ -59,10 +59,7 @@ class GenerateTestsModel( lateinit var chosenClassesToMockAlways: Set lateinit var commentStyle: JavaDocCommentStyle - /** - * TODO: Null when there is no configuration provided. - */ - var springSettings: SpringSettings? = null + lateinit var springSettings: SpringSettings val conflictTriggers: ConflictTriggers = ConflictTriggers() val preCompilePromises: MutableList> = mutableListOf() diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt index 9cf157b446..b6fdbf62a2 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt @@ -13,6 +13,7 @@ import com.jetbrains.rd.util.ConcurrentHashMap import com.jetbrains.rd.util.lifetime.LifetimeDefinition import kotlinx.coroutines.runBlocking import mu.KotlinLogging +import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.common.* import org.utbot.framework.UtSettings import org.utbot.framework.codegen.tree.ututils.UtilClassKind @@ -144,17 +145,13 @@ class EngineProcess private constructor(val project: Project, private val classN fun getSpringBeanDefinitions( classpathList: List, - configuration: SpringConfiguration, - profileExpression: String?, - fileStorage: Array, + springSettings: PresentSpringSettings ): List { assertReadAccessNotAllowed() val result = engineModel.getSpringBeanDefinitions.startBlocking( GetSpringBeanDefinitions( classpathList.toTypedArray(), - kryoHelper.writeObject(configuration), - fileStorage, - profileExpression + kryoHelper.writeObject(springSettings) ) ) return result.beanDefinitions @@ -292,7 +289,6 @@ class EngineProcess private constructor(val project: Project, private val classN generateUtilClassFile: Boolean, enableTestsTimeout: Boolean, testClassPackageName: String, - codeGenerationContext: CodeGenerationContext, ): Pair { assertReadAccessNotAllowed() val params = makeParams( @@ -303,7 +299,6 @@ class EngineProcess private constructor(val project: Project, private val classN generateUtilClassFile, enableTestsTimeout, testClassPackageName, - codeGenerationContext, ) val result = engineModel.render.startBlocking(params) val realUtilClassKind = result.utilClassKind?.let { @@ -324,7 +319,6 @@ class EngineProcess private constructor(val project: Project, private val classN generateUtilClassFile: Boolean, enableTestsTimeout: Boolean, testClassPackageName: String, - codeGenerationContext: CodeGenerationContext, ): RenderParams = RenderParams( testSetsId, @@ -343,7 +337,6 @@ class EngineProcess private constructor(val project: Project, private val classN model.hangingTestsTimeout.timeoutMs, enableTestsTimeout, testClassPackageName, - kryoHelper.writeObject(codeGenerationContext), ) private fun getSourceFile(params: SourceStrategyMethodArgs): String? = diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index bbf51d760b..b60fe4fa2f 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -54,6 +54,7 @@ import com.intellij.ui.JBColor import com.intellij.ui.JBIntSpinner import com.intellij.ui.SideBorder import com.intellij.ui.SimpleTextAttributes +import org.utbot.framework.plugin.api.SpringSettings.* import com.intellij.ui.components.CheckBox import com.intellij.ui.components.JBLabel import com.intellij.ui.components.JBScrollPane @@ -94,7 +95,6 @@ import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.framework.plugin.api.TreatOverflowAsError import org.utbot.framework.plugin.api.MockFramework.MOCKITO import org.utbot.framework.plugin.api.SpringTestType -import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.MockFramework import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.CodeGenerationSettingItem @@ -133,12 +133,7 @@ import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle import org.utbot.intellij.plugin.ui.utils.parseVersion import org.utbot.intellij.plugin.ui.utils.testResourceRootTypes import org.utbot.intellij.plugin.ui.utils.testRootType -import org.utbot.intellij.plugin.util.IntelliJApiHelper -import org.utbot.intellij.plugin.util.SpringConfigurationsHelper -import org.utbot.intellij.plugin.util.extractFirstLevelMembers -import org.utbot.intellij.plugin.util.findSdkVersion -import org.utbot.intellij.plugin.util.SpringConfigurationType -import org.utbot.intellij.plugin.util.findSdkVersionOrNull +import org.utbot.intellij.plugin.util.* import java.awt.BorderLayout import java.awt.Color import java.awt.Component @@ -700,26 +695,26 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.timeout = TimeUnit.SECONDS.toMillis(timeoutSpinner.number.toLong()) model.testSourceRoot?.apply { model.updateSourceRootHistory(this.toNioPath().toString()) } - when (springConfig.item) { - NO_SPRING_CONFIGURATION_OPTION -> null - else -> { - val shortConfigName = springConfig.item.toString() - //TODO: avoid this check on xml here, merge two helpers into one - if (isXmlSpringConfigUsed()) { - val absolutePath = xmlConfigurationHelper.restoreFullName(shortConfigName) - SpringConfiguration.XMLConfiguration(absolutePath) - } else { - val classBinaryName = javaConfigurationHelper.restoreFullName(shortConfigName) - SpringConfiguration.JavaConfiguration(classBinaryName) + model.springSettings = + when (springConfig.item) { + NO_SPRING_CONFIGURATION_OPTION -> AbsentSpringSettings() + else -> { + val shortConfigName = springConfig.item.toString() + val config = + if (isXmlSpringConfigUsed()) { + val absolutePath = xmlConfigurationHelper.restoreFullName(shortConfigName) + SpringConfiguration.XMLConfiguration(absolutePath) + } else { + val classBinaryName = javaConfigurationHelper.restoreFullName(shortConfigName) + SpringConfiguration.JavaConfiguration(classBinaryName) + } + + PresentSpringSettings( + configuration = config, + profiles = parseProfileExpression(profileNames.text, DEFAULT_SPRING_PROFILE_NAME) + ) } } - }?.let { - model.springSettings = - SpringSettings( - configuration = it, - profileExpression = profileNames.text.let { text -> text.ifEmpty { DEFAULT_SPRING_PROFILE_NAME } } - ) - } model.springTestType = springTestType.item @@ -1148,10 +1143,10 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m springConfig.addActionListener { _ -> if (isSpringConfigSelected()) { if (isXmlSpringConfigUsed()) { - springTestsType.item = SpringTestsType.defaultItem + springTestType.item = SpringTestType.defaultItem } - if (springTestsType.item == UNIT_TEST) { + if (springTestType.item == UNIT_TEST) { mockStrategies.item = MockStrategyApi.springDefaultItem } } else { @@ -1160,7 +1155,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m else -> MockStrategyApi.defaultItem } - springTestsType.item = SpringTestsType.defaultItem + springTestType.item = SpringTestType.defaultItem profileNames.text = "" } @@ -1350,10 +1345,10 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m if (isSpringConfigSelected()) { mockStrategies.isEnabled = false profileNames.isEnabled = true - springTestsType.isEnabled = !isXmlSpringConfigUsed() + springTestType.isEnabled = !isXmlSpringConfigUsed() } else { profileNames.isEnabled = false - springTestsType.isEnabled = false + springTestType.isEnabled = false } } } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt index c952295602..1c21adfd16 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/SpringConfigurationsHelper.kt @@ -92,6 +92,23 @@ class SpringConfigurationsHelper(val configType: SpringConfigurationType) { } +/* + * Transforms active profile information + * from the form of user input to a list of active profiles. + * + * NOTICE: Current user input form is comma-separated values, but it may be changed later. + */ +fun parseProfileExpression(profileExpression: String?, default: String): Array { + if (profileExpression.isNullOrEmpty()) { + return arrayOf(default) + } + + return profileExpression + .filter { !it.isWhitespace() } + .split(',') + .toTypedArray() +} + @Deprecated("To be deleted") enum class SpringConfigurationType( val separatorsToSplitBy: Array, diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt index eba3618af9..a4a51181fb 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/EngineProcessModel.kt @@ -77,7 +77,6 @@ object EngineProcessModel : Ext(EngineProcessRoot) { field("hangingTestsTimeout", PredefinedType.long) field("enableTestsTimeout", PredefinedType.bool) field("testClassPackageName", PredefinedType.string) - field("codeGenerationContext", array(PredefinedType.byte)) } val renderResult = structdef { field("generatedCode", PredefinedType.string) @@ -88,9 +87,7 @@ object EngineProcessModel : Ext(EngineProcessRoot) { } val getSpringBeanDefinitions = structdef { field("classpath", array(PredefinedType.string)) - field("configuration", array(PredefinedType.byte)) - field("fileStorage", array(PredefinedType.string)) - field("profileExpression", PredefinedType.string.nullable) // TODO: why nullable? + field("springSettings", array(PredefinedType.byte)) } val methodDescription = structdef { field("name", PredefinedType.string) diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt index 7c23f14be1..e5474cae67 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SpringAnalyzerModel.kt @@ -7,9 +7,7 @@ object SpringAnalyzerRoot : Root() object SpringAnalyzerProcessModel : Ext(SpringAnalyzerRoot) { val springAnalyzerParams = structdef { - field("configuration", array(PredefinedType.byte)) - field("fileStorage", array(PredefinedType.string)) - field("profileExpression", PredefinedType.string.nullable) + field("springSettings", array(PredefinedType.byte)) } val beanAdditionalData = structdef { diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/analyzer/SpringApplicationAnalyzer.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/analyzer/SpringApplicationAnalyzer.kt index 74b1ea5c66..e1a07a7c57 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/analyzer/SpringApplicationAnalyzer.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/analyzer/SpringApplicationAnalyzer.kt @@ -10,10 +10,11 @@ import org.utbot.spring.utils.SourceFinder class SpringApplicationAnalyzer { fun getBeanDefinitions(applicationData: ApplicationData): Array { + // TODO: get rid of SourceFinder val configurationClasses = SourceFinder(applicationData).findSources() val instantiationSettings = InstantiationSettings( configurationClasses, - applicationData.profileExpression, + applicationData.springSettings.profiles, ) return SpringApiProviderFacade.getInstance(this::class.java.classLoader) diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt index 2ba1c63dcd..b776eb9c76 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/api/ApplicationData.kt @@ -1,10 +1,7 @@ package org.utbot.spring.api -import org.utbot.framework.plugin.api.SpringConfiguration -import java.net.URL +import org.utbot.framework.plugin.api.SpringSettings.* class ApplicationData( - val configurationFile: SpringConfiguration, - val fileStorage: List, - val profileExpression: String?, + val springSettings: PresentSpringSettings ) diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt index 825bbaeffe..066048b61e 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/generated/SpringAnalyzerProcessModel.Generated.kt @@ -50,7 +50,7 @@ class SpringAnalyzerProcessModel private constructor( } - const val serializationHash = -6862945874536334699L + const val serializationHash = 8094902537230457267L } override val serializersOwner: ISerializersOwner get() = SpringAnalyzerProcessModel @@ -97,7 +97,7 @@ val IProtocol.springAnalyzerProcessModel get() = getOrCreateExtension(SpringAnal /** - * #### Generated from [SpringAnalyzerModel.kt:15] + * #### Generated from [SpringAnalyzerModel.kt:13] */ data class BeanAdditionalData ( val factoryMethodName: String, @@ -166,7 +166,7 @@ data class BeanAdditionalData ( /** - * #### Generated from [SpringAnalyzerModel.kt:21] + * #### Generated from [SpringAnalyzerModel.kt:19] */ data class BeanDefinitionData ( val beanName: String, @@ -238,9 +238,7 @@ data class BeanDefinitionData ( * #### Generated from [SpringAnalyzerModel.kt:9] */ data class SpringAnalyzerParams ( - val configuration: ByteArray, - val fileStorage: Array, - val profileExpression: String? + val springSettings: ByteArray ) : IPrintable { //companion @@ -249,16 +247,12 @@ data class SpringAnalyzerParams ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): SpringAnalyzerParams { - val configuration = buffer.readByteArray() - val fileStorage = buffer.readArray {buffer.readString()} - val profileExpression = buffer.readNullable { buffer.readString() } - return SpringAnalyzerParams(configuration, fileStorage, profileExpression) + val springSettings = buffer.readByteArray() + return SpringAnalyzerParams(springSettings) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: SpringAnalyzerParams) { - buffer.writeByteArray(value.configuration) - buffer.writeArray(value.fileStorage) { buffer.writeString(it) } - buffer.writeNullable(value.profileExpression) { buffer.writeString(it) } + buffer.writeByteArray(value.springSettings) } @@ -274,27 +268,21 @@ data class SpringAnalyzerParams ( other as SpringAnalyzerParams - if (!(configuration contentEquals other.configuration)) return false - if (!(fileStorage contentDeepEquals other.fileStorage)) return false - if (profileExpression != other.profileExpression) return false + if (!(springSettings contentEquals other.springSettings)) return false return true } //hash code trait override fun hashCode(): Int { var __r = 0 - __r = __r*31 + configuration.contentHashCode() - __r = __r*31 + fileStorage.contentDeepHashCode() - __r = __r*31 + if (profileExpression != null) profileExpression.hashCode() else 0 + __r = __r*31 + springSettings.contentHashCode() return __r } //pretty print override fun print(printer: PrettyPrinter) { printer.println("SpringAnalyzerParams (") printer.indent { - print("configuration = "); configuration.print(printer); println() - print("fileStorage = "); fileStorage.print(printer); println() - print("profileExpression = "); profileExpression.print(printer); println() + print("springSettings = "); springSettings.print(printer); println() } printer.print(")") } @@ -304,7 +292,7 @@ data class SpringAnalyzerParams ( /** - * #### Generated from [SpringAnalyzerModel.kt:27] + * #### Generated from [SpringAnalyzerModel.kt:25] */ data class SpringAnalyzerResult ( val beanDefinitions: Array diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt index 9bd5e92a7f..d63195b4b2 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt @@ -88,11 +88,9 @@ class SpringAnalyzerProcess private constructor( private val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel } fun getBeanDefinitions( - configuration: ByteArray, - fileStorage: Array, - profileExpression: String?, + springSettings: ByteArray ): SpringAnalyzerResult { - val params = SpringAnalyzerParams(configuration, fileStorage, profileExpression) + val params = SpringAnalyzerParams(springSettings) return springAnalyzerModel.analyze.startBlocking(params) } } diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt index 37c17bf365..8a1d72f8d2 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcessMain.kt @@ -45,9 +45,7 @@ private fun SpringAnalyzerProcessModel.setup(watchdog: IdleWatchdog, realProtoco watchdog.measureTimeForActiveCall(analyze, "Analyzing Spring Application") { params -> val applicationData = ApplicationData( - kryoHelper.readObject(params.configuration), - params.fileStorage.map { File(it).toURI().toURL() }, - params.profileExpression, + kryoHelper.readObject(params.springSettings) ) SpringAnalyzerResult( diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt index 9c865f615a..691ce2f40c 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/utils/SourceFinder.kt @@ -4,6 +4,7 @@ import com.jetbrains.rd.util.getLogger import com.jetbrains.rd.util.info import org.springframework.context.annotation.ImportResource import org.utbot.common.patchAnnotation +import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.spring.api.ApplicationData import org.utbot.spring.config.TestApplicationConfiguration import org.utbot.spring.configurators.ApplicationConfigurationType @@ -18,8 +19,8 @@ class SourceFinder( private val classLoader: ClassLoader = this::class.java.classLoader fun findSources(): Array> = - when (val config = applicationData.configurationFile) { - is SpringConfiguration.JavaConfiguration -> { + when (val config = applicationData.springSettings.configuration) { + is JavaConfiguration -> { logger.info { "Using java Spring configuration" } arrayOf( TestApplicationConfiguration::class.java, @@ -27,7 +28,7 @@ class SourceFinder( ) } - is SpringConfiguration.XMLConfiguration -> { + is XMLConfiguration -> { logger.info { "Using xml Spring configuration" } // Put `applicationData.configurationFile` in `@ImportResource` of `TestApplicationConfiguration` diff --git a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/instantiator/InstantiationSettings.kt b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/instantiator/InstantiationSettings.kt index db6eafe115..3a783a1b7b 100644 --- a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/instantiator/InstantiationSettings.kt +++ b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/instantiator/InstantiationSettings.kt @@ -2,5 +2,5 @@ package org.utbot.spring.api.instantiator class InstantiationSettings( val configurationClasses: Array>, - val profileExpression: String?, + val profiles: Array, ) \ No newline at end of file diff --git a/utbot-spring-commons/src/main/kotlin/org/utbot/spring/SpringApiImpl.kt b/utbot-spring-commons/src/main/kotlin/org/utbot/spring/SpringApiImpl.kt index 58773e5e76..65907f737a 100644 --- a/utbot-spring-commons/src/main/kotlin/org/utbot/spring/SpringApiImpl.kt +++ b/utbot-spring-commons/src/main/kotlin/org/utbot/spring/SpringApiImpl.kt @@ -30,7 +30,7 @@ class SpringApiImpl( patchAnnotation( annotation = it.getAnnotation(ActiveProfiles::class.java), property = "value", - newValue = parseProfileExpression(instantiationSettings.profileExpression) + newValue = instantiationSettings.profiles ) patchAnnotation( annotation = it.getAnnotation(ContextConfiguration::class.java), @@ -153,23 +153,6 @@ class SpringApiImpl( false } - companion object { - private const val DEFAULT_PROFILE_NAME = "default" - - /** - * Transforms active profile information - * from the form of user input to a list of active profiles. - * - * Current user input form is comma-separated values, but it may be changed later. - */ - private fun parseProfileExpression(profileExpression: String?): Array = - if (profileExpression.isNullOrEmpty()) arrayOf(DEFAULT_PROFILE_NAME) - else profileExpression - .filter { !it.isWhitespace() } - .split(',') - .toTypedArray() - } - data class SimpleBeanDefinition( val beanName: String, val bean: Any, diff --git a/utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt b/utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt new file mode 100644 index 0000000000..e69de29bb2 From 342a66f1769425f8cf90393f501893cda7c41cc1 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:49:00 +0300 Subject: [PATCH 7/8] Adapt annotation codegeneration --- ...CgSpringIntegrationTestClassConstructor.kt | 32 +++++++++++++++++-- .../spring/api/context/ContextWrapper.kt | 0 .../spring/environment/EnvironmentFactory.kt | 0 3 files changed, 30 insertions(+), 2 deletions(-) delete mode 100644 utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt delete mode 100644 utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt index 5ec31e5ccb..0fd7e103d6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt @@ -7,6 +7,7 @@ import org.utbot.framework.codegen.domain.TestNg import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.* import org.utbot.framework.codegen.domain.models.AnnotationTarget.* +import org.utbot.framework.codegen.util.resolve import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* @@ -61,12 +62,39 @@ class CgSpringIntegrationTestClassConstructor( ) addAnnotation( classId = activeProfilesClassId, - argument = springSettings.profiles.first(), // TODO: andrey + namedArguments = + listOf( + CgNamedAnnotationArgument( + name = "profiles", + value = + CgArrayAnnotationArgument( + springSettings.profiles.map { profile -> + profile.resolve() + } + ) + ) + ), target = Class, ) addAnnotation( classId = contextConfigurationClassId, - argument = (springSettings.configuration as JavaConfiguration).classBinaryName, // TODO: andrey + namedArguments = + listOf( + CgNamedAnnotationArgument( + name = "classes", + value = CgArrayAnnotationArgument( + listOf( + createGetClassExpression( + // TODO: + // For now we support only JavaConfigurations in integration tests. + // Adapt for XMLConfigurations when supported. + ClassId((springSettings.configuration as JavaConfiguration).classBinaryName), + codegenLanguage + ) + ) + ) + ) + ), target = Class, ) addAnnotation( diff --git a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt b/utbot-spring-commons/src/main/kotlin/org/utbot/spring/environment/EnvironmentFactory.kt deleted file mode 100644 index e69de29bb2..0000000000 From a1b34b65efae09bda637335381b975bdfe5c35ed Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:25:43 +0300 Subject: [PATCH 8/8] Apply comment suggestions --- .../main/kotlin/org/utbot/framework/plugin/api/Api.kt | 9 +++++++-- .../codegen/tree/CgAbstractSpringTestClassConstructor.kt | 7 +++---- .../org/utbot/framework/process/EngineProcessMain.kt | 2 +- .../execution/mock/SpringInstrumentationContext.kt | 0 .../utbot/intellij/plugin/models/GenerateTestsModel.kt | 3 +-- .../intellij/plugin/ui/GenerateTestsDialogWindow.kt | 6 +++--- .../org/utbot/spring/process/SpringAnalyzerProcess.kt | 7 +++++-- 7 files changed, 20 insertions(+), 14 deletions(-) delete mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index aa7b10a8ba..4e325a414b 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1399,6 +1399,12 @@ sealed interface SpringConfiguration { sealed interface SpringSettings { class AbsentSpringSettings : SpringSettings { // Denotes no configuration and no profile setting + + // NOTICE: + // `class` should not be replaced with `object` + // in order to avoid issues caused by Kryo deserialization + // that creates new instances breaking `when` expressions + // that check reference equality instead of type equality } class PresentSpringSettings( @@ -1442,7 +1448,6 @@ class SpringApplicationContext( private val springInjectedClasses: Set get() { if (!areInjectedClassesInitialized) { - // TODO: use more info from SpringBeanDefinitionData than beanTypeName offers here for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { try { val beanClass = utContext.classLoader.loadClass(beanTypeName) @@ -1511,7 +1516,7 @@ enum class SpringTestType( override val displayName: String, override val description: String, // Integration tests generation requires spring test framework being installed - var frameworkInstalled: Boolean = false, + var testFrameworkInstalled: Boolean = false, ) : CodeGenerationSettingItem { UNIT_TEST( "Unit tests", diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt index 4e7f4761b8..7f6db82243 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt @@ -27,7 +27,6 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): protected val variableConstructor: CgSpringVariableConstructor = CgComponents.getVariableConstructorBy(context) as CgSpringVariableConstructor - protected val statementConstructor: CgStatementConstructor = CgComponents.getStatementConstructorBy(context) override fun constructTestClassBody(testClassModel: SpringTestClassModel): CgClassBody { return buildClassBody(currentTestClass) { @@ -88,7 +87,7 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): annotationClassId: ClassId, groupedModelsByClassId: TypedModelWrappers, ): List { - val annotation = statementConstructor.addAnnotation(annotationClassId, Field) + val annotation = addAnnotation(annotationClassId, Field) val constructedDeclarations = mutableListOf() for ((classId, listOfUtModels) in groupedModelsByClassId) { @@ -133,7 +132,7 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): } protected fun constructBeforeMethod(statements: List): CgFrameworkUtilMethod { - val beforeAnnotation = statementConstructor.addAnnotation(context.testFramework.beforeMethodId, Method) + val beforeAnnotation = addAnnotation(context.testFramework.beforeMethodId, Method) return CgFrameworkUtilMethod( name = "setUp", statements = statements, @@ -143,7 +142,7 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): } protected fun constructAfterMethod(statements: List): CgFrameworkUtilMethod { - val afterAnnotation = statementConstructor.addAnnotation(context.testFramework.afterMethodId, Method) + val afterAnnotation = addAnnotation(context.testFramework.afterMethodId, Method) return CgFrameworkUtilMethod( name = "tearDown", statements = statements, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt index 8059ddeb3d..0fe1b94720 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt @@ -83,7 +83,7 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch val springAnalyzerProcess = SpringAnalyzerProcess.createBlocking(params.classpath.toList()) val result = springAnalyzerProcess.terminateOnException { _ -> springAnalyzerProcess.getBeanDefinitions( - params.springSettings + kryoHelper.readObject(params.springSettings) ) } springAnalyzerProcess.terminate() diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/mock/SpringInstrumentationContext.kt deleted file mode 100644 index e69de29bb2..0000000000 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 a7df31e701..b0114ca4b3 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 @@ -44,8 +44,6 @@ class GenerateTestsModel( override var sourceRootHistory = project.service().sourceRootHistory override var codegenLanguage = project.service().codegenLanguage - lateinit var springTestType: SpringTestType - lateinit var testFramework: TestFramework lateinit var mockStrategy: MockStrategyApi lateinit var mockFramework: MockFramework @@ -60,6 +58,7 @@ class GenerateTestsModel( lateinit var commentStyle: JavaDocCommentStyle lateinit var springSettings: SpringSettings + lateinit var springTestType: SpringTestType val conflictTriggers: ConflictTriggers = ConflictTriggers() val preCompilePromises: MutableList> = mutableListOf() diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index b60fe4fa2f..46ddb0920f 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -370,7 +370,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m else -> null } installedDiFramework?.let { - INTEGRATION_TEST.frameworkInstalled = findDependencyInjectionTestLibrary(model.testModule, it) != null + INTEGRATION_TEST.testFrameworkInstalled = findDependencyInjectionTestLibrary(model.testModule, it) != null } model.projectType = if (installedDiFramework != null) ProjectType.Spring else ProjectType.PureJvm @@ -996,7 +996,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.preCompilePromises += addDependency(model.testModule, libraryDescriptor) } - INTEGRATION_TEST.frameworkInstalled = true + INTEGRATION_TEST.testFrameworkInstalled = true } private fun configureMockFramework() { @@ -1281,7 +1281,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m index: Int, selected: Boolean, hasFocus: Boolean ) { this.append(value.displayName, SimpleTextAttributes.REGULAR_ATTRIBUTES) - if (value == INTEGRATION_TEST && !INTEGRATION_TEST.frameworkInstalled) { + if (value == INTEGRATION_TEST && !INTEGRATION_TEST.testFrameworkInstalled) { val additionalText = when { SpringBoot.isInstalled -> " (spring-boot-test will be installed)" SpringBeans.isInstalled -> " (spring-test will be installed)" diff --git a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt index d63195b4b2..044ef0c4a9 100644 --- a/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt +++ b/utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/process/SpringAnalyzerProcess.kt @@ -22,6 +22,8 @@ import org.utbot.spring.generated.SpringAnalyzerProcessModel import org.utbot.spring.generated.SpringAnalyzerResult import org.utbot.spring.generated.springAnalyzerProcessModel import java.io.File +import org.utbot.framework.plugin.api.SpringSettings.* +import org.utbot.framework.process.kryo.KryoHelper class SpringAnalyzerProcessInstantDeathException : InstantProcessDeathException( @@ -86,11 +88,12 @@ class SpringAnalyzerProcess private constructor( private val springAnalyzerModel: SpringAnalyzerProcessModel = onSchedulerBlocking { protocol.springAnalyzerProcessModel } private val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel } + private val kryoHelper = KryoHelper(lifetime) fun getBeanDefinitions( - springSettings: ByteArray + springSettings: PresentSpringSettings ): SpringAnalyzerResult { - val params = SpringAnalyzerParams(springSettings) + val params = SpringAnalyzerParams(kryoHelper.writeObject(springSettings)) return springAnalyzerModel.analyze.startBlocking(params) } }