From 13fe4cd6345c49d2753c0cac2b38776afbc0642e Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 10:52:30 +0300 Subject: [PATCH 01/20] Move `ApplicationContext` and `SpringApplicationContext` to `utbot-framework` --- .../org/utbot/framework/plugin/api/Api.kt | 208 ------------------ .../src/main/kotlin/org/utbot/engine/Mocks.kt | 2 +- .../main/kotlin/org/utbot/engine/Traverser.kt | 2 +- .../org/utbot/engine/UtBotSymbolicEngine.kt | 2 + .../framework/context/ApplicationContext.kt | 75 +++++++ .../context/SpringApplicationContext.kt | 158 +++++++++++++ .../framework/plugin/api/TestCaseGenerator.kt | 2 + .../framework/process/EngineProcessMain.kt | 1 + .../generator/UtTestsDialogProcessor.kt | 2 + .../intellij/plugin/process/EngineProcess.kt | 1 + .../testing/TestCodeGeneratorPipeline.kt | 2 +- 11 files changed, 244 insertions(+), 211 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.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 80f0f070d2..ac61cf912d 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 @@ -8,7 +8,6 @@ package org.utbot.framework.plugin.api -import mu.KotlinLogging import org.utbot.common.FileUtil import org.utbot.common.isDefaultValue import org.utbot.common.withToStringThreadLocalReentrancyGuard @@ -56,17 +55,8 @@ import java.io.File import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import org.utbot.common.isAbstract -import org.utbot.common.isStatic -import org.utbot.framework.isFromTrustedLibrary -import org.utbot.framework.plugin.api.TypeReplacementMode.* import org.utbot.framework.plugin.api.util.SpringModelUtils -import org.utbot.framework.plugin.api.util.allDeclaredFieldIds -import org.utbot.framework.plugin.api.util.allSuperTypes -import org.utbot.framework.plugin.api.util.fieldId -import org.utbot.framework.plugin.api.util.isSubtypeOf -import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.process.OpenModulesContainer -import soot.SootField import soot.SootMethod const val SYMBOLIC_NULL_ADDR: Int = 0 @@ -1336,71 +1326,6 @@ interface SpringCodeGenerationContext : CodeGenerationContext { val springContextLoadingResult: SpringContextLoadingResult? } -/** - * A context to use when no specific data is required. - * - * @param mockFrameworkInstalled shows if we have installed framework dependencies - * @param staticsMockingIsConfigured shows if we have installed static mocking tools - */ -open class ApplicationContext( - val mockFrameworkInstalled: Boolean = true, - staticsMockingIsConfigured: Boolean = true, -) : CodeGenerationContext { - var staticsMockingIsConfigured = staticsMockingIsConfigured - private set - - init { - /** - * Situation when mock framework is not installed but static mocking is configured is semantically incorrect. - * - * However, it may be obtained in real application after this actions: - * - fully configure mocking (dependency installed + resource file created) - * - remove mockito-core dependency from project - * - forget to remove mock-maker file from resource directory - * - * Here we transform this configuration to semantically correct. - */ - if (!mockFrameworkInstalled && staticsMockingIsConfigured) { - this.staticsMockingIsConfigured = false - } - } - - /** - * Shows if there are any restrictions on type implementors. - */ - open val typeReplacementMode: TypeReplacementMode = AnyImplementor - - /** - * Finds a type to replace the original abstract type - * if it is guided with some additional information. - */ - open fun replaceTypeIfNeeded(type: RefType): ClassId? = null - - /** - * Sets the restrictions on speculative not null - * constraints in current application context. - * - * @see docs/SpeculativeFieldNonNullability.md for more information. - */ - open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = - UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary() - - /** - * Checks whether accessing [field] (with a method invocation or field access) speculatively - * cannot produce [NullPointerException] (according to its finality or accessibility). - * - * @see docs/SpeculativeFieldNonNullability.md for more information. - */ - open fun speculativelyCannotProduceNullPointerException( - field: SootField, - classUnderTest: ClassId, - ): Boolean = field.isFinal || !field.isPublic - - open fun preventsFurtherTestGeneration(): Boolean = false - - open fun getErrors(): List = emptyList() -} - sealed class SpringConfiguration(val fullDisplayName: String) { class JavaConfiguration(val classBinaryName: String) : SpringConfiguration(classBinaryName) class XMLConfiguration(val absolutePath: String) : SpringConfiguration(absolutePath) @@ -1433,139 +1358,6 @@ class SpringContextLoadingResult( val exceptions: List ) -/** - * Data we get from Spring application context - * to manage engine and code generator behaviour. - * - * @param beanDefinitions describes bean definitions (bean name, type, some optional additional data) - * @param shouldUseImplementors describes it we want to replace interfaces with injected types or not - */ -// TODO move this class to utbot-framework so we can use it as abstract factory -// to get rid of numerous `when`s and polymorphically create things like: -// - Instrumentation -// - FuzzedType (to get rid of thisInstanceFuzzedTypeWrapper) -// - JavaValueProvider -// - CgVariableConstructor -// - CodeGeneratorResult (generateForSpringClass) -// Right now this refactoring is blocked because some interfaces need to get extracted and moved to utbot-framework-api -// As an alternative we can just move ApplicationContext itself to utbot-framework -class SpringApplicationContext( - mockInstalled: Boolean, - staticsMockingIsConfigured: Boolean, - val beanDefinitions: List = emptyList(), - private val shouldUseImplementors: Boolean, - override val springTestType: SpringTestType, - override val springSettings: SpringSettings, -): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext { - - override var springContextLoadingResult: SpringContextLoadingResult? = null - - companion object { - private val logger = KotlinLogging.logger {} - } - - private var areInjectedClassesInitialized : Boolean = false - private var areAllInjectedTypesInitialized: Boolean = false - - // Classes representing concrete types that are actually used in Spring application - private val springInjectedClasses: Set - get() { - if (!areInjectedClassesInitialized) { - for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { - try { - val beanClass = utContext.classLoader.loadClass(beanTypeName) - if (!beanClass.isAbstract && !beanClass.isInterface && - !beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) { - springInjectedClassesStorage += beanClass.id - } - } catch (e: Throwable) { - // For some Spring beans (e.g. with anonymous classes) - // 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 $beanTypeName (${e.message})" } - - else -> throw e - } - } - } - - // This is done to be sure that this storage is not empty after the first class loading iteration. - // So, even if all loaded classes were filtered out, we will not try to load them again. - areInjectedClassesInitialized = true - } - - return springInjectedClassesStorage - } - - private val allInjectedTypes: Set - get() { - if (!areAllInjectedTypesInitialized) { - allInjectedTypesStorage = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet() - areAllInjectedTypesInitialized = true - } - - return allInjectedTypesStorage - } - - // imitates `by lazy` (we can't use actual `by lazy` because communication via RD breaks it) - private var allInjectedTypesStorage: Set = emptySet() - - // This is a service field to model the lazy behavior of [springInjectedClasses]. - // Do not call it outside the getter. - // - // Actually, we should just call [springInjectedClasses] with `by lazy`, but we had problems - // with a strange `kotlin.UNINITIALIZED_VALUE` in `speculativelyCannotProduceNullPointerException` method call. - private val springInjectedClassesStorage = mutableSetOf() - - override val typeReplacementMode: TypeReplacementMode = - if (shouldUseImplementors) KnownImplementor else NoImplementors - - /** - * Replaces an interface type with its implementor type - * if there is the unique implementor in bean definitions. - */ - override fun replaceTypeIfNeeded(type: RefType): ClassId? = - if (type.isAbstractType) { - springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) } - } else { - null - } - - override fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = false - - /** - * In Spring applications we can mark as speculatively not null - * fields if they are mocked and injecting into class under test so on. - * - * Fields are not mocked if their actual type is obtained from [springInjectedClasses]. - * - */ - override fun speculativelyCannotProduceNullPointerException( - field: SootField, - classUnderTest: ClassId, - ): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in allInjectedTypes - - override fun preventsFurtherTestGeneration(): Boolean = - super.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false - - override fun getErrors(): List = - springContextLoadingResult?.exceptions?.map { exception -> - UtError( - "Failed to load Spring application context", - exception - ) - }.orEmpty() + super.getErrors() - - fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> - // some bean classes may fail to load - runCatching { - val beanClass = ClassId(beanDef.beanTypeName).jClass - classId.jClass.isAssignableFrom(beanClass) - }.getOrElse { false } - } -} - enum class SpringTestType( override val id: String, override val displayName: String, diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt index 4b16c57db4..bf81618295 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt @@ -19,7 +19,7 @@ import kotlinx.collections.immutable.persistentListOf import org.utbot.common.nameOfPackage import org.utbot.engine.types.OBJECT_TYPE import org.utbot.engine.util.mockListeners.MockListenerController -import org.utbot.framework.plugin.api.ApplicationContext +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.util.isInaccessibleViaReflection import soot.BooleanType import soot.RefType diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index fc213b52de..102050e024 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -116,7 +116,7 @@ import org.utbot.framework.UtSettings import org.utbot.framework.UtSettings.preferredCexOption import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable import org.utbot.framework.isFromTrustedLibrary -import org.utbot.framework.plugin.api.ApplicationContext +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.FieldId 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 43077551f2..71fd896bad 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -33,6 +33,8 @@ import org.utbot.framework.UtSettings.pathSelectorStepsLimit import org.utbot.framework.UtSettings.pathSelectorType import org.utbot.framework.UtSettings.processUnknownStatesDuringConcreteExecution import org.utbot.framework.UtSettings.useDebugVisualization +import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.Step import org.utbot.framework.plugin.api.util.* diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt new file mode 100644 index 0000000000..28f54155df --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -0,0 +1,75 @@ +package org.utbot.framework.context + +import org.utbot.framework.UtSettings +import org.utbot.framework.isFromTrustedLibrary +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.CodeGenerationContext +import org.utbot.framework.plugin.api.TypeReplacementMode +import org.utbot.framework.plugin.api.UtError +import soot.RefType +import soot.SootField + +/** + * A context to use when no specific data is required. + * + * @param mockFrameworkInstalled shows if we have installed framework dependencies + * @param staticsMockingIsConfigured shows if we have installed static mocking tools + */ +open class ApplicationContext( + val mockFrameworkInstalled: Boolean = true, + staticsMockingIsConfigured: Boolean = true, +) : CodeGenerationContext { + var staticsMockingIsConfigured = staticsMockingIsConfigured + private set + + init { + /** + * Situation when mock framework is not installed but static mocking is configured is semantically incorrect. + * + * However, it may be obtained in real application after this actions: + * - fully configure mocking (dependency installed + resource file created) + * - remove mockito-core dependency from project + * - forget to remove mock-maker file from resource directory + * + * Here we transform this configuration to semantically correct. + */ + if (!mockFrameworkInstalled && staticsMockingIsConfigured) { + this.staticsMockingIsConfigured = false + } + } + + /** + * Shows if there are any restrictions on type implementors. + */ + open val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor + + /** + * Finds a type to replace the original abstract type + * if it is guided with some additional information. + */ + open fun replaceTypeIfNeeded(type: RefType): ClassId? = null + + /** + * Sets the restrictions on speculative not null + * constraints in current application context. + * + * @see docs/SpeculativeFieldNonNullability.md for more information. + */ + open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = + UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary() + + /** + * Checks whether accessing [field] (with a method invocation or field access) speculatively + * cannot produce [NullPointerException] (according to its finality or accessibility). + * + * @see docs/SpeculativeFieldNonNullability.md for more information. + */ + open fun speculativelyCannotProduceNullPointerException( + field: SootField, + classUnderTest: ClassId, + ): Boolean = field.isFinal || !field.isPublic + + open fun preventsFurtherTestGeneration(): Boolean = false + + open fun getErrors(): List = emptyList() +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt new file mode 100644 index 0000000000..adae9ea3be --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt @@ -0,0 +1,158 @@ +package org.utbot.framework.context + +import mu.KotlinLogging +import org.utbot.common.isAbstract +import org.utbot.common.isStatic +import org.utbot.framework.plugin.api.BeanDefinitionData +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.SpringCodeGenerationContext +import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.SpringTestType +import org.utbot.framework.plugin.api.TypeReplacementMode +import org.utbot.framework.plugin.api.UtError +import org.utbot.framework.plugin.api.classId +import org.utbot.framework.plugin.api.id +import org.utbot.framework.plugin.api.isAbstractType +import org.utbot.framework.plugin.api.util.allDeclaredFieldIds +import org.utbot.framework.plugin.api.util.allSuperTypes +import org.utbot.framework.plugin.api.util.fieldId +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.isSubtypeOf +import org.utbot.framework.plugin.api.util.jClass +import org.utbot.framework.plugin.api.util.utContext +import soot.RefType +import soot.SootField + +/** + * Data we get from Spring application context + * to manage engine and code generator behaviour. + * + * @param beanDefinitions describes bean definitions (bean name, type, some optional additional data) + * @param shouldUseImplementors describes it we want to replace interfaces with injected types or not + */ +// TODO move this class to utbot-framework so we can use it as abstract factory +// to get rid of numerous `when`s and polymorphically create things like: +// - Instrumentation +// - FuzzedType (to get rid of thisInstanceFuzzedTypeWrapper) +// - JavaValueProvider +// - CgVariableConstructor +// - CodeGeneratorResult (generateForSpringClass) +// Right now this refactoring is blocked because some interfaces need to get extracted and moved to utbot-framework-api +// As an alternative we can just move ApplicationContext itself to utbot-framework +class SpringApplicationContext( + mockInstalled: Boolean, + staticsMockingIsConfigured: Boolean, + val beanDefinitions: List = emptyList(), + private val shouldUseImplementors: Boolean, + override val springTestType: SpringTestType, + override val springSettings: SpringSettings, +): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext { + + override var springContextLoadingResult: SpringContextLoadingResult? = null + + companion object { + private val logger = KotlinLogging.logger {} + } + + private var areInjectedClassesInitialized : Boolean = false + private var areAllInjectedTypesInitialized: Boolean = false + + // Classes representing concrete types that are actually used in Spring application + private val springInjectedClasses: Set + get() { + if (!areInjectedClassesInitialized) { + for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { + try { + val beanClass = utContext.classLoader.loadClass(beanTypeName) + if (!beanClass.isAbstract && !beanClass.isInterface && + !beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) { + springInjectedClassesStorage += beanClass.id + } + } catch (e: Throwable) { + // For some Spring beans (e.g. with anonymous classes) + // 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 $beanTypeName (${e.message})" } + + else -> throw e + } + } + } + + // This is done to be sure that this storage is not empty after the first class loading iteration. + // So, even if all loaded classes were filtered out, we will not try to load them again. + areInjectedClassesInitialized = true + } + + return springInjectedClassesStorage + } + + private val allInjectedTypes: Set + get() { + if (!areAllInjectedTypesInitialized) { + allInjectedTypesStorage = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet() + areAllInjectedTypesInitialized = true + } + + return allInjectedTypesStorage + } + + // imitates `by lazy` (we can't use actual `by lazy` because communication via RD breaks it) + private var allInjectedTypesStorage: Set = emptySet() + + // This is a service field to model the lazy behavior of [springInjectedClasses]. + // Do not call it outside the getter. + // + // Actually, we should just call [springInjectedClasses] with `by lazy`, but we had problems + // with a strange `kotlin.UNINITIALIZED_VALUE` in `speculativelyCannotProduceNullPointerException` method call. + private val springInjectedClassesStorage = mutableSetOf() + + override val typeReplacementMode: TypeReplacementMode = + if (shouldUseImplementors) TypeReplacementMode.KnownImplementor else TypeReplacementMode.NoImplementors + + /** + * Replaces an interface type with its implementor type + * if there is the unique implementor in bean definitions. + */ + override fun replaceTypeIfNeeded(type: RefType): ClassId? = + if (type.isAbstractType) { + springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) } + } else { + null + } + + override fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = false + + /** + * In Spring applications we can mark as speculatively not null + * fields if they are mocked and injecting into class under test so on. + * + * Fields are not mocked if their actual type is obtained from [springInjectedClasses]. + * + */ + override fun speculativelyCannotProduceNullPointerException( + field: SootField, + classUnderTest: ClassId, + ): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in allInjectedTypes + + override fun preventsFurtherTestGeneration(): Boolean = + super.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false + + override fun getErrors(): List = + springContextLoadingResult?.exceptions?.map { exception -> + UtError( + "Failed to load Spring application context", + exception + ) + }.orEmpty() + super.getErrors() + + fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> + // some bean classes may fail to load + runCatching { + val beanClass = ClassId(beanDef.beanTypeName).jClass + classId.jClass.isAssignableFrom(beanClass) + }.getOrElse { false } + } +} \ No newline at end of file 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 ba78166b30..5bd87ea982 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 @@ -25,6 +25,8 @@ import org.utbot.framework.UtSettings.checkSolverTimeoutMillis import org.utbot.framework.UtSettings.disableCoroutinesDebug import org.utbot.framework.UtSettings.utBotGenerationTimeoutInMillis import org.utbot.framework.UtSettings.warmupConcreteExecution +import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.SpringApplicationContext import org.utbot.framework.plugin.api.utils.checkFrameworkDependencies import org.utbot.framework.minimization.minimizeTestCase import org.utbot.framework.plugin.api.util.SpringModelUtils.entityClassIds 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 ead8820553..ae1fdd32c1 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 @@ -18,6 +18,7 @@ import org.utbot.framework.codegen.generator.CodeGenerator import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.codegen.reports.TestsGenerationReport import org.utbot.framework.codegen.services.language.CgLanguageAssistant +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.MethodDescription import org.utbot.framework.plugin.api.util.UtContext 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 cd8524ceeb..fe18e24719 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 @@ -48,6 +48,8 @@ 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.context.ApplicationContext +import org.utbot.framework.context.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* 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 b6fdbf62a2..221cacad88 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 @@ -17,6 +17,7 @@ import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.common.* import org.utbot.framework.UtSettings import org.utbot.framework.codegen.tree.ututils.UtilClassKind +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.BeanAdditionalData import org.utbot.framework.plugin.api.BeanDefinitionData diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt index 1e9c66f417..6a503bc304 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt @@ -2,7 +2,6 @@ package org.utbot.testing import mu.KotlinLogging import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue import org.utbot.common.FileUtil import org.utbot.common.measureTime import org.utbot.common.info @@ -17,6 +16,7 @@ import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.codegen.services.language.CgLanguageAssistant 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.context.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.description From bf63dd2d39e3228d9cc0cf5b30f6005644b67f6a Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 10:59:25 +0300 Subject: [PATCH 02/20] Merge `avoidSpeculativeNotNullChecks` and `speculativelyCannotProduceNullPointerException` into one method --- .../src/main/kotlin/org/utbot/engine/Traverser.kt | 8 ++------ .../utbot/framework/context/ApplicationContext.kt | 14 ++++---------- .../framework/context/SpringApplicationContext.kt | 2 -- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index 102050e024..91f2efe7c4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -2336,12 +2336,8 @@ class Traverser( * See more detailed documentation in [ApplicationContext] mentioned methods. */ private fun checkAndMarkLibraryFieldSpeculativelyNotNull(field: SootField, createdField: SymbolicValue) { - if (applicationContext.avoidSpeculativeNotNullChecks(field) || - !applicationContext.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId)) { - return - } - - markAsSpeculativelyNotNull(createdField.addr) + if (applicationContext.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId)) + markAsSpeculativelyNotNull(createdField.addr) } private fun createArray(pName: String, type: ArrayType): ArrayValue { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index 28f54155df..f7f50be9e0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -49,15 +49,6 @@ open class ApplicationContext( */ open fun replaceTypeIfNeeded(type: RefType): ClassId? = null - /** - * Sets the restrictions on speculative not null - * constraints in current application context. - * - * @see docs/SpeculativeFieldNonNullability.md for more information. - */ - open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = - UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary() - /** * Checks whether accessing [field] (with a method invocation or field access) speculatively * cannot produce [NullPointerException] (according to its finality or accessibility). @@ -67,7 +58,10 @@ open class ApplicationContext( open fun speculativelyCannotProduceNullPointerException( field: SootField, classUnderTest: ClassId, - ): Boolean = field.isFinal || !field.isPublic + ): Boolean = + !UtSettings.maximizeCoverageUsingReflection && + field.declaringClass.isFromTrustedLibrary() && + (field.isFinal || !field.isPublic) open fun preventsFurtherTestGeneration(): Boolean = false diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt index adae9ea3be..ccf2b1b2cd 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt @@ -123,8 +123,6 @@ class SpringApplicationContext( null } - override fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = false - /** * In Spring applications we can mark as speculatively not null * fields if they are mocked and injecting into class under test so on. From eae27de270d8acbf6a6e922cb5c8caf3fe0fcb9b Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 11:09:49 +0300 Subject: [PATCH 03/20] Extract `ApplicationContext` interface --- .../framework/context/ApplicationContext.kt | 48 +++------------- .../context/SimpleApplicationContext.kt | 55 +++++++++++++++++++ .../context/SpringApplicationContext.kt | 9 ++- .../framework/plugin/api/TestCaseGenerator.kt | 3 +- .../generator/UtTestsDialogProcessor.kt | 7 ++- .../testing/TestCodeGeneratorPipeline.kt | 1 - 6 files changed, 74 insertions(+), 49 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index f7f50be9e0..22dee50a0e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,7 +1,5 @@ package org.utbot.framework.context -import org.utbot.framework.UtSettings -import org.utbot.framework.isFromTrustedLibrary import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodeGenerationContext import org.utbot.framework.plugin.api.TypeReplacementMode @@ -9,45 +7,20 @@ import org.utbot.framework.plugin.api.UtError import soot.RefType import soot.SootField -/** - * A context to use when no specific data is required. - * - * @param mockFrameworkInstalled shows if we have installed framework dependencies - * @param staticsMockingIsConfigured shows if we have installed static mocking tools - */ -open class ApplicationContext( - val mockFrameworkInstalled: Boolean = true, - staticsMockingIsConfigured: Boolean = true, -) : CodeGenerationContext { - var staticsMockingIsConfigured = staticsMockingIsConfigured - private set - - init { - /** - * Situation when mock framework is not installed but static mocking is configured is semantically incorrect. - * - * However, it may be obtained in real application after this actions: - * - fully configure mocking (dependency installed + resource file created) - * - remove mockito-core dependency from project - * - forget to remove mock-maker file from resource directory - * - * Here we transform this configuration to semantically correct. - */ - if (!mockFrameworkInstalled && staticsMockingIsConfigured) { - this.staticsMockingIsConfigured = false - } - } +interface ApplicationContext : CodeGenerationContext { + val mockFrameworkInstalled: Boolean + val staticsMockingIsConfigured: Boolean /** * Shows if there are any restrictions on type implementors. */ - open val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor + val typeReplacementMode: TypeReplacementMode /** * Finds a type to replace the original abstract type * if it is guided with some additional information. */ - open fun replaceTypeIfNeeded(type: RefType): ClassId? = null + fun replaceTypeIfNeeded(type: RefType): ClassId? /** * Checks whether accessing [field] (with a method invocation or field access) speculatively @@ -55,15 +28,12 @@ open class ApplicationContext( * * @see docs/SpeculativeFieldNonNullability.md for more information. */ - open fun speculativelyCannotProduceNullPointerException( + fun speculativelyCannotProduceNullPointerException( field: SootField, classUnderTest: ClassId, - ): Boolean = - !UtSettings.maximizeCoverageUsingReflection && - field.declaringClass.isFromTrustedLibrary() && - (field.isFinal || !field.isPublic) + ): Boolean - open fun preventsFurtherTestGeneration(): Boolean = false + fun preventsFurtherTestGeneration(): Boolean - open fun getErrors(): List = emptyList() + fun getErrors(): List } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt new file mode 100644 index 0000000000..623b95a3cb --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt @@ -0,0 +1,55 @@ +package org.utbot.framework.context + +import org.utbot.framework.UtSettings +import org.utbot.framework.isFromTrustedLibrary +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.TypeReplacementMode +import org.utbot.framework.plugin.api.UtError +import soot.RefType +import soot.SootField + +/** + * A context to use when no specific data is required. + * + * @param mockFrameworkInstalled shows if we have installed framework dependencies + * @param staticsMockingIsConfigured shows if we have installed static mocking tools + */ +class SimpleApplicationContext( + override val mockFrameworkInstalled: Boolean = true, + staticsMockingIsConfigured: Boolean = true, +) : ApplicationContext { + override var staticsMockingIsConfigured = staticsMockingIsConfigured + private set + + init { + /** + * Situation when mock framework is not installed but static mocking is configured is semantically incorrect. + * + * However, it may be obtained in real application after this actions: + * - fully configure mocking (dependency installed + resource file created) + * - remove mockito-core dependency from project + * - forget to remove mock-maker file from resource directory + * + * Here we transform this configuration to semantically correct. + */ + if (!mockFrameworkInstalled && staticsMockingIsConfigured) { + this.staticsMockingIsConfigured = false + } + } + + override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor + + override fun replaceTypeIfNeeded(type: RefType): ClassId? = null + + override fun speculativelyCannotProduceNullPointerException( + field: SootField, + classUnderTest: ClassId, + ): Boolean = + !UtSettings.maximizeCoverageUsingReflection && + field.declaringClass.isFromTrustedLibrary() && + (field.isFinal || !field.isPublic) + + override fun preventsFurtherTestGeneration(): Boolean = false + + override fun getErrors(): List = emptyList() +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt index ccf2b1b2cd..2b80dd52d6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt @@ -41,13 +41,12 @@ import soot.SootField // Right now this refactoring is blocked because some interfaces need to get extracted and moved to utbot-framework-api // As an alternative we can just move ApplicationContext itself to utbot-framework class SpringApplicationContext( - mockInstalled: Boolean, - staticsMockingIsConfigured: Boolean, + private val delegateContext: ApplicationContext, val beanDefinitions: List = emptyList(), private val shouldUseImplementors: Boolean, override val springTestType: SpringTestType, override val springSettings: SpringSettings, -): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext { +): ApplicationContext by delegateContext, SpringCodeGenerationContext { override var springContextLoadingResult: SpringContextLoadingResult? = null @@ -136,7 +135,7 @@ class SpringApplicationContext( ): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in allInjectedTypes override fun preventsFurtherTestGeneration(): Boolean = - super.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false + delegateContext.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false override fun getErrors(): List = springContextLoadingResult?.exceptions?.map { exception -> @@ -144,7 +143,7 @@ class SpringApplicationContext( "Failed to load Spring application context", exception ) - }.orEmpty() + super.getErrors() + }.orEmpty() + delegateContext.getErrors() fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> // some bean classes may fail to load 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 5bd87ea982..bc9e9bdf45 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 @@ -26,6 +26,7 @@ import org.utbot.framework.UtSettings.disableCoroutinesDebug import org.utbot.framework.UtSettings.utBotGenerationTimeoutInMillis import org.utbot.framework.UtSettings.warmupConcreteExecution import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.SimpleApplicationContext import org.utbot.framework.context.SpringApplicationContext import org.utbot.framework.plugin.api.utils.checkFrameworkDependencies import org.utbot.framework.minimization.minimizeTestCase @@ -70,7 +71,7 @@ open class TestCaseGenerator( val engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(), val isCanceled: () -> Boolean = { false }, val forceSootReload: Boolean = true, - val applicationContext: ApplicationContext = ApplicationContext(), + val applicationContext: ApplicationContext = SimpleApplicationContext(), ) { private val logger: KLogger = KotlinLogging.logger {} private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout") 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 fe18e24719..c7dd9223fd 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,6 +49,7 @@ import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS import org.utbot.framework.UtSettings import org.utbot.framework.codegen.domain.ProjectType.* import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.SimpleApplicationContext import org.utbot.framework.context.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.SpringSettings.* @@ -262,6 +263,7 @@ object UtTestsDialogProcessor { process.terminateOnException { _ -> val classpathForClassLoader = buildDirs + classpathList process.setupUtContext(classpathForClassLoader) + val simpleApplicationContext = SimpleApplicationContext(mockFrameworkInstalled, staticMockingConfigured) val applicationContext = when (model.projectType) { Spring -> { val beanDefinitions = @@ -281,15 +283,14 @@ object UtTestsDialogProcessor { clarifyBeanDefinitionReturnTypes(beanDefinitions, project) SpringApplicationContext( - mockFrameworkInstalled, - staticMockingConfigured, + simpleApplicationContext, clarifiedBeanDefinitions, shouldUseImplementors, model.springTestType, model.springSettings, ) } - else -> ApplicationContext(mockFrameworkInstalled, staticMockingConfigured) + else -> simpleApplicationContext } process.createTestGenerator( buildDirs, diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt index 6a503bc304..9f51ad1582 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt @@ -16,7 +16,6 @@ import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.codegen.services.language.CgLanguageAssistant 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.context.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.description From a3677ccf0ac3e50a67d4d675791eda88f19ec266 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 11:53:14 +0300 Subject: [PATCH 04/20] Extract `MockerContext` interface --- .../src/main/kotlin/org/utbot/engine/Mocks.kt | 8 +++--- .../org/utbot/engine/UtBotSymbolicEngine.kt | 2 +- .../framework/context/ApplicationContext.kt | 4 +-- .../context/SimpleApplicationContext.kt | 26 ++----------------- .../framework/context/mocker/MockerContext.kt | 13 ++++++++++ .../context/mocker/SimpleMockerContext.kt | 14 ++++++++++ .../generator/UtTestsDialogProcessor.kt | 5 +++- 7 files changed, 40 insertions(+), 32 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt index bf81618295..a6ff1cfba7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt @@ -19,7 +19,7 @@ import kotlinx.collections.immutable.persistentListOf import org.utbot.common.nameOfPackage import org.utbot.engine.types.OBJECT_TYPE import org.utbot.engine.util.mockListeners.MockListenerController -import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.mocker.MockerContext import org.utbot.framework.plugin.api.util.isInaccessibleViaReflection import soot.BooleanType import soot.RefType @@ -168,7 +168,7 @@ class Mocker( private val hierarchy: Hierarchy, chosenClassesToMockAlways: Set, internal val mockListenerController: MockListenerController? = null, - private val applicationContext: ApplicationContext, + private val mockerContext: MockerContext, ) { private val mocksAreDesired: Boolean = strategy != MockStrategy.NO_MOCKS @@ -227,10 +227,10 @@ class Mocker( val mockingIsPossible = when (mockInfo) { is UtFieldMockInfo, - is UtObjectMockInfo -> applicationContext.mockFrameworkInstalled + is UtObjectMockInfo -> mockerContext.mockFrameworkInstalled is UtNewInstanceMockInfo, is UtStaticMethodMockInfo, - is UtStaticObjectMockInfo -> applicationContext.staticsMockingIsConfigured + is UtStaticObjectMockInfo -> mockerContext.staticsMockingIsConfigured } val mockingIsForcedAndPossible = mockAlways(mockedValue.type) && mockingIsPossible 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 71fd896bad..5dec551e70 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -143,7 +143,7 @@ class UtBotSymbolicEngine( hierarchy, chosenClassesToMockAlways, MockListenerController(controller), - applicationContext = applicationContext, + mockerContext = applicationContext.mockerContext, ) fun attachMockListener(mockListener: MockListener) = mocker.mockListenerController?.attach(mockListener) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index 22dee50a0e..b23b0ccb2e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,5 +1,6 @@ package org.utbot.framework.context +import org.utbot.framework.context.mocker.MockerContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodeGenerationContext import org.utbot.framework.plugin.api.TypeReplacementMode @@ -8,8 +9,7 @@ import soot.RefType import soot.SootField interface ApplicationContext : CodeGenerationContext { - val mockFrameworkInstalled: Boolean - val staticsMockingIsConfigured: Boolean + val mockerContext: MockerContext /** * Shows if there are any restrictions on type implementors. diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt index 623b95a3cb..00908b46f2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt @@ -1,6 +1,7 @@ package org.utbot.framework.context import org.utbot.framework.UtSettings +import org.utbot.framework.context.mocker.MockerContext import org.utbot.framework.isFromTrustedLibrary import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeReplacementMode @@ -10,33 +11,10 @@ import soot.SootField /** * A context to use when no specific data is required. - * - * @param mockFrameworkInstalled shows if we have installed framework dependencies - * @param staticsMockingIsConfigured shows if we have installed static mocking tools */ class SimpleApplicationContext( - override val mockFrameworkInstalled: Boolean = true, - staticsMockingIsConfigured: Boolean = true, + override val mockerContext: MockerContext ) : ApplicationContext { - override var staticsMockingIsConfigured = staticsMockingIsConfigured - private set - - init { - /** - * Situation when mock framework is not installed but static mocking is configured is semantically incorrect. - * - * However, it may be obtained in real application after this actions: - * - fully configure mocking (dependency installed + resource file created) - * - remove mockito-core dependency from project - * - forget to remove mock-maker file from resource directory - * - * Here we transform this configuration to semantically correct. - */ - if (!mockFrameworkInstalled && staticsMockingIsConfigured) { - this.staticsMockingIsConfigured = false - } - } - override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor override fun replaceTypeIfNeeded(type: RefType): ClassId? = null diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt new file mode 100644 index 0000000000..ab5defefb8 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt @@ -0,0 +1,13 @@ +package org.utbot.framework.context.mocker + +interface MockerContext { + /** + * Shows if we have installed framework dependencies + */ + val mockFrameworkInstalled: Boolean + + /** + * Shows if we have installed static mocking tools + */ + val staticsMockingIsConfigured: Boolean +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt new file mode 100644 index 0000000000..0e9a8b6f27 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt @@ -0,0 +1,14 @@ +package org.utbot.framework.context.mocker + +class SimpleMockerContext( + override val mockFrameworkInstalled: Boolean, + staticsMockingIsConfigured: Boolean +) : MockerContext { + /** + * NOTE: Can only be `true` when [mockFrameworkInstalled], because + * situation when mock framework is not installed but static mocking + * is configured is semantically incorrect. + */ + override val staticsMockingIsConfigured: Boolean = + mockFrameworkInstalled && staticsMockingIsConfigured +} \ No newline at end of file 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 c7dd9223fd..98f7fca692 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 @@ -51,6 +51,7 @@ import org.utbot.framework.codegen.domain.ProjectType.* import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.SimpleApplicationContext import org.utbot.framework.context.SpringApplicationContext +import org.utbot.framework.context.mocker.SimpleMockerContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* @@ -263,7 +264,9 @@ object UtTestsDialogProcessor { process.terminateOnException { _ -> val classpathForClassLoader = buildDirs + classpathList process.setupUtContext(classpathForClassLoader) - val simpleApplicationContext = SimpleApplicationContext(mockFrameworkInstalled, staticMockingConfigured) + val simpleApplicationContext = SimpleApplicationContext( + SimpleMockerContext(mockFrameworkInstalled, staticMockingConfigured) + ) val applicationContext = when (model.projectType) { Spring -> { val beanDefinitions = From dca31f119daf9a1cdfd5269ee2f0926ea04a8d0c Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 11:57:21 +0300 Subject: [PATCH 05/20] Configure default `ApplicationContext` for `TestCaseGenerator` --- .../org/utbot/framework/plugin/api/TestCaseGenerator.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 bc9e9bdf45..b0082ff979 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 @@ -71,7 +71,12 @@ open class TestCaseGenerator( val engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(), val isCanceled: () -> Boolean = { false }, val forceSootReload: Boolean = true, - val applicationContext: ApplicationContext = SimpleApplicationContext(), + val applicationContext: ApplicationContext = SimpleApplicationContext( + SimpleMockerContext( + mockFrameworkInstalled = true, + staticsMockingIsConfigured = true + ) + ), ) { private val logger: KLogger = KotlinLogging.logger {} private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout") From 444212ae28f339733fd9b231aa32964e39888361 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 12:13:44 +0300 Subject: [PATCH 06/20] Group contexts in packages by their kind (simple and Spring) --- utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt | 2 +- .../main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt | 2 +- .../org/utbot/framework/context/ApplicationContext.kt | 1 - .../utbot/framework/context/{mocker => }/MockerContext.kt | 2 +- .../context/{ => simple}/SimpleApplicationContext.kt | 5 +++-- .../context/{mocker => simple}/SimpleMockerContext.kt | 4 +++- .../context/{ => spring}/SpringApplicationContext.kt | 3 ++- .../org/utbot/framework/plugin/api/TestCaseGenerator.kt | 5 +++-- .../intellij/plugin/generator/UtTestsDialogProcessor.kt | 7 +++---- 9 files changed, 17 insertions(+), 14 deletions(-) rename utbot-framework/src/main/kotlin/org/utbot/framework/context/{mocker => }/MockerContext.kt (85%) rename utbot-framework/src/main/kotlin/org/utbot/framework/context/{ => simple}/SimpleApplicationContext.kt (87%) rename utbot-framework/src/main/kotlin/org/utbot/framework/context/{mocker => simple}/SimpleMockerContext.kt (83%) rename utbot-framework/src/main/kotlin/org/utbot/framework/context/{ => spring}/SpringApplicationContext.kt (98%) diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt index a6ff1cfba7..9faf511ab6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt @@ -19,7 +19,7 @@ import kotlinx.collections.immutable.persistentListOf import org.utbot.common.nameOfPackage import org.utbot.engine.types.OBJECT_TYPE import org.utbot.engine.util.mockListeners.MockListenerController -import org.utbot.framework.context.mocker.MockerContext +import org.utbot.framework.context.MockerContext import org.utbot.framework.plugin.api.util.isInaccessibleViaReflection import soot.BooleanType import soot.RefType 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 5dec551e70..a2f3522b7d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -34,7 +34,7 @@ import org.utbot.framework.UtSettings.pathSelectorType import org.utbot.framework.UtSettings.processUnknownStatesDuringConcreteExecution import org.utbot.framework.UtSettings.useDebugVisualization import org.utbot.framework.context.ApplicationContext -import org.utbot.framework.context.SpringApplicationContext +import org.utbot.framework.context.spring.SpringApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.Step import org.utbot.framework.plugin.api.util.* diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index b23b0ccb2e..821333f592 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,6 +1,5 @@ package org.utbot.framework.context -import org.utbot.framework.context.mocker.MockerContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodeGenerationContext import org.utbot.framework.plugin.api.TypeReplacementMode diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/MockerContext.kt similarity index 85% rename from utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/context/MockerContext.kt index ab5defefb8..a85f591f5d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/MockerContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/MockerContext.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.context.mocker +package org.utbot.framework.context interface MockerContext { /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt similarity index 87% rename from utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt index 00908b46f2..8348ea8d3f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt @@ -1,7 +1,8 @@ -package org.utbot.framework.context +package org.utbot.framework.context.simple import org.utbot.framework.UtSettings -import org.utbot.framework.context.mocker.MockerContext +import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.MockerContext import org.utbot.framework.isFromTrustedLibrary import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeReplacementMode diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleMockerContext.kt similarity index 83% rename from utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleMockerContext.kt index 0e9a8b6f27..e7b0977d9e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/mocker/SimpleMockerContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleMockerContext.kt @@ -1,4 +1,6 @@ -package org.utbot.framework.context.mocker +package org.utbot.framework.context.simple + +import org.utbot.framework.context.MockerContext class SimpleMockerContext( override val mockFrameworkInstalled: Boolean, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt index 2b80dd52d6..df32770b24 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt @@ -1,8 +1,9 @@ -package org.utbot.framework.context +package org.utbot.framework.context.spring import mu.KotlinLogging import org.utbot.common.isAbstract import org.utbot.common.isStatic +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringCodeGenerationContext 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 b0082ff979..2af6cda9c0 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 @@ -26,8 +26,9 @@ import org.utbot.framework.UtSettings.disableCoroutinesDebug import org.utbot.framework.UtSettings.utBotGenerationTimeoutInMillis import org.utbot.framework.UtSettings.warmupConcreteExecution import org.utbot.framework.context.ApplicationContext -import org.utbot.framework.context.SimpleApplicationContext -import org.utbot.framework.context.SpringApplicationContext +import org.utbot.framework.context.simple.SimpleApplicationContext +import org.utbot.framework.context.simple.SimpleMockerContext +import org.utbot.framework.context.spring.SpringApplicationContext import org.utbot.framework.plugin.api.utils.checkFrameworkDependencies import org.utbot.framework.minimization.minimizeTestCase import org.utbot.framework.plugin.api.util.SpringModelUtils.entityClassIds 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 98f7fca692..c8038a3c99 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 @@ -48,10 +48,9 @@ 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.context.ApplicationContext -import org.utbot.framework.context.SimpleApplicationContext -import org.utbot.framework.context.SpringApplicationContext -import org.utbot.framework.context.mocker.SimpleMockerContext +import org.utbot.framework.context.simple.SimpleApplicationContext +import org.utbot.framework.context.spring.SpringApplicationContext +import org.utbot.framework.context.simple.SimpleMockerContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* From 810d2c8107fd9406923b009fef857aca76197a89 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 14:25:31 +0300 Subject: [PATCH 07/20] Extract `TypeReplacer` and `NonNullSpeculator`, replace `shouldUseImplementors` with `beanDefinitions.isNotEmpty()` --- .../main/kotlin/org/utbot/engine/Traverser.kt | 13 +- .../org/utbot/engine/UtBotSymbolicEngine.kt | 3 +- .../framework/context/ApplicationContext.kt | 28 +--- .../framework/context/NonNullSpeculator.kt | 17 ++ .../utbot/framework/context/TypeReplacer.kt | 18 +++ .../simple/SimpleApplicationContext.kt | 23 +-- .../context/simple/SimpleNonNullSpeculator.kt | 17 ++ .../context/simple/SimpleTypeReplacer.kt | 12 ++ .../spring/SpringApplicationContext.kt | 148 +----------------- .../spring/SpringApplicationContextImpl.kt | 102 ++++++++++++ .../context/spring/SpringNonNullSpeculator.kt | 19 +++ .../context/spring/SpringTypeReplacer.kt | 26 +++ .../generator/UtTestsDialogProcessor.kt | 7 +- 13 files changed, 238 insertions(+), 195 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/NonNullSpeculator.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleNonNullSpeculator.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index 91f2efe7c4..38c7e71d65 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -117,6 +117,8 @@ import org.utbot.framework.UtSettings.preferredCexOption import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable import org.utbot.framework.isFromTrustedLibrary import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.NonNullSpeculator +import org.utbot.framework.context.TypeReplacer import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.FieldId @@ -239,7 +241,8 @@ class Traverser( internal val typeResolver: TypeResolver, private val globalGraph: InterProceduralUnitGraph, private val mocker: Mocker, - private val applicationContext: ApplicationContext, + private val typeReplacer: TypeReplacer, + private val nonNullSpeculator: NonNullSpeculator, private val taintContext: TaintContext, ) : UtContextInitializer() { @@ -1393,8 +1396,8 @@ class Traverser( // However, if we have the restriction on implementor type (it may be obtained // from Spring bean definitions, for example), we can just create a symbolic object // with hard constraint on the mentioned type. - val replacedClassId = when (applicationContext.typeReplacementMode) { - KnownImplementor -> applicationContext.replaceTypeIfNeeded(type) + val replacedClassId = when (typeReplacer.typeReplacementMode) { + KnownImplementor -> typeReplacer.replaceTypeIfNeeded(type) AnyImplementor, NoImplementors -> null } @@ -1512,7 +1515,7 @@ class Traverser( return createMockedObject(addr, type, mockInfoGenerator, nullEqualityConstraint) } - val concreteImplementation: Concrete? = when (applicationContext.typeReplacementMode) { + val concreteImplementation: Concrete? = when (typeReplacer.typeReplacementMode) { AnyImplementor -> findConcreteImplementation(addr, type, typeHardConstraint) // If our type is not abstract, both in `KnownImplementors` and `NoImplementors` mode, @@ -2336,7 +2339,7 @@ class Traverser( * See more detailed documentation in [ApplicationContext] mentioned methods. */ private fun checkAndMarkLibraryFieldSpeculativelyNotNull(field: SootField, createdField: SymbolicValue) { - if (applicationContext.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId)) + if (nonNullSpeculator.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId)) markAsSpeculativelyNotNull(createdField.addr) } 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 a2f3522b7d..c322c69887 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -179,7 +179,8 @@ class UtBotSymbolicEngine( typeResolver, globalGraph, mocker, - applicationContext, + applicationContext.typeReplacer, + applicationContext.nonNullSpeculator, taintContext, ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index 821333f592..42b3b97450 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,36 +1,12 @@ package org.utbot.framework.context -import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodeGenerationContext -import org.utbot.framework.plugin.api.TypeReplacementMode import org.utbot.framework.plugin.api.UtError -import soot.RefType -import soot.SootField interface ApplicationContext : CodeGenerationContext { val mockerContext: MockerContext - - /** - * Shows if there are any restrictions on type implementors. - */ - val typeReplacementMode: TypeReplacementMode - - /** - * Finds a type to replace the original abstract type - * if it is guided with some additional information. - */ - fun replaceTypeIfNeeded(type: RefType): ClassId? - - /** - * Checks whether accessing [field] (with a method invocation or field access) speculatively - * cannot produce [NullPointerException] (according to its finality or accessibility). - * - * @see docs/SpeculativeFieldNonNullability.md for more information. - */ - fun speculativelyCannotProduceNullPointerException( - field: SootField, - classUnderTest: ClassId, - ): Boolean + val typeReplacer: TypeReplacer + val nonNullSpeculator: NonNullSpeculator fun preventsFurtherTestGeneration(): Boolean diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/NonNullSpeculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/NonNullSpeculator.kt new file mode 100644 index 0000000000..3c4830cd45 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/NonNullSpeculator.kt @@ -0,0 +1,17 @@ +package org.utbot.framework.context + +import org.utbot.framework.plugin.api.ClassId +import soot.SootField + +interface NonNullSpeculator { + /** + * Checks whether accessing [field] (with a method invocation or field access) speculatively + * cannot produce [NullPointerException] (according to its finality or accessibility). + * + * @see docs/SpeculativeFieldNonNullability.md for more information. + */ + fun speculativelyCannotProduceNullPointerException( + field: SootField, + classUnderTest: ClassId, + ): Boolean +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt new file mode 100644 index 0000000000..52c3ee8604 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt @@ -0,0 +1,18 @@ +package org.utbot.framework.context + +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.TypeReplacementMode +import soot.RefType + +interface TypeReplacer { + /** + * Shows if there are any restrictions on type implementors. + */ + val typeReplacementMode: TypeReplacementMode + + /** + * Finds a type to replace the original abstract type + * if it is guided with some additional information. + */ + fun replaceTypeIfNeeded(type: RefType): ClassId? +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt index 8348ea8d3f..b79b45876b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt @@ -1,32 +1,19 @@ package org.utbot.framework.context.simple -import org.utbot.framework.UtSettings import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.MockerContext -import org.utbot.framework.isFromTrustedLibrary -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.TypeReplacementMode +import org.utbot.framework.context.NonNullSpeculator +import org.utbot.framework.context.TypeReplacer import org.utbot.framework.plugin.api.UtError -import soot.RefType -import soot.SootField /** * A context to use when no specific data is required. */ class SimpleApplicationContext( - override val mockerContext: MockerContext + override val mockerContext: MockerContext, + override val typeReplacer: TypeReplacer = SimpleTypeReplacer(), + override val nonNullSpeculator: NonNullSpeculator = SimpleNonNullSpeculator() ) : ApplicationContext { - override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor - - override fun replaceTypeIfNeeded(type: RefType): ClassId? = null - - override fun speculativelyCannotProduceNullPointerException( - field: SootField, - classUnderTest: ClassId, - ): Boolean = - !UtSettings.maximizeCoverageUsingReflection && - field.declaringClass.isFromTrustedLibrary() && - (field.isFinal || !field.isPublic) override fun preventsFurtherTestGeneration(): Boolean = false diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleNonNullSpeculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleNonNullSpeculator.kt new file mode 100644 index 0000000000..b1b8404190 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleNonNullSpeculator.kt @@ -0,0 +1,17 @@ +package org.utbot.framework.context.simple + +import org.utbot.framework.UtSettings +import org.utbot.framework.context.NonNullSpeculator +import org.utbot.framework.isFromTrustedLibrary +import org.utbot.framework.plugin.api.ClassId +import soot.SootField + +class SimpleNonNullSpeculator : NonNullSpeculator { + override fun speculativelyCannotProduceNullPointerException( + field: SootField, + classUnderTest: ClassId, + ): Boolean = + !UtSettings.maximizeCoverageUsingReflection && + field.declaringClass.isFromTrustedLibrary() && + (field.isFinal || !field.isPublic) +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt new file mode 100644 index 0000000000..300aea86e5 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt @@ -0,0 +1,12 @@ +package org.utbot.framework.context.simple + +import org.utbot.framework.context.TypeReplacer +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.TypeReplacementMode +import soot.RefType + +class SimpleTypeReplacer : TypeReplacer { + override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor + + override fun replaceTypeIfNeeded(type: RefType): ClassId? = null +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt index df32770b24..f04002a775 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt @@ -1,156 +1,24 @@ package org.utbot.framework.context.spring -import mu.KotlinLogging -import org.utbot.common.isAbstract -import org.utbot.common.isStatic import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringCodeGenerationContext import org.utbot.framework.plugin.api.SpringContextLoadingResult -import org.utbot.framework.plugin.api.SpringSettings -import org.utbot.framework.plugin.api.SpringTestType -import org.utbot.framework.plugin.api.TypeReplacementMode -import org.utbot.framework.plugin.api.UtError -import org.utbot.framework.plugin.api.classId -import org.utbot.framework.plugin.api.id -import org.utbot.framework.plugin.api.isAbstractType -import org.utbot.framework.plugin.api.util.allDeclaredFieldIds -import org.utbot.framework.plugin.api.util.allSuperTypes -import org.utbot.framework.plugin.api.util.fieldId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.isSubtypeOf -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.utContext -import soot.RefType -import soot.SootField /** * Data we get from Spring application context * to manage engine and code generator behaviour. - * - * @param beanDefinitions describes bean definitions (bean name, type, some optional additional data) - * @param shouldUseImplementors describes it we want to replace interfaces with injected types or not */ -// TODO move this class to utbot-framework so we can use it as abstract factory -// to get rid of numerous `when`s and polymorphically create things like: -// - Instrumentation -// - FuzzedType (to get rid of thisInstanceFuzzedTypeWrapper) -// - JavaValueProvider -// - CgVariableConstructor -// - CodeGeneratorResult (generateForSpringClass) -// Right now this refactoring is blocked because some interfaces need to get extracted and moved to utbot-framework-api -// As an alternative we can just move ApplicationContext itself to utbot-framework -class SpringApplicationContext( - private val delegateContext: ApplicationContext, - val beanDefinitions: List = emptyList(), - private val shouldUseImplementors: Boolean, - override val springTestType: SpringTestType, - override val springSettings: SpringSettings, -): ApplicationContext by delegateContext, SpringCodeGenerationContext { - - override var springContextLoadingResult: SpringContextLoadingResult? = null - - companion object { - private val logger = KotlinLogging.logger {} - } - - private var areInjectedClassesInitialized : Boolean = false - private var areAllInjectedTypesInitialized: Boolean = false - - // Classes representing concrete types that are actually used in Spring application - private val springInjectedClasses: Set - get() { - if (!areInjectedClassesInitialized) { - for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { - try { - val beanClass = utContext.classLoader.loadClass(beanTypeName) - if (!beanClass.isAbstract && !beanClass.isInterface && - !beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) { - springInjectedClassesStorage += beanClass.id - } - } catch (e: Throwable) { - // For some Spring beans (e.g. with anonymous classes) - // 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 $beanTypeName (${e.message})" } - - else -> throw e - } - } - } - - // This is done to be sure that this storage is not empty after the first class loading iteration. - // So, even if all loaded classes were filtered out, we will not try to load them again. - areInjectedClassesInitialized = true - } - - return springInjectedClassesStorage - } - - private val allInjectedTypes: Set - get() { - if (!areAllInjectedTypesInitialized) { - allInjectedTypesStorage = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet() - areAllInjectedTypesInitialized = true - } - - return allInjectedTypesStorage - } - - // imitates `by lazy` (we can't use actual `by lazy` because communication via RD breaks it) - private var allInjectedTypesStorage: Set = emptySet() - - // This is a service field to model the lazy behavior of [springInjectedClasses]. - // Do not call it outside the getter. - // - // Actually, we should just call [springInjectedClasses] with `by lazy`, but we had problems - // with a strange `kotlin.UNINITIALIZED_VALUE` in `speculativelyCannotProduceNullPointerException` method call. - private val springInjectedClassesStorage = mutableSetOf() - - override val typeReplacementMode: TypeReplacementMode = - if (shouldUseImplementors) TypeReplacementMode.KnownImplementor else TypeReplacementMode.NoImplementors - +// TODO #2358 +interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationContext { /** - * Replaces an interface type with its implementor type - * if there is the unique implementor in bean definitions. + * Describes bean definitions (bean name, type, some optional additional data) */ - override fun replaceTypeIfNeeded(type: RefType): ClassId? = - if (type.isAbstractType) { - springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) } - } else { - null - } - - /** - * In Spring applications we can mark as speculatively not null - * fields if they are mocked and injecting into class under test so on. - * - * Fields are not mocked if their actual type is obtained from [springInjectedClasses]. - * - */ - override fun speculativelyCannotProduceNullPointerException( - field: SootField, - classUnderTest: ClassId, - ): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in allInjectedTypes - - override fun preventsFurtherTestGeneration(): Boolean = - delegateContext.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false - - override fun getErrors(): List = - springContextLoadingResult?.exceptions?.map { exception -> - UtError( - "Failed to load Spring application context", - exception - ) - }.orEmpty() + delegateContext.getErrors() + val beanDefinitions: List + val springInjectedClasses: Set + val allInjectedTypes: Set - fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> - // some bean classes may fail to load - runCatching { - val beanClass = ClassId(beanDef.beanTypeName).jClass - classId.jClass.isAssignableFrom(beanClass) - }.getOrElse { false } - } + override var springContextLoadingResult: SpringContextLoadingResult? + fun getBeansAssignableTo(classId: ClassId): List } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt new file mode 100644 index 0000000000..376cd58cee --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -0,0 +1,102 @@ +package org.utbot.framework.context.spring + +import mu.KotlinLogging +import org.utbot.common.isAbstract +import org.utbot.common.isStatic +import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.NonNullSpeculator +import org.utbot.framework.context.TypeReplacer +import org.utbot.framework.plugin.api.BeanDefinitionData +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.SpringTestType +import org.utbot.framework.plugin.api.UtError +import org.utbot.framework.plugin.api.util.allSuperTypes +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.jClass +import org.utbot.framework.plugin.api.util.utContext + +class SpringApplicationContextImpl( + private val delegateContext: ApplicationContext, + override val beanDefinitions: List = emptyList(), + override val springTestType: SpringTestType, + override val springSettings: SpringSettings, +): ApplicationContext by delegateContext, SpringApplicationContext { + companion object { + private val logger = KotlinLogging.logger {} + } + + override val typeReplacer: TypeReplacer = SpringTypeReplacer(delegateContext.typeReplacer, this) + override val nonNullSpeculator: NonNullSpeculator = SpringNonNullSpeculator(delegateContext.nonNullSpeculator, this) + + override var springContextLoadingResult: SpringContextLoadingResult? = null + + override fun preventsFurtherTestGeneration(): Boolean = + delegateContext.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false + + override fun getErrors(): List = + springContextLoadingResult?.exceptions?.map { exception -> + UtError( + "Failed to load Spring application context", + exception + ) + }.orEmpty() + delegateContext.getErrors() + + override fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> + // some bean classes may fail to load + runCatching { + val beanClass = ClassId(beanDef.beanTypeName).jClass + classId.jClass.isAssignableFrom(beanClass) + }.getOrElse { false } + } + + // Classes representing concrete types that are actually used in Spring application + override val springInjectedClasses: Set + get() { + if (!areAllInjectedSuperTypesInitialized) { + for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { + try { + val beanClass = utContext.classLoader.loadClass(beanTypeName) + if (!beanClass.isAbstract && !beanClass.isInterface && + !beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) { + _injectedTypes += beanClass.id + } + } catch (e: Throwable) { + // For some Spring beans (e.g. with anonymous classes) + // 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 $beanTypeName (${e.message})" } + + else -> throw e + } + } + } + + // This is done to be sure that this storage is not empty after the first class loading iteration. + // So, even if all loaded classes were filtered out, we will not try to load them again. + areAllInjectedSuperTypesInitialized = true + } + + return _injectedTypes + } + + override val allInjectedTypes: Set + get() { + if (!areInjectedTypesInitialized) { + _allInjectedSuperTypes = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet() + areInjectedTypesInitialized = true + } + + return _allInjectedSuperTypes + } + + // the following properties help to imitate `by lazy` behaviour, do not use them directly + // (we can't use actual `by lazy` because communication via RD breaks it) + private var _allInjectedSuperTypes: Set = emptySet() + private var areAllInjectedSuperTypesInitialized : Boolean = false + + private val _injectedTypes = mutableSetOf() + private var areInjectedTypesInitialized: Boolean = false +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt new file mode 100644 index 0000000000..d286dfdafe --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt @@ -0,0 +1,19 @@ +package org.utbot.framework.context.spring + +import org.utbot.framework.context.NonNullSpeculator +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.classId +import org.utbot.framework.plugin.api.util.allDeclaredFieldIds +import org.utbot.framework.plugin.api.util.fieldId +import soot.SootField + +class SpringNonNullSpeculator( + private val delegateNonNullSpeculator: NonNullSpeculator, + private val springApplicationContext: SpringApplicationContext +) : NonNullSpeculator { + override fun speculativelyCannotProduceNullPointerException(field: SootField, classUnderTest: ClassId): Boolean = + // TODO add ` || delegateNonNullSpeculator.speculativelyCannotProduceNullPointerException(field, classUnderTest)` + // (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR) + field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in springApplicationContext.allInjectedTypes + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt new file mode 100644 index 0000000000..9b476d95eb --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt @@ -0,0 +1,26 @@ +package org.utbot.framework.context.spring + +import org.utbot.framework.context.TypeReplacer +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.TypeReplacementMode +import org.utbot.framework.plugin.api.id +import org.utbot.framework.plugin.api.isAbstractType +import org.utbot.framework.plugin.api.util.isSubtypeOf +import soot.RefType + +class SpringTypeReplacer( + private val delegateTypeReplacer: TypeReplacer, + private val springApplicationContext: SpringApplicationContext +) : TypeReplacer { + override val typeReplacementMode: TypeReplacementMode = + // TODO add ` || delegateTypeReplacer.typeReplacementMode == TypeReplacementMode.KnownImplementor` + // (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR) + if (springApplicationContext.beanDefinitions.isNotEmpty()) TypeReplacementMode.KnownImplementor + else TypeReplacementMode.NoImplementors + + override fun replaceTypeIfNeeded(type: RefType): ClassId? = + // TODO add `delegateTypeReplacer.replaceTypeIfNeeded(type) ?: ` + // (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR) + if (type.isAbstractType) springApplicationContext.springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) } + else null +} \ No newline at end of file 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 c8038a3c99..16d9874643 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,8 +49,8 @@ import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS import org.utbot.framework.UtSettings import org.utbot.framework.codegen.domain.ProjectType.* import org.utbot.framework.context.simple.SimpleApplicationContext -import org.utbot.framework.context.spring.SpringApplicationContext import org.utbot.framework.context.simple.SimpleMockerContext +import org.utbot.framework.context.spring.SpringApplicationContextImpl import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* @@ -279,15 +279,12 @@ object UtTestsDialogProcessor { } } - val shouldUseImplementors = beanDefinitions.isNotEmpty() - val clarifiedBeanDefinitions = clarifyBeanDefinitionReturnTypes(beanDefinitions, project) - SpringApplicationContext( + SpringApplicationContextImpl( simpleApplicationContext, clarifiedBeanDefinitions, - shouldUseImplementors, model.springTestType, model.springSettings, ) From c7f075374c794950f39bb74cc92b053af575ab58 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 14:49:13 +0300 Subject: [PATCH 08/20] Extract `ConcreteExecutionContext` --- .../framework/context/ApplicationContext.kt | 8 +++---- .../context/ConcreteExecutionContext.kt | 15 +++++++++++++ .../simple/SimpleApplicationContext.kt | 10 ++++----- .../simple/SimpleConcreteExecutionContext.kt | 14 +++++++++++++ .../spring/SpringApplicationContextImpl.kt | 18 +++++++--------- .../spring/SpringConcreteExecutionContext.kt | 21 +++++++++++++++++++ .../framework/plugin/api/TestCaseGenerator.kt | 13 ++++++++---- 7 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index 42b3b97450..51ce384a20 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,14 +1,14 @@ package org.utbot.framework.context import org.utbot.framework.plugin.api.CodeGenerationContext -import org.utbot.framework.plugin.api.UtError interface ApplicationContext : CodeGenerationContext { val mockerContext: MockerContext val typeReplacer: TypeReplacer val nonNullSpeculator: NonNullSpeculator - fun preventsFurtherTestGeneration(): Boolean - - fun getErrors(): List + fun createConcreteExecutionContext( + fullClasspath: String, + classpathWithoutDependencies: String + ): ConcreteExecutionContext } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt new file mode 100644 index 0000000000..f5d0804435 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt @@ -0,0 +1,15 @@ +package org.utbot.framework.context + +import org.utbot.framework.plugin.api.UtError + +interface ConcreteExecutionContext { + fun preventsFurtherTestGeneration(): Boolean + + fun getErrors(): List + + // TODO refactor, so this interface only includes the following: + // val instrumentation: Instrumentation + // fun createValueProviderOrThrow(classUnderTest: ClassId, idGenerator: IdentityPreservingIdGenerator): JavaValueProvider + // fun loadContext(): ContextLoadingResult + // fun Coverage.filterCoveredInstructions(classUnderTestId: ClassId): Coverage +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt index b79b45876b..3b35ddca46 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt @@ -1,10 +1,10 @@ package org.utbot.framework.context.simple import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.context.MockerContext import org.utbot.framework.context.NonNullSpeculator import org.utbot.framework.context.TypeReplacer -import org.utbot.framework.plugin.api.UtError /** * A context to use when no specific data is required. @@ -14,8 +14,8 @@ class SimpleApplicationContext( override val typeReplacer: TypeReplacer = SimpleTypeReplacer(), override val nonNullSpeculator: NonNullSpeculator = SimpleNonNullSpeculator() ) : ApplicationContext { - - override fun preventsFurtherTestGeneration(): Boolean = false - - override fun getErrors(): List = emptyList() + override fun createConcreteExecutionContext( + fullClasspath: String, + classpathWithoutDependencies: String + ): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath, classpathWithoutDependencies) } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt new file mode 100644 index 0000000000..dc910bb3fc --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt @@ -0,0 +1,14 @@ +package org.utbot.framework.context.simple + +import org.utbot.framework.context.ConcreteExecutionContext +import org.utbot.framework.plugin.api.UtError + +class SimpleConcreteExecutionContext( + // TODO these properties will be used later (to fulfill TODO in ConcreteExecutionContext) + val fullClassPath: String, + val classpathWithoutDependencies: String +) : ConcreteExecutionContext { + override fun preventsFurtherTestGeneration(): Boolean = false + + override fun getErrors(): List = emptyList() +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 376cd58cee..cd27f602c4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -4,6 +4,7 @@ import mu.KotlinLogging import org.utbot.common.isAbstract import org.utbot.common.isStatic import org.utbot.framework.context.ApplicationContext +import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.context.NonNullSpeculator import org.utbot.framework.context.TypeReplacer import org.utbot.framework.plugin.api.BeanDefinitionData @@ -32,16 +33,13 @@ class SpringApplicationContextImpl( override var springContextLoadingResult: SpringContextLoadingResult? = null - override fun preventsFurtherTestGeneration(): Boolean = - delegateContext.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false - - override fun getErrors(): List = - springContextLoadingResult?.exceptions?.map { exception -> - UtError( - "Failed to load Spring application context", - exception - ) - }.orEmpty() + delegateContext.getErrors() + override fun createConcreteExecutionContext( + fullClasspath: String, + classpathWithoutDependencies: String + ): ConcreteExecutionContext = SpringConcreteExecutionContext( + delegateContext.createConcreteExecutionContext(fullClasspath, classpathWithoutDependencies), + this + ) override fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> // some bean classes may fail to load diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt new file mode 100644 index 0000000000..5d1a87f565 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt @@ -0,0 +1,21 @@ +package org.utbot.framework.context.spring + +import org.utbot.framework.context.ConcreteExecutionContext +import org.utbot.framework.plugin.api.UtError + +class SpringConcreteExecutionContext( + private val delegateContext: ConcreteExecutionContext, + private val springApplicationContext: SpringApplicationContext, +) : ConcreteExecutionContext { + override fun preventsFurtherTestGeneration(): Boolean = + delegateContext.preventsFurtherTestGeneration() || + springApplicationContext.springContextLoadingResult?.contextLoaded == false + + override fun getErrors(): List = + springApplicationContext.springContextLoadingResult?.exceptions?.map { exception -> + UtError( + "Failed to load Spring application context", + exception + ) + }.orEmpty() + delegateContext.getErrors() +} \ No newline at end of file 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 2af6cda9c0..8eb641bf60 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 @@ -81,6 +81,11 @@ open class TestCaseGenerator( ) { private val logger: KLogger = KotlinLogging.logger {} private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout") + private val concreteExecutionContext = applicationContext.createConcreteExecutionContext( + fullClasspath = classpathForEngine, + classpathWithoutDependencies = buildDirs.joinToString(File.pathSeparator) + ) + private val executionInstrumentation by lazy { when (applicationContext) { is SpringApplicationContext -> when (val settings = applicationContext.springSettings) { @@ -158,8 +163,8 @@ open class TestCaseGenerator( return@flow doContextDependentPreparationForTestGeneration() - applicationContext.getErrors().forEach { emit(it) } - if (applicationContext.preventsFurtherTestGeneration()) + concreteExecutionContext.getErrors().forEach { emit(it) } + if (concreteExecutionContext.preventsFurtherTestGeneration()) return@flow try { @@ -194,10 +199,10 @@ open class TestCaseGenerator( doContextDependentPreparationForTestGeneration() val method2errors: Map> = methods.associateWith { - applicationContext.getErrors().associateTo(mutableMapOf()) { it.description to 1 } + concreteExecutionContext.getErrors().associateTo(mutableMapOf()) { it.description to 1 } } - if (applicationContext.preventsFurtherTestGeneration()) + if (concreteExecutionContext.preventsFurtherTestGeneration()) return@use methods.map { method -> UtMethodTestSet(method, errors = method2errors.getValue(method)) } val executionStartInMillis = System.currentTimeMillis() From b794b9f7457684728bbf978e3c576e5281b9abd6 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Thu, 13 Jul 2023 16:56:43 +0300 Subject: [PATCH 09/20] Make naming of `SpringApplicationContext` properties more consistent --- .../framework/context/spring/SpringApplicationContext.kt | 4 ++-- .../context/spring/SpringApplicationContextImpl.kt | 7 +++---- .../framework/context/spring/SpringNonNullSpeculator.kt | 2 +- .../utbot/framework/context/spring/SpringTypeReplacer.kt | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt index f04002a775..15fab49219 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt @@ -16,8 +16,8 @@ interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationCon * Describes bean definitions (bean name, type, some optional additional data) */ val beanDefinitions: List - val springInjectedClasses: Set - val allInjectedTypes: Set + val injectedTypes: Set + val allInjectedSuperTypes: Set override var springContextLoadingResult: SpringContextLoadingResult? fun getBeansAssignableTo(classId: ClassId): List diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index cd27f602c4..790e9320c2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -12,7 +12,6 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringContextLoadingResult import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.SpringTestType -import org.utbot.framework.plugin.api.UtError import org.utbot.framework.plugin.api.util.allSuperTypes import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass @@ -50,7 +49,7 @@ class SpringApplicationContextImpl( } // Classes representing concrete types that are actually used in Spring application - override val springInjectedClasses: Set + override val injectedTypes: Set get() { if (!areAllInjectedSuperTypesInitialized) { for (beanTypeName in beanDefinitions.map { it.beanTypeName }) { @@ -80,10 +79,10 @@ class SpringApplicationContextImpl( return _injectedTypes } - override val allInjectedTypes: Set + override val allInjectedSuperTypes: Set get() { if (!areInjectedTypesInitialized) { - _allInjectedSuperTypes = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet() + _allInjectedSuperTypes = injectedTypes.flatMap { it.allSuperTypes() }.toSet() areInjectedTypesInitialized = true } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt index d286dfdafe..5f49d7800d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringNonNullSpeculator.kt @@ -14,6 +14,6 @@ class SpringNonNullSpeculator( override fun speculativelyCannotProduceNullPointerException(field: SootField, classUnderTest: ClassId): Boolean = // TODO add ` || delegateNonNullSpeculator.speculativelyCannotProduceNullPointerException(field, classUnderTest)` // (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR) - field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in springApplicationContext.allInjectedTypes + field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in springApplicationContext.allInjectedSuperTypes } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt index 9b476d95eb..78362c7520 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt @@ -21,6 +21,6 @@ class SpringTypeReplacer( override fun replaceTypeIfNeeded(type: RefType): ClassId? = // TODO add `delegateTypeReplacer.replaceTypeIfNeeded(type) ?: ` // (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR) - if (type.isAbstractType) springApplicationContext.springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) } + if (type.isAbstractType) springApplicationContext.injectedTypes.singleOrNull { it.isSubtypeOf(type.id) } else null } \ No newline at end of file From 351c0a14b0b1acac36c1a59a1ca689ac8a99c89d Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 17 Jul 2023 10:58:16 +0300 Subject: [PATCH 10/20] Pass `Instrumentation.Factory` via Kryo instead of `Instrumentation` itself --- .../org/utbot/engine/UtBotSymbolicEngine.kt | 6 +- .../org/utbot/external/api/UtBotJavaApi.kt | 4 +- .../context/ConcreteExecutionContext.kt | 2 +- .../framework/coverage/CoverageCalculator.kt | 2 +- .../framework/plugin/api/TestCaseGenerator.kt | 37 ++++---- .../org/utbot/examples/TestConstructors.kt | 10 +-- .../examples/TestCoverageInstrumentation.kt | 16 ++-- .../examples/TestInvokeInstrumentation.kt | 14 +-- .../TestInvokeWithStaticsInstrumentation.kt | 8 +- .../kotlin/org/utbot/examples/TestIsolated.kt | 12 +-- .../org/utbot/examples/TestStaticMethods.kt | 6 +- .../utbot/examples/TestWithInstrumentation.kt | 6 +- .../org/utbot/examples/benchmark/Benchmark.kt | 4 +- .../examples/benchmark/BenchmarkFibonacci.kt | 4 +- .../benchmark/TestBenchmarkClasses.kt | 4 +- .../org/utbot/examples/et/TestMixedExTrace.kt | 2 +- .../utbot/examples/et/TestSimpleExTrace.kt | 12 +-- .../org/utbot/examples/et/TestStaticsUsage.kt | 4 +- .../utbot/examples/jacoco/TestSameAsJaCoCo.kt | 2 +- .../utbot/instrumentation/ConcreteExecutor.kt | 30 +++---- .../org/utbot/instrumentation/Executor.kt | 2 +- .../instrumentation/Instrumentation.kt | 11 ++- .../instrumentation/InvokeInstrumentation.kt | 4 + .../InvokeWithStaticsInstrumentation.kt | 4 + .../coverage/CoverageInstrumentation.kt | 6 +- .../et/ExecutionTraceInstrumentation.kt | 4 + .../execution/UtExecutionInstrumentation.kt | 56 ++++++++---- .../SpringUtExecutionInstrumentation.kt | 87 +++++++++++-------- .../process/InstrumentedProcessMain.kt | 5 +- .../instrumentation/rd/InstrumentedProcess.kt | 4 +- 30 files changed, 213 insertions(+), 155 deletions(-) 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 c322c69887..9fccce9ecf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -54,6 +54,7 @@ import org.utbot.instrumentation.getRelevantSpringRepositories import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation import org.utbot.taint.* import org.utbot.taint.model.TaintConfiguration import soot.jimple.Stmt @@ -117,10 +118,11 @@ class UtBotSymbolicEngine( val mockStrategy: MockStrategy = NO_MOCKS, chosenClassesToMockAlways: Set, val applicationContext: ApplicationContext, - executionInstrumentation: Instrumentation, + executionInstrumentationFactory: UtExecutionInstrumentation.Factory<*>, userTaintConfigurationProvider: TaintConfigurationProvider? = null, private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis, ) : UtContextInitializer() { + private val graph = methodUnderTest.sootMethod.jimpleBody().apply { logger.trace { "JIMPLE for $methodUnderTest:\n$this" } }.graph() @@ -189,7 +191,7 @@ class UtBotSymbolicEngine( private val concreteExecutor = ConcreteExecutor( - executionInstrumentation, + executionInstrumentationFactory, classpath, ).apply { this.classLoader = utContext.classLoader } diff --git a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt index 1036f927ac..89b778fa2c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt @@ -40,6 +40,8 @@ import org.utbot.fuzzing.Seed import org.utbot.fuzzing.ValueProvider import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.execute +import org.utbot.instrumentation.instrumentation.execution.SimpleUtExecutionInstrumentation +import java.io.File import kotlin.reflect.jvm.kotlinFunction object UtBotJavaApi { @@ -71,7 +73,7 @@ object UtBotJavaApi { val testSets: MutableList = generatedTestCases.toMutableList() val concreteExecutor = ConcreteExecutor( - UtExecutionInstrumentation, + SimpleUtExecutionInstrumentation.Factory(pathsToUserClasses = classpath.split(File.pathSeparator).toSet()), classpath, ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt index f5d0804435..ec04d58132 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt @@ -8,7 +8,7 @@ interface ConcreteExecutionContext { fun getErrors(): List // TODO refactor, so this interface only includes the following: - // val instrumentation: Instrumentation + // val instrumentationFactory: UtExecutionInstrumentation.Factory<*> // fun createValueProviderOrThrow(classUnderTest: ClassId, idGenerator: IdentityPreservingIdGenerator): JavaValueProvider // fun loadContext(): ContextLoadingResult // fun Coverage.filterCoveredInstructions(classUnderTestId: ClassId): Coverage diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt index cfefe3c12e..8c29eadb2f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.runBlocking fun methodCoverage(executable: ExecutableId, executions: List>, classpath: String): Coverage { val methodSignature = executable.signature val classId = executable.classId - return ConcreteExecutor(CoverageInstrumentation, classpath).let { executor -> + return ConcreteExecutor(CoverageInstrumentation.Factory(), classpath).let { executor -> for (execution in executions) { val args = execution.stateBefore.params.map { it.value }.toMutableList() val caller = execution.stateBefore.caller 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 8eb641bf60..030e7736fa 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 @@ -43,8 +43,9 @@ 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.spring.SpringUtExecutionInstrumentation +import org.utbot.instrumentation.instrumentation.execution.SimpleUtExecutionInstrumentation import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation +import org.utbot.instrumentation.instrumentation.spring.SpringUtExecutionInstrumentation import org.utbot.instrumentation.tryLoadingSpringContext import org.utbot.instrumentation.warmup import org.utbot.taint.TaintConfigurationProvider @@ -86,25 +87,29 @@ open class TestCaseGenerator( classpathWithoutDependencies = buildDirs.joinToString(File.pathSeparator) ) - private val executionInstrumentation by lazy { + private val executionInstrumentationFactory: UtExecutionInstrumentation.Factory<*> = run { + val simpleUtExecutionInstrumentationFactory = SimpleUtExecutionInstrumentation.Factory(classpathForEngine.split(File.pathSeparator).toSet()) when (applicationContext) { - is SpringApplicationContext -> when (val settings = applicationContext.springSettings) { - is AbsentSpringSettings -> UtExecutionInstrumentation - is PresentSpringSettings -> when (applicationContext.springTestType) { - UNIT_TEST -> UtExecutionInstrumentation - INTEGRATION_TEST -> SpringUtExecutionInstrumentation( - UtExecutionInstrumentation, - settings, - applicationContext.beanDefinitions, - buildDirs.map { it.toURL() }.toTypedArray(), - ) + is SpringApplicationContext -> { + when (val settings = applicationContext.springSettings) { + is AbsentSpringSettings -> simpleUtExecutionInstrumentationFactory + is PresentSpringSettings -> when (applicationContext.springTestType) { + UNIT_TEST -> simpleUtExecutionInstrumentationFactory + INTEGRATION_TEST -> SpringUtExecutionInstrumentation.Factory( + simpleUtExecutionInstrumentationFactory, + settings, + applicationContext.beanDefinitions, + buildDirs.map { it.toURL() }.toTypedArray(), + ) + } } } - else -> UtExecutionInstrumentation + else -> simpleUtExecutionInstrumentationFactory } } + private val classpathForEngine: String get() = (buildDirs + listOfNotNull(classpath)).joinToString(File.pathSeparator) @@ -128,7 +133,7 @@ open class TestCaseGenerator( // force pool to create an appropriate executor // TODO ensure that instrumented process that starts here is properly terminated ConcreteExecutor( - executionInstrumentation, + executionInstrumentationFactory, classpathForEngine, ).apply { warmup() @@ -335,7 +340,7 @@ open class TestCaseGenerator( mockStrategy = mockStrategyApi.toModel(), chosenClassesToMockAlways = chosenClassesToMockAlways, applicationContext = applicationContext, - executionInstrumentation = executionInstrumentation, + executionInstrumentationFactory = executionInstrumentationFactory, solverTimeoutInMillis = executionTimeEstimator.updatedSolverCheckTimeoutMillis, userTaintConfigurationProvider = userTaintConfigurationProvider, ) @@ -471,7 +476,7 @@ open class TestCaseGenerator( if (applicationContext.springContextLoadingResult == null) // force pool to create an appropriate executor applicationContext.springContextLoadingResult = ConcreteExecutor( - executionInstrumentation, + executionInstrumentationFactory, classpathForEngine ).tryLoadingSpringContext() } diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt index 93801a9621..7d37d0c569 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt @@ -28,7 +28,7 @@ class TestConstructors { @Test fun testDefaultConstructor() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), CLASSPATH ).use { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -43,7 +43,7 @@ class TestConstructors { @Test fun testIntConstructors() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), CLASSPATH ).use { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -65,7 +65,7 @@ class TestConstructors { @Test fun testStringConstructors() { withInstrumentation( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -86,7 +86,7 @@ class TestConstructors { @Test fun testCoverageConstructor() { withInstrumentation( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -106,7 +106,7 @@ class TestConstructors { @Test fun testExecutionTraceConstructor() { withInstrumentation( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt index 34f9da3fd9..de520914c9 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt @@ -24,7 +24,7 @@ class TestCoverageInstrumentation { @Test fun testCatchTargetException() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -41,7 +41,7 @@ class TestCoverageInstrumentation { @Test fun testIfBranches() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -63,7 +63,7 @@ class TestCoverageInstrumentation { @Test fun testWrongArgumentsException() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -86,7 +86,7 @@ class TestCoverageInstrumentation { @Test fun testMultipleRunsInsideCoverage() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -121,7 +121,7 @@ class TestCoverageInstrumentation { @Test fun testSameResult() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -143,7 +143,7 @@ class TestCoverageInstrumentation { @Test fun testResult() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -160,7 +160,7 @@ class TestCoverageInstrumentation { @Test fun testEmptyMethod() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -176,7 +176,7 @@ class TestCoverageInstrumentation { @Test fun testTernaryOperator() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), StaticSubstitutionExamples::class.java.protectionDomain.codeSource.location.path ).use { val testObject = StaticSubstitutionExamples() diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt index 85ecde4416..1bb05465e8 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt @@ -21,7 +21,7 @@ class TestInvokeInstrumentation { @Test fun testCatchTargetException() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { @@ -36,7 +36,7 @@ class TestInvokeInstrumentation { @Test fun testWrongArgumentsException() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -57,7 +57,7 @@ class TestInvokeInstrumentation { @Test fun testSameResult() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -73,7 +73,7 @@ class TestInvokeInstrumentation { @Test fun testEmptyMethod() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -87,7 +87,7 @@ class TestInvokeInstrumentation { @Test fun testStaticMethodCall() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute(StaticExampleClass::inc, arrayOf()) @@ -105,7 +105,7 @@ class TestInvokeInstrumentation { @Test fun testNullableMethod() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( @@ -136,7 +136,7 @@ class TestInvokeInstrumentation { @Test fun testDifferentSignaturesButSameMethodNames() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ClassWithSameMethodNames::class.java.protectionDomain.codeSource.location.path ).use { val clazz = ClassWithSameMethodNames::class diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt index b1865499e0..cda707c17a 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt @@ -35,7 +35,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testIfBranches() { ConcreteExecutor( - InvokeWithStaticsInstrumentation(), + InvokeWithStaticsInstrumentation.Factory(), CLASSPATH ).use { val res = it.execute(StaticExampleClass::inc, arrayOf(), null) @@ -52,7 +52,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testHiddenClass1() { ConcreteExecutor( - InvokeWithStaticsInstrumentation(), + InvokeWithStaticsInstrumentation.Factory(), CLASSPATH ).use { val res = it.execute(TestedClass::slomayInts, arrayOf(), null) @@ -71,7 +71,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testHiddenClassRepeatCall() { ConcreteExecutor( - InvokeWithStaticsInstrumentation(), + InvokeWithStaticsInstrumentation.Factory(), CLASSPATH ).use { val se = StaticEnvironment( @@ -89,7 +89,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testReferenceEquality() { ConcreteExecutor( - InvokeWithStaticsInstrumentation(), + InvokeWithStaticsInstrumentation.Factory(), CLASSPATH ).use { diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt index 500da27859..3538e2979b 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt @@ -21,7 +21,7 @@ class TestIsolated { fun testCatchTargetException() { val javaClass = ExampleClass::class.java ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), javaClass.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -37,7 +37,7 @@ class TestIsolated { @Test fun testWrongArgumentsException() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -63,7 +63,7 @@ class TestIsolated { @Test fun testSameResult() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -81,7 +81,7 @@ class TestIsolated { @Test fun testEmptyMethod() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -97,7 +97,7 @@ class TestIsolated { @Test fun testStaticMethodCall() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val isolatedFunctionInc = Isolated(StaticExampleClass::inc, it) @@ -116,7 +116,7 @@ class TestIsolated { @Test fun testNullableMethod() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val isolatedFunction = Isolated(StaticExampleClass::canBeNull, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt index 6ad3bca179..bc33834f80 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt @@ -17,7 +17,7 @@ class TestStaticMethods { @Test fun testStaticMethodCall() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute(StaticExampleClass::inc, arrayOf()) @@ -44,7 +44,7 @@ class TestStaticMethods { @Test fun testNullableMethod() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( @@ -75,7 +75,7 @@ class TestStaticMethods { @Test fun testNullableMethodWithoutAnnotations() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt index f49c010b81..22e6308c52 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt @@ -20,7 +20,7 @@ class TestWithInstrumentation { @Test fun testStaticMethodCall() { withInstrumentation( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), StaticExampleClass::class.java.protectionDomain.codeSource.location.path ) { executor -> val res1 = executor.execute(StaticExampleClass::inc, arrayOf()) @@ -47,7 +47,7 @@ class TestWithInstrumentation { @Test fun testDifferentSignaturesButSameMethodNames() { withInstrumentation( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), ClassWithSameMethodNames::class.java.protectionDomain.codeSource.location.path ) { executor -> val clazz = ClassWithSameMethodNames::class @@ -70,7 +70,7 @@ class TestWithInstrumentation { @Test fun testInnerClasses() { withInstrumentation( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), ClassWithInnerClasses::class.java.protectionDomain.codeSource.location.path ) { executor -> val innerClazz = ClassWithInnerClasses.InnerClass::class.java diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt index 41ec9da126..55da2d91df 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt @@ -12,7 +12,7 @@ import org.junit.jupiter.api.Assertions.assertEquals fun getBasicCoverageTime(count: Int): Double { var time: Long ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), Repeater::class.java.protectionDomain.codeSource.location.path ).use { executor -> val dc0 = Repeater(", ") @@ -51,7 +51,7 @@ fun getNativeCallTime(count: Int): Double { fun getJustResultTime(count: Int): Double { var time: Long ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), Repeater::class.java.protectionDomain.codeSource.location.path ).use { val dc0 = Repeater(", ") diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt index 4c370553de..e65de088a2 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt @@ -13,7 +13,7 @@ import kotlin.system.measureNanoTime fun getBasicCoverageTime_fib(count: Int): Double { var time: Long ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val fib = Isolated(Fibonacci::calc, it) @@ -47,7 +47,7 @@ fun getNativeCallTime_fib(count: Int): Double { fun getJustResultTime_fib(count: Int): Double { var time: Long ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val fib = Isolated(Fibonacci::calc, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt index 81d8240500..c660d9291a 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt @@ -18,7 +18,7 @@ class TestBenchmarkClasses { @Disabled("Ask Sergey to check") fun testRepeater() { ConcreteExecutor( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), Repeater::class.java.protectionDomain.codeSource.location.path ).use { val dc0 = Repeater(", ") @@ -36,7 +36,7 @@ class TestBenchmarkClasses { @Test fun testFibonacci() { ConcreteExecutor( - InvokeInstrumentation(), + InvokeInstrumentation.Factory(), Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val res = diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt index 560a314633..cedaf15539 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt @@ -25,7 +25,7 @@ class TestMixedExTrace { @Test fun testMixedDoesNotThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassMixedWithNotInstrumented_Instr::a, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt index e7dab32d5f..dbb732eb7c 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt @@ -34,7 +34,7 @@ class TestSimpleExTrace { @Test fun testClassSimple() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val alwaysThrows = Isolated(ClassSimple::alwaysThrows, it) @@ -89,7 +89,7 @@ class TestSimpleExTrace { @Test fun testClasSimpleCatch() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassSimpleCatch::A, it) @@ -159,7 +159,7 @@ class TestSimpleExTrace { @Test fun testClassSimpleRecursive() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassSimpleRecursive::A, it) @@ -228,7 +228,7 @@ class TestSimpleExTrace { @Test fun testClassBinaryRecursionWithTrickyThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassBinaryRecursionWithTrickyThrow::A, it) @@ -347,7 +347,7 @@ class TestSimpleExTrace { @Test fun testClassBinaryRecursionWithThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassBinaryRecursionWithThrow::A, it) @@ -436,7 +436,7 @@ class TestSimpleExTrace { @Test fun testClassSimpleNPE() { ConcreteExecutor( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), CLASSPATH ).use { val A = Isolated(ClassSimpleNPE::A, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt index f4aef6ead6..1375cc898f 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt @@ -31,7 +31,7 @@ class StaticsUsageDetectionTest { @Test fun testStaticsUsageOneUsage() { withInstrumentation( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), ObjectWithStaticFieldsExample::class.java.protectionDomain.codeSource.location.path ) { val instance = ObjectWithStaticFieldsExample() @@ -46,7 +46,7 @@ class StaticsUsageDetectionTest { @Test fun testStaticsUsageZeroUsages() { withInstrumentation( - ExecutionTraceInstrumentation(), + ExecutionTraceInstrumentation.Factory(), ObjectWithStaticFieldsExample::class.java.protectionDomain.codeSource.location.path ) { val instance = ObjectWithStaticFieldsExample() diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt index de8051a775..88187068d1 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt @@ -123,7 +123,7 @@ private fun methodCoverageWithJaCoCo(kClass: KClass<*>, method: KCallable<*>, ex private fun methodCoverage(kClass: KClass<*>, method: KCallable<*>, executions: List): Pair { return withInstrumentation( - CoverageInstrumentation, + CoverageInstrumentation.Factory(), kClass.java.protectionDomain.codeSource.location.path ) { executor -> for (execution in executions) { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt index 90539abbf9..ddbbe76a71 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt @@ -48,10 +48,10 @@ private val logger = KotlinLogging.logger {} * @see [org.utbot.instrumentation.instrumentation.coverage.CoverageInstrumentation]. */ inline fun > withInstrumentation( - instrumentation: T, + instrumentationFactory: Instrumentation.Factory, pathsToUserClasses: String, block: (ConcreteExecutor) -> TBlockResult -) = ConcreteExecutor(instrumentation, pathsToUserClasses).use { +) = ConcreteExecutor(instrumentationFactory, pathsToUserClasses).use { block(it) } @@ -59,20 +59,20 @@ class ConcreteExecutorPool(val maxCount: Int = Settings.defaultConcreteExecutorP private val executors = ArrayDeque>(maxCount) /** - * Tries to find the concrete executor for the supplied [instrumentation] and [pathsToDependencyClasses]. If it + * Tries to find the concrete executor for the supplied [instrumentationFactory] and [pathsToDependencyClasses]. If it * doesn't exist, then creates a new one. */ fun > get( - instrumentation: TInstrumentation, + instrumentationFactory: Instrumentation.Factory, pathsToUserClasses: String, ): ConcreteExecutor { executors.removeIf { !it.alive } @Suppress("UNCHECKED_CAST") return executors.firstOrNull { - it.pathsToUserClasses == pathsToUserClasses && it.instrumentation == instrumentation + it.pathsToUserClasses == pathsToUserClasses && it.instrumentationFactory == instrumentationFactory } as? ConcreteExecutor - ?: ConcreteExecutor.createNew(instrumentation, pathsToUserClasses).apply { + ?: ConcreteExecutor.createNew(instrumentationFactory, pathsToUserClasses).apply { executors.addFirst(this) if (executors.size > maxCount) { executors.removeLast().close() @@ -100,12 +100,12 @@ class ConcreteExecutorPool(val maxCount: Int = Settings.defaultConcreteExecutorP * * If [instrumentation] depends on other classes, they should be passed in [pathsToDependencyClasses]. * - * Also takes [instrumentation] object which will be used in the instrumented process for the instrumentation. + * Also takes [instrumentationFactory] object which will be used in the instrumented process to create an [Instrumentation]. * - * @param TIResult the return type of [Instrumentation.invoke] function for the given [instrumentation]. + * @param TIResult the return type of [Instrumentation.invoke] function for the given [Instrumentation]. */ -class ConcreteExecutor> private constructor( - internal val instrumentation: TInstrumentation, +class ConcreteExecutor> private constructor( + internal val instrumentationFactory: Instrumentation.Factory, internal val pathsToUserClasses: String ) : Closeable, Executor { private val ldef: LifetimeDefinition = LifetimeDefinition() @@ -129,14 +129,14 @@ class ConcreteExecutor> p * and in case of failure, creates a new one. */ operator fun > invoke( - instrumentation: TInstrumentation, + instrumentationFactory: Instrumentation.Factory, pathsToUserClasses: String, - ) = defaultPool.get(instrumentation, pathsToUserClasses) + ) = defaultPool.get(instrumentationFactory, pathsToUserClasses) internal fun > createNew( - instrumentation: TInstrumentation, + instrumentationFactory: Instrumentation.Factory, pathsToUserClasses: String - ) = ConcreteExecutor(instrumentation, pathsToUserClasses) + ) = ConcreteExecutor(instrumentationFactory, pathsToUserClasses) } var classLoader: ClassLoader? = UtContext.currentContext()?.classLoader @@ -157,7 +157,7 @@ class ConcreteExecutor> p if (proc == null || !proc.lifetime.isAlive) { proc = InstrumentedProcess( ldef, - instrumentation, + instrumentationFactory, pathsToUserClasses, classLoader ) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/Executor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/Executor.kt index 4744cf765a..80213cb248 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/Executor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/Executor.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.runBlocking * * @param TResult the type of an execution result. */ -interface Executor { +interface Executor { /** * Main method to override. * Returns the result of the execution of the [ExecutableId] with [arguments] and [parameters]. diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/Instrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/Instrumentation.kt index d6bd839734..4adcb58992 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/Instrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/Instrumentation.kt @@ -27,10 +27,9 @@ interface Instrumentation : ClassFileTransformer fun getStaticField(fieldId: FieldId): Result<*> - /** - * Will be called in the very beginning in the instrumented process. - * - * Do not call from engine process to avoid unwanted side effects (e.g. Spring context initialization) - */ - fun init(pathsToUserClasses: Set) {} + interface Factory> { + val additionalRuntimeClasspath: Set get() = emptySet() + + fun create(): TInstrumentation + } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt index 730f73fd5b..73e11d7114 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt @@ -117,4 +117,8 @@ class InvokeInstrumentation : Instrumentation> { protectionDomain: ProtectionDomain, classfileBuffer: ByteArray ) = null + + class Factory : Instrumentation.Factory, InvokeInstrumentation> { + override fun create(): InvokeInstrumentation = InvokeInstrumentation() + } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt index 4b91be37fa..5bd1253128 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt @@ -89,6 +89,10 @@ class InvokeWithStaticsInstrumentation : Instrumentation> { .forEach { it.withAccessibility { it.set(null, savedFields[it.name]) } } } } + + class Factory : Instrumentation.Factory, InvokeWithStaticsInstrumentation> { + override fun create(): InvokeWithStaticsInstrumentation = InvokeWithStaticsInstrumentation() + } } private fun checkField(field: Field) = Modifier.isStatic(field.modifiers) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt index bba4f864ca..98fbcb0e37 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt @@ -22,7 +22,7 @@ data class CoverageInfo( /** * This instrumentation allows collecting coverage after several calls. */ -object CoverageInstrumentation : Instrumentation> { +class CoverageInstrumentation : Instrumentation> { private val invokeWithStatics = InvokeWithStaticsInstrumentation() /** @@ -94,6 +94,10 @@ object CoverageInstrumentation : Instrumentation> { return instrumenter.classByteCode } + + class Factory : Instrumentation.Factory, CoverageInstrumentation> { + override fun create(): CoverageInstrumentation = CoverageInstrumentation() + } } /** diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt index c10e90e73b..9424d9f8d9 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt @@ -57,4 +57,8 @@ class ExecutionTraceInstrumentation : Instrumentation { classByteCode } } + + class Factory : Instrumentation.Factory { + override fun create(): ExecutionTraceInstrumentation = ExecutionTraceInstrumentation() + } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt index 824393c1bb..c7a7185f9c 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt @@ -47,20 +47,39 @@ data class UtConcreteExecutionResult( } } -// TODO if possible make it non singleton -object UtExecutionInstrumentation : Instrumentation { - private val delegateInstrumentation = InvokeInstrumentation() +interface UtExecutionInstrumentation : Instrumentation { + override fun invoke( + clazz: Class<*>, + methodSignature: String, + arguments: ArgumentList, + parameters: Any? + ): UtConcreteExecutionResult = invoke( + clazz, methodSignature, arguments, parameters, phasesWrapper = { invokeBasePhases -> invokeBasePhases() } + ) - var instrumentationContext: InstrumentationContext = SimpleInstrumentationContext() + fun invoke( + clazz: Class<*>, + methodSignature: String, + arguments: ArgumentList, + parameters: Any?, + phasesWrapper: PhasesController.(invokeBasePhases: () -> UtConcreteExecutionResult) -> UtConcreteExecutionResult + ): UtConcreteExecutionResult - private val traceHandler = TraceHandler() - private val ndDetector = NonDeterministicDetector() - private val pathsToUserClasses = mutableSetOf() + interface Factory : Instrumentation.Factory { + override fun create(): TInstrumentation = create(SimpleInstrumentationContext()) - override fun init(pathsToUserClasses: Set) { - UtExecutionInstrumentation.pathsToUserClasses.clear() - UtExecutionInstrumentation.pathsToUserClasses += pathsToUserClasses + fun create(instrumentationContext: InstrumentationContext): TInstrumentation } +} + +class SimpleUtExecutionInstrumentation( + private val pathsToUserClasses: Set, + private val instrumentationContext: InstrumentationContext = SimpleInstrumentationContext() +) : UtExecutionInstrumentation { + private val delegateInstrumentation = InvokeInstrumentation() + + private val traceHandler = TraceHandler() + private val ndDetector = NonDeterministicDetector() /** * Ignores [arguments], because concrete arguments will be constructed @@ -69,14 +88,6 @@ object UtExecutionInstrumentation : Instrumentation { * Argument [parameters] must be of type [UtConcreteExecutionData]. */ override fun invoke( - clazz: Class<*>, - methodSignature: String, - arguments: ArgumentList, - parameters: Any? - ): UtConcreteExecutionResult = - invoke(clazz, methodSignature, arguments, parameters, phasesWrapper = { it() }) - - fun invoke( clazz: Class<*>, methodSignature: String, arguments: ArgumentList, @@ -191,4 +202,13 @@ object UtExecutionInstrumentation : Instrumentation { return instrumenter.classByteCode } + + class Factory( + private val pathsToUserClasses: Set + ) : UtExecutionInstrumentation.Factory { + override fun create(): UtExecutionInstrumentation = SimpleUtExecutionInstrumentation(pathsToUserClasses) + + override fun create(instrumentationContext: InstrumentationContext): UtExecutionInstrumentation = + SimpleUtExecutionInstrumentation(pathsToUserClasses, instrumentationContext) + } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt index a2f55b089d..64cc38c6fe 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt @@ -6,16 +6,17 @@ import org.utbot.common.JarUtils 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.FieldId import org.utbot.framework.plugin.api.SpringContextLoadingResult 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 import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation +import org.utbot.instrumentation.instrumentation.execution.context.InstrumentationContext import org.utbot.instrumentation.instrumentation.execution.phases.ExecutionPhaseFailingOnAnyException -import org.utbot.instrumentation.process.HandlerClassesLoader +import org.utbot.instrumentation.instrumentation.execution.phases.PhasesController import org.utbot.spring.api.SpringApi import java.net.URL import java.net.URLClassLoader @@ -25,14 +26,15 @@ import java.security.ProtectionDomain * UtExecutionInstrumentation wrapper that is aware of Spring configuration and profiles and initialises Spring context */ class SpringUtExecutionInstrumentation( - private val delegateInstrumentation: UtExecutionInstrumentation, - private val springSettings: PresentSpringSettings, + instrumentationContext: InstrumentationContext, + delegateInstrumentationFactory: UtExecutionInstrumentation.Factory<*>, + springSettings: PresentSpringSettings, private val beanDefinitions: List, - private val buildDirs: Array, -) : Instrumentation by delegateInstrumentation { - - private lateinit var instrumentationContext: SpringInstrumentationContext - private lateinit var userSourcesClassLoader: URLClassLoader + buildDirs: Array, +) : UtExecutionInstrumentation { + private val instrumentationContext = SpringInstrumentationContext(springSettings, instrumentationContext) + private val delegateInstrumentation = delegateInstrumentationFactory.create(this.instrumentationContext) + private val userSourcesClassLoader = URLClassLoader(buildDirs, null) private val relatedBeansCache = mutableMapOf, Set>() @@ -46,23 +48,6 @@ class SpringUtExecutionInstrumentation( private const val SPRING_COMMONS_JAR_FILENAME = "utbot-spring-commons-shadow.jar" } - override fun init(pathsToUserClasses: Set) { - HandlerClassesLoader.addUrls( - listOf( - JarUtils.extractJarFileFromResources( - jarFileName = SPRING_COMMONS_JAR_FILENAME, - jarResourcePath = "lib/$SPRING_COMMONS_JAR_FILENAME", - targetDirectoryName = "spring-commons" - ).path - ) - ) - - userSourcesClassLoader = URLClassLoader(buildDirs, null) - instrumentationContext = SpringInstrumentationContext(springSettings, delegateInstrumentation.instrumentationContext) - delegateInstrumentation.instrumentationContext = instrumentationContext - delegateInstrumentation.init(pathsToUserClasses) - } - fun tryLoadingSpringContext(): SpringContextLoadingResult { val apiProviderResult = instrumentationContext.springApiProviderResult return SpringContextLoadingResult( @@ -75,25 +60,30 @@ class SpringUtExecutionInstrumentation( clazz: Class<*>, methodSignature: String, arguments: ArgumentList, - parameters: Any? + parameters: Any?, + phasesWrapper: PhasesController.(invokeBasePhases: () -> UtConcreteExecutionResult) -> UtConcreteExecutionResult ): UtConcreteExecutionResult { getRelevantBeans(clazz).forEach { beanName -> springApi.resetBean(beanName) } return delegateInstrumentation.invoke(clazz, methodSignature, arguments, parameters) { invokeBasePhases -> - // NB! beforeTestMethod() and afterTestMethod() are intentionally called inside phases, - // so they are executed in one thread with method under test - // NB! beforeTestMethod() and afterTestMethod() are executed without timeout, because: - // - if the invokeBasePhases() times out, we still want to execute afterTestMethod() - // - first call to beforeTestMethod() can take significant amount of time due to class loading & transformation - executePhaseWithoutTimeout(SpringBeforeTestMethodPhase) { springApi.beforeTestMethod() } - try { - invokeBasePhases() - } finally { - executePhaseWithoutTimeout(SpringAfterTestMethodPhase) { springApi.afterTestMethod() } + phasesWrapper { + // NB! beforeTestMethod() and afterTestMethod() are intentionally called inside phases, + // so they are executed in one thread with method under test + // NB! beforeTestMethod() and afterTestMethod() are executed without timeout, because: + // - if the invokeBasePhases() times out, we still want to execute afterTestMethod() + // - first call to beforeTestMethod() can take significant amount of time due to class loading & transformation + executePhaseWithoutTimeout(SpringBeforeTestMethodPhase) { springApi.beforeTestMethod() } + try { + invokeBasePhases() + } finally { + executePhaseWithoutTimeout(SpringAfterTestMethodPhase) { springApi.afterTestMethod() } + } } } } + override fun getStaticField(fieldId: FieldId): Result<*> = delegateInstrumentation.getStaticField(fieldId) + private fun getRelevantBeans(clazz: Class<*>): Set = relatedBeansCache.getOrPut(clazz) { beanDefinitions .filter { it.beanTypeName == clazz.name } @@ -136,4 +126,27 @@ class SpringUtExecutionInstrumentation( } else { null } + + class Factory( + private val delegateInstrumentationFactory: UtExecutionInstrumentation.Factory<*>, + private val springSettings: PresentSpringSettings, + private val beanDefinitions: List, + private val buildDirs: Array, + ) : UtExecutionInstrumentation.Factory { + override val additionalRuntimeClasspath: Set + get() = super.additionalRuntimeClasspath + JarUtils.extractJarFileFromResources( + jarFileName = SPRING_COMMONS_JAR_FILENAME, + jarResourcePath = "lib/$SPRING_COMMONS_JAR_FILENAME", + targetDirectoryName = "spring-commons" + ).path + + override fun create(instrumentationContext: InstrumentationContext): SpringUtExecutionInstrumentation = + SpringUtExecutionInstrumentation( + instrumentationContext, + delegateInstrumentationFactory, + springSettings, + beanDefinitions, + buildDirs + ) + } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt index 70b64339c0..58618ac593 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt @@ -144,11 +144,12 @@ private fun InstrumentedProcessModel.setup(kryoHelper: KryoHelper, watchdog: Idl } watchdog.measureTimeForActiveCall(setInstrumentation, "Instrumentation setup") { params -> logger.debug { "setInstrumentation request" } - instrumentation = kryoHelper.readObject(params.instrumentation) + val instrumentationFactory = kryoHelper.readObject>(params.instrumentation) + HandlerClassesLoader.addUrls(instrumentationFactory.additionalRuntimeClasspath) + instrumentation = instrumentationFactory.create() logger.debug { "instrumentation - ${instrumentation.javaClass.name} " } Agent.dynamicClassTransformer.transformer = instrumentation Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses) - instrumentation.init(pathsToUserClasses) } watchdog.measureTimeForActiveCall(addPaths, "User and dependency classpath setup") { params -> pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet() diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt index 7ec82ef285..baef39ac5f 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt @@ -88,7 +88,7 @@ class InstrumentedProcess private constructor( suspend operator fun > invoke( parent: Lifetime, - instrumentation: TInstrumentation, + instrumentationFactory: Instrumentation.Factory, pathsToUserClasses: String, classLoader: ClassLoader? ): InstrumentedProcess = parent.createNested().terminateOnException { lifetime -> @@ -131,7 +131,7 @@ class InstrumentedProcess private constructor( logger.trace("sending instrumentation") proc.instrumentedProcessModel.setInstrumentation.startSuspending( proc.lifetime, SetInstrumentationParams( - proc.kryoHelper.writeObject(instrumentation) + proc.kryoHelper.writeObject(instrumentationFactory) ) ) logger.trace("start commands sent") From 452a49579b1d5ad05844de45ece0b36fa4a91029 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 17 Jul 2023 16:25:20 +0300 Subject: [PATCH 11/20] Refactor `ConcreteExecutionContext` interface, to avoid `when`s by `ApplicationContext` type --- .../org/utbot/framework/plugin/api/Api.kt | 33 +++- .../org/utbot/engine/UtBotSymbolicEngine.kt | 67 ++------ ...CgSpringIntegrationTestClassConstructor.kt | 2 +- .../context/ConcreteExecutionContext.kt | 30 +++- ...verageFilteringConcreteExecutionContext.kt | 93 +++++++++++ .../simple/SimpleApplicationContext.kt | 2 +- .../simple/SimpleConcreteExecutionContext.kt | 37 ++++- .../spring/SpringApplicationContext.kt | 4 +- .../spring/SpringApplicationContextImpl.kt | 36 ++++- .../spring/SpringConcreteExecutionContext.kt | 21 --- ...IntegrationTestConcreteExecutionContext.kt | 119 ++++++++++++++ .../framework/plugin/api/TestCaseGenerator.kt | 146 +++--------------- .../utbot/instrumentation/ConcreteExecutor.kt | 4 +- .../SpringUtExecutionInstrumentation.kt | 6 +- .../api/UTSpringContextLoadingException.kt | 2 +- 15 files changed, 357 insertions(+), 245 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/CoverageFilteringConcreteExecutionContext.kt delete mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestConcreteExecutionContext.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 ac61cf912d..67b6a5f576 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,7 +1323,7 @@ interface CodeGenerationContext interface SpringCodeGenerationContext : CodeGenerationContext { val springTestType: SpringTestType val springSettings: SpringSettings - val springContextLoadingResult: SpringContextLoadingResult? + val concreteContextLoadingResult: ConcreteContextLoadingResult? } sealed class SpringConfiguration(val fullDisplayName: String) { @@ -1349,14 +1349,35 @@ sealed interface SpringSettings { } /** - * [contextLoaded] can be `true` while [exceptions] is not empty, - * if we failed to use most specific SpringApi available (e.g. SpringBoot), but - * were able to successfully fall back to less specific SpringApi (e.g. PureSpring). + * Result of loading concrete execution context (e.g. Spring application context). + * + * [contextLoaded] can be `true` while [exceptions] is not empty. For example, we may fail + * to load context with most specific SpringApi available (e.g. SpringBoot), + * but successfully fall back to less specific SpringApi (e.g. PureSpring). */ -class SpringContextLoadingResult( +class ConcreteContextLoadingResult( val contextLoaded: Boolean, val exceptions: List -) +) { + val utErrors: List get() = + exceptions.map { UtError(it.message ?: "Concrete context loading failed", it) } + + fun andThen(onSuccess: () -> ConcreteContextLoadingResult) = + if (contextLoaded) { + val otherResult = onSuccess() + ConcreteContextLoadingResult( + contextLoaded = otherResult.contextLoaded, + exceptions = exceptions + otherResult.exceptions + ) + } else this + + companion object { + fun successWithoutExceptions() = ConcreteContextLoadingResult( + contextLoaded = true, + exceptions = emptyList() + ) + } +} enum class SpringTestType( override val id: String, 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 9fccce9ecf..46d16f234d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -10,7 +10,6 @@ import org.utbot.analytics.Predictors import org.utbot.api.exception.UtMockAssumptionViolatedException import org.utbot.common.debug import org.utbot.common.measureTime -import org.utbot.common.tryLoadClass import org.utbot.engine.MockStrategy.NO_MOCKS import org.utbot.engine.pc.* import org.utbot.engine.selectors.* @@ -34,7 +33,7 @@ import org.utbot.framework.UtSettings.pathSelectorType import org.utbot.framework.UtSettings.processUnknownStatesDuringConcreteExecution import org.utbot.framework.UtSettings.useDebugVisualization import org.utbot.framework.context.ApplicationContext -import org.utbot.framework.context.spring.SpringApplicationContext +import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.Step import org.utbot.framework.plugin.api.util.* @@ -44,17 +43,11 @@ import org.utbot.framework.util.graph import org.utbot.framework.util.sootMethod import org.utbot.fuzzer.* import org.utbot.fuzzing.* -import org.utbot.fuzzing.providers.FieldValueProvider -import org.utbot.fuzzing.providers.ObjectValueProvider -import org.utbot.fuzzing.spring.SavedEntityValueProvider -import org.utbot.fuzzing.spring.SpringBeanValueProvider import org.utbot.fuzzing.utils.Trie import org.utbot.instrumentation.ConcreteExecutor -import org.utbot.instrumentation.getRelevantSpringRepositories import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult -import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation import org.utbot.taint.* import org.utbot.taint.model.TaintConfiguration import soot.jimple.Stmt @@ -118,7 +111,7 @@ class UtBotSymbolicEngine( val mockStrategy: MockStrategy = NO_MOCKS, chosenClassesToMockAlways: Set, val applicationContext: ApplicationContext, - executionInstrumentationFactory: UtExecutionInstrumentation.Factory<*>, + val concreteExecutionContext: ConcreteExecutionContext, userTaintConfigurationProvider: TaintConfigurationProvider? = null, private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis, ) : UtContextInitializer() { @@ -191,7 +184,7 @@ class UtBotSymbolicEngine( private val concreteExecutor = ConcreteExecutor( - executionInstrumentationFactory, + concreteExecutionContext.instrumentationFactory, classpath, ).apply { this.classLoader = utContext.classLoader } @@ -393,57 +386,15 @@ class UtBotSymbolicEngine( val names = graph.body.method.tags.filterIsInstance().firstOrNull()?.names ?: emptyList() var testEmittedByFuzzer = 0 - if (applicationContext is SpringApplicationContext && - applicationContext.springTestType == SpringTestType.INTEGRATION_TEST && - applicationContext.getBeansAssignableTo(methodUnderTest.classId).isEmpty()) { - val fullConfigDisplayName = (applicationContext.springSettings as? SpringSettings.PresentSpringSettings) - ?.configuration?.fullDisplayName - val errorDescription = "No beans of type ${methodUnderTest.classId.name} were found. " + - "Try choosing different Spring configuration or adding beans to $fullConfigDisplayName" - emit(UtError( - errorDescription, - IllegalStateException(errorDescription) - )) + val valueProviders = try { + concreteExecutionContext.tryCreateValueProvider(concreteExecutor, classUnderTest, defaultIdGenerator) + } catch (e: Exception) { + emit(UtError(e.message ?: "Failed to create ValueProvider", e)) return@flow - } - - val valueProviders = ValueProvider.of(defaultValueProviders(defaultIdGenerator)) - .letIf(applicationContext is SpringApplicationContext - && applicationContext.springTestType == SpringTestType.INTEGRATION_TEST - ) { provider -> - val relevantRepositories = concreteExecutor.getRelevantSpringRepositories(methodUnderTest.classId) - logger.info { "Detected relevant repositories for class ${methodUnderTest.classId}: $relevantRepositories" } + }.let(transform) - val generatedValueAnnotationClasses = SpringModelUtils.generatedValueClassIds.mapNotNull { - @Suppress("UNCHECKED_CAST") // type system fails to understand that GeneratedValue is indeed an annotation - utContext.classLoader.tryLoadClass(it.name) as Class? - } - - val generatedValueFieldIds = - relevantRepositories - .map { it.entityClassId.jClass } - .flatMap { entityClass -> generateSequence(entityClass) { it.superclass } } - .flatMap { it.declaredFields.toList() } - .filter { field -> generatedValueAnnotationClasses.any { field.isAnnotationPresent(it) } } - .map { it.fieldId } - logger.info { "Detected @GeneratedValue fields: $generatedValueFieldIds" } - - // spring should try to generate bean values, but if it fails, then object value provider is used for it - val springBeanValueProvider = SpringBeanValueProvider( - defaultIdGenerator, - beanNameProvider = { classId -> - (applicationContext as SpringApplicationContext).getBeansAssignableTo(classId) - .map { it.beanName } - }, - relevantRepositories = relevantRepositories - ).withFallback(ObjectValueProvider(defaultIdGenerator)) - provider - .except { p -> p is ObjectValueProvider } - .with(springBeanValueProvider) - .with(ValueProvider.of(relevantRepositories.map { SavedEntityValueProvider(defaultIdGenerator, it) })) - .with(ValueProvider.of(generatedValueFieldIds.map { FieldValueProvider(defaultIdGenerator, it) })) - }.let(transform) val coverageToMinStateBeforeSize = mutableMapOf, Int>() + runJavaFuzzing( defaultIdGenerator, methodUnderTest, 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 34b6b750bd..45fab74fe4 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 @@ -64,7 +64,7 @@ class CgSpringIntegrationTestClassConstructor( ) private fun constructContextLoadsMethod() : CgTestMethod { - val contextLoadingResult = springCodeGenerationContext.springContextLoadingResult + val contextLoadingResult = springCodeGenerationContext.concreteContextLoadingResult if (contextLoadingResult == null) logger.error { "Missing contextLoadingResult" } val exception = contextLoadingResult?.exceptions?.firstOrNull() diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt index ec04d58132..c9b8103345 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt @@ -1,15 +1,29 @@ package org.utbot.framework.context -import org.utbot.framework.plugin.api.UtError +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult +import org.utbot.framework.plugin.api.UtExecution +import org.utbot.fuzzer.IdentityPreservingIdGenerator +import org.utbot.fuzzing.JavaValueProvider +import org.utbot.instrumentation.ConcreteExecutor +import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation interface ConcreteExecutionContext { - fun preventsFurtherTestGeneration(): Boolean + val instrumentationFactory: UtExecutionInstrumentation.Factory<*> - fun getErrors(): List + fun loadContext( + concreteExecutor: ConcreteExecutor, + ): ConcreteContextLoadingResult - // TODO refactor, so this interface only includes the following: - // val instrumentationFactory: UtExecutionInstrumentation.Factory<*> - // fun createValueProviderOrThrow(classUnderTest: ClassId, idGenerator: IdentityPreservingIdGenerator): JavaValueProvider - // fun loadContext(): ContextLoadingResult - // fun Coverage.filterCoveredInstructions(classUnderTestId: ClassId): Coverage + fun transformExecutionsBeforeMinimization( + executions: List, + classUnderTestId: ClassId + ): List + + fun tryCreateValueProvider( + concreteExecutor: ConcreteExecutor, + classUnderTest: ClassId, + idGenerator: IdentityPreservingIdGenerator, + ): JavaValueProvider } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/CoverageFilteringConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/CoverageFilteringConcreteExecutionContext.kt new file mode 100644 index 0000000000..b7ff805157 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/CoverageFilteringConcreteExecutionContext.kt @@ -0,0 +1,93 @@ +package org.utbot.framework.context.custom + +import mu.KotlinLogging +import org.utbot.common.hasOnClasspath +import org.utbot.common.tryLoadClass +import org.utbot.framework.context.ConcreteExecutionContext +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtExecution +import org.utbot.framework.plugin.api.util.utContext +import java.io.File +import java.net.URLClassLoader + +/** + * Decorator of [delegateContext] that filters coverage before test set minimization + * (see [transformExecutionsBeforeMinimization]) to avoid generating too many tests that + * only increase coverage of third party libraries. + * + * This implementation: + * - always keeps instructions that are in class under test (even if other rules say otherwise) + * - filters out instructions in classes marked with annotations from [annotationsToIgnoreCoverage] + * - filters out instructions from classes that are not found in `classpathToIncludeCoverageFrom` + * + * Finally, if [keepOriginalCoverageOnEmptyFilteredCoverage] is `true` we restore original coverage + * for executions whose coverage becomes empty after filtering. + */ +class CoverageFilteringConcreteExecutionContext( + private val delegateContext: ConcreteExecutionContext, + classpathToIncludeCoverageFrom: String, + private val annotationsToIgnoreCoverage: Set, + private val keepOriginalCoverageOnEmptyFilteredCoverage: Boolean, +) : ConcreteExecutionContext by delegateContext { + private val urlsToIncludeCoverageFrom = classpathToIncludeCoverageFrom.split(File.pathSeparator) + .map { File(it).toURI().toURL() } + .toTypedArray() + + companion object { + private val logger = KotlinLogging.logger {} + } + + override fun transformExecutionsBeforeMinimization( + executions: List, + classUnderTestId: ClassId + ): List { + val annotationsToIgnoreCoverage = + annotationsToIgnoreCoverage.mapNotNull { utContext.classLoader.tryLoadClass(it.name) } + + val classLoaderToIncludeCoverageFrom = URLClassLoader(urlsToIncludeCoverageFrom, null) + + val classesToIncludeCoverageFromCache = mutableMapOf() + + return executions.map { execution -> + val coverage = execution.coverage ?: return@map execution + + val filteredCoveredInstructions = + coverage.coveredInstructions + .filter { instruction -> + val instrClassName = instruction.className + + classesToIncludeCoverageFromCache.getOrPut(instrClassName) { + instrClassName == classUnderTestId.name || + (classLoaderToIncludeCoverageFrom.hasOnClasspath(instrClassName) && + !hasAnnotations(instrClassName, annotationsToIgnoreCoverage)) + } + } + .ifEmpty { + if (keepOriginalCoverageOnEmptyFilteredCoverage) { + logger.warn("Execution covered instruction list became empty. Proceeding with not filtered instruction list.") + coverage.coveredInstructions + } else { + logger.warn("Execution covered instruction list became empty. Proceeding with empty coverage.") + emptyList() + } + } + + execution.copy( + coverage = coverage.copy( + coveredInstructions = filteredCoveredInstructions + ) + ) + } + } + + private fun hasAnnotations(className: String, annotations: List>): Boolean = + utContext + .classLoader + .loadClass(className) + .annotations + .any { existingAnnotation -> + annotations.any { annotation -> + annotation.isInstance(existingAnnotation) + } + } +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt index 3b35ddca46..21debdb4b5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt @@ -17,5 +17,5 @@ class SimpleApplicationContext( override fun createConcreteExecutionContext( fullClasspath: String, classpathWithoutDependencies: String - ): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath, classpathWithoutDependencies) + ): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath) } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt index dc910bb3fc..bdbd67c0c2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt @@ -1,14 +1,35 @@ package org.utbot.framework.context.simple import org.utbot.framework.context.ConcreteExecutionContext -import org.utbot.framework.plugin.api.UtError +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult +import org.utbot.framework.plugin.api.UtExecution +import org.utbot.fuzzer.IdentityPreservingIdGenerator +import org.utbot.fuzzing.JavaValueProvider +import org.utbot.fuzzing.ValueProvider +import org.utbot.fuzzing.defaultValueProviders +import org.utbot.instrumentation.ConcreteExecutor +import org.utbot.instrumentation.instrumentation.execution.SimpleUtExecutionInstrumentation +import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation +import java.io.File -class SimpleConcreteExecutionContext( - // TODO these properties will be used later (to fulfill TODO in ConcreteExecutionContext) - val fullClassPath: String, - val classpathWithoutDependencies: String -) : ConcreteExecutionContext { - override fun preventsFurtherTestGeneration(): Boolean = false +class SimpleConcreteExecutionContext(fullClassPath: String) : ConcreteExecutionContext { + override val instrumentationFactory: UtExecutionInstrumentation.Factory<*> = + SimpleUtExecutionInstrumentation.Factory(fullClassPath.split(File.pathSeparator).toSet()) - override fun getErrors(): List = emptyList() + override fun loadContext( + concreteExecutor: ConcreteExecutor, + ): ConcreteContextLoadingResult = ConcreteContextLoadingResult.successWithoutExceptions() + + override fun transformExecutionsBeforeMinimization( + executions: List, + classUnderTestId: ClassId + ): List = executions + + override fun tryCreateValueProvider( + concreteExecutor: ConcreteExecutor, + classUnderTest: ClassId, + idGenerator: IdentityPreservingIdGenerator + ): JavaValueProvider = ValueProvider.of(defaultValueProviders(idGenerator)) } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt index 15fab49219..82b91e6ca7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt @@ -4,7 +4,7 @@ import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.SpringCodeGenerationContext -import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult /** * Data we get from Spring application context @@ -19,6 +19,6 @@ interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationCon val injectedTypes: Set val allInjectedSuperTypes: Set - override var springContextLoadingResult: SpringContextLoadingResult? + override var concreteContextLoadingResult: ConcreteContextLoadingResult? fun getBeansAssignableTo(classId: ClassId): List } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 790e9320c2..4b0852ceeb 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -7,11 +7,13 @@ import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.context.NonNullSpeculator import org.utbot.framework.context.TypeReplacer +import org.utbot.framework.context.custom.CoverageFilteringConcreteExecutionContext import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.SpringTestType +import org.utbot.framework.plugin.api.util.SpringModelUtils.entityClassIds import org.utbot.framework.plugin.api.util.allSuperTypes import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass @@ -30,15 +32,37 @@ class SpringApplicationContextImpl( override val typeReplacer: TypeReplacer = SpringTypeReplacer(delegateContext.typeReplacer, this) override val nonNullSpeculator: NonNullSpeculator = SpringNonNullSpeculator(delegateContext.nonNullSpeculator, this) - override var springContextLoadingResult: SpringContextLoadingResult? = null + override var concreteContextLoadingResult: ConcreteContextLoadingResult? = null override fun createConcreteExecutionContext( fullClasspath: String, classpathWithoutDependencies: String - ): ConcreteExecutionContext = SpringConcreteExecutionContext( - delegateContext.createConcreteExecutionContext(fullClasspath, classpathWithoutDependencies), - this - ) + ): ConcreteExecutionContext { + var delegateConcreteExecutionContext = delegateContext.createConcreteExecutionContext( + fullClasspath, + classpathWithoutDependencies + ) + + // to avoid filtering out all coverage, we only filter + // coverage when `classpathWithoutDependencies` is provided + // (e.g. when we are launched from IDE plugin) + if (classpathWithoutDependencies.isNotEmpty()) + delegateConcreteExecutionContext = CoverageFilteringConcreteExecutionContext( + delegateContext = delegateConcreteExecutionContext, + classpathToIncludeCoverageFrom = classpathWithoutDependencies, + annotationsToIgnoreCoverage = entityClassIds.toSet(), + keepOriginalCoverageOnEmptyFilteredCoverage = true + ) + + return when (springTestType) { + SpringTestType.UNIT_TEST -> delegateConcreteExecutionContext + SpringTestType.INTEGRATION_TEST -> SpringIntegrationTestConcreteExecutionContext( + delegateConcreteExecutionContext, + classpathWithoutDependencies, + this + ) + } + } override fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> // some bean classes may fail to load diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt deleted file mode 100644 index 5d1a87f565..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringConcreteExecutionContext.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.utbot.framework.context.spring - -import org.utbot.framework.context.ConcreteExecutionContext -import org.utbot.framework.plugin.api.UtError - -class SpringConcreteExecutionContext( - private val delegateContext: ConcreteExecutionContext, - private val springApplicationContext: SpringApplicationContext, -) : ConcreteExecutionContext { - override fun preventsFurtherTestGeneration(): Boolean = - delegateContext.preventsFurtherTestGeneration() || - springApplicationContext.springContextLoadingResult?.contextLoaded == false - - override fun getErrors(): List = - springApplicationContext.springContextLoadingResult?.exceptions?.map { exception -> - UtError( - "Failed to load Spring application context", - exception - ) - }.orEmpty() + delegateContext.getErrors() -} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestConcreteExecutionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestConcreteExecutionContext.kt new file mode 100644 index 0000000000..87b7387e03 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestConcreteExecutionContext.kt @@ -0,0 +1,119 @@ +package org.utbot.framework.context.spring + +import mu.KotlinLogging +import org.utbot.common.tryLoadClass +import org.utbot.framework.context.ConcreteExecutionContext +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult +import org.utbot.framework.plugin.api.SpringRepositoryId +import org.utbot.framework.plugin.api.SpringSettings +import org.utbot.framework.plugin.api.UtExecution +import org.utbot.framework.plugin.api.util.SpringModelUtils +import org.utbot.framework.plugin.api.util.allDeclaredFieldIds +import org.utbot.framework.plugin.api.util.jField +import org.utbot.framework.plugin.api.util.utContext +import org.utbot.fuzzer.IdentityPreservingIdGenerator +import org.utbot.fuzzing.JavaValueProvider +import org.utbot.fuzzing.ValueProvider +import org.utbot.fuzzing.providers.FieldValueProvider +import org.utbot.fuzzing.providers.ObjectValueProvider +import org.utbot.fuzzing.spring.SavedEntityValueProvider +import org.utbot.fuzzing.spring.SpringBeanValueProvider +import org.utbot.instrumentation.ConcreteExecutor +import org.utbot.instrumentation.getRelevantSpringRepositories +import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation +import org.utbot.instrumentation.instrumentation.spring.SpringUtExecutionInstrumentation +import org.utbot.instrumentation.tryLoadingSpringContext +import java.io.File + +class SpringIntegrationTestConcreteExecutionContext( + private val delegateContext: ConcreteExecutionContext, + classpathWithoutDependencies: String, + private val springApplicationContext: SpringApplicationContext, +) : ConcreteExecutionContext { + private val springSettings = (springApplicationContext.springSettings as? SpringSettings.PresentSpringSettings) ?: + error("Integration tests cannot be generated without Spring configuration") + + companion object { + private val logger = KotlinLogging.logger {} + } + + override val instrumentationFactory: UtExecutionInstrumentation.Factory<*> = + SpringUtExecutionInstrumentation.Factory( + delegateContext.instrumentationFactory, + springSettings, + springApplicationContext.beanDefinitions, + buildDirs = classpathWithoutDependencies.split(File.pathSeparator) + .map { File(it).toURI().toURL() } + .toTypedArray(), + ) + + override fun loadContext( + concreteExecutor: ConcreteExecutor, + ): ConcreteContextLoadingResult = + delegateContext.loadContext(concreteExecutor).andThen { + springApplicationContext.concreteContextLoadingResult ?: concreteExecutor.tryLoadingSpringContext().also { + springApplicationContext.concreteContextLoadingResult = it + } + } + + override fun transformExecutionsBeforeMinimization( + executions: List, + classUnderTestId: ClassId + ): List = delegateContext.transformExecutionsBeforeMinimization(executions, classUnderTestId) + + override fun tryCreateValueProvider( + concreteExecutor: ConcreteExecutor, + classUnderTest: ClassId, + idGenerator: IdentityPreservingIdGenerator + ): JavaValueProvider { + if (springApplicationContext.getBeansAssignableTo(classUnderTest).isEmpty()) + error( + "No beans of type ${classUnderTest.name} are found. " + + "Try choosing different Spring configuration or adding beans to " + + springSettings.configuration.fullDisplayName + ) + + val relevantRepositories = concreteExecutor.getRelevantSpringRepositories(classUnderTest) + logger.info { "Detected relevant repositories for class $classUnderTest: $relevantRepositories" } + + // spring should try to generate bean values, but if it fails, then object value provider is used for it + val springBeanValueProvider = SpringBeanValueProvider( + idGenerator, + beanNameProvider = { classId -> + springApplicationContext.getBeansAssignableTo(classId).map { it.beanName } + }, + relevantRepositories = relevantRepositories + ).withFallback(ObjectValueProvider(idGenerator)) + + return delegateContext.tryCreateValueProvider(concreteExecutor, classUnderTest, idGenerator) + .except { p -> p is ObjectValueProvider } + .with(springBeanValueProvider) + .with(createSavedEntityValueProviders(relevantRepositories, idGenerator)) + .with(createFieldValueProviders(relevantRepositories, idGenerator)) + } + + private fun createSavedEntityValueProviders( + relevantRepositories: Set, + idGenerator: IdentityPreservingIdGenerator + ) = ValueProvider.of(relevantRepositories.map { SavedEntityValueProvider(idGenerator, it) }) + + private fun createFieldValueProviders( + relevantRepositories: Set, + idGenerator: IdentityPreservingIdGenerator + ): JavaValueProvider { + val generatedValueAnnotationClasses = SpringModelUtils.generatedValueClassIds.mapNotNull { + @Suppress("UNCHECKED_CAST") // type system fails to understand that @GeneratedValue is indeed an annotation + utContext.classLoader.tryLoadClass(it.name) as Class? + } + + val generatedValueFieldIds = + relevantRepositories + .flatMap { it.entityClassId.allDeclaredFieldIds } + .filter { fieldId -> generatedValueAnnotationClasses.any { fieldId.jField.isAnnotationPresent(it) } } + logger.info { "Detected @GeneratedValue fields: $generatedValueFieldIds" } + + return ValueProvider.of(generatedValueFieldIds.map { FieldValueProvider(idGenerator, it) }) + } +} \ No newline at end of file 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 030e7736fa..ff0b8962e2 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 @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.yield @@ -28,10 +29,8 @@ import org.utbot.framework.UtSettings.warmupConcreteExecution import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.simple.SimpleApplicationContext import org.utbot.framework.context.simple.SimpleMockerContext -import org.utbot.framework.context.spring.SpringApplicationContext import org.utbot.framework.plugin.api.utils.checkFrameworkDependencies import org.utbot.framework.minimization.minimizeTestCase -import org.utbot.framework.plugin.api.util.SpringModelUtils.entityClassIds import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.plugin.services.JdkInfo @@ -43,10 +42,6 @@ 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.SimpleUtExecutionInstrumentation -import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation -import org.utbot.instrumentation.instrumentation.spring.SpringUtExecutionInstrumentation -import org.utbot.instrumentation.tryLoadingSpringContext import org.utbot.instrumentation.warmup import org.utbot.taint.TaintConfigurationProvider import java.io.File @@ -87,29 +82,6 @@ open class TestCaseGenerator( classpathWithoutDependencies = buildDirs.joinToString(File.pathSeparator) ) - private val executionInstrumentationFactory: UtExecutionInstrumentation.Factory<*> = run { - val simpleUtExecutionInstrumentationFactory = SimpleUtExecutionInstrumentation.Factory(classpathForEngine.split(File.pathSeparator).toSet()) - when (applicationContext) { - is SpringApplicationContext -> { - when (val settings = applicationContext.springSettings) { - is AbsentSpringSettings -> simpleUtExecutionInstrumentationFactory - is PresentSpringSettings -> when (applicationContext.springTestType) { - UNIT_TEST -> simpleUtExecutionInstrumentationFactory - INTEGRATION_TEST -> SpringUtExecutionInstrumentation.Factory( - simpleUtExecutionInstrumentationFactory, - settings, - applicationContext.beanDefinitions, - buildDirs.map { it.toURL() }.toTypedArray(), - ) - } - } - } - - else -> simpleUtExecutionInstrumentationFactory - } - } - - private val classpathForEngine: String get() = (buildDirs + listOfNotNull(classpath)).joinToString(File.pathSeparator) @@ -133,7 +105,7 @@ open class TestCaseGenerator( // force pool to create an appropriate executor // TODO ensure that instrumented process that starts here is properly terminated ConcreteExecutor( - executionInstrumentationFactory, + concreteExecutionContext.instrumentationFactory, classpathForEngine, ).apply { warmup() @@ -147,12 +119,12 @@ open class TestCaseGenerator( TestSelectionStrategyType.DO_NOT_MINIMIZE_STRATEGY -> executions TestSelectionStrategyType.COVERAGE_STRATEGY -> minimizeTestCase( - when (applicationContext) { - is SpringApplicationContext -> executions.filterCoveredInstructions(classUnderTestId) - else -> executions - } + concreteExecutionContext.transformExecutionsBeforeMinimization( + executions, + classUnderTestId + ), + executionToTestSuite = { it.result::class.java } ) - { it.result::class.java } } @Throws(CancellationException::class) @@ -167,9 +139,9 @@ open class TestCaseGenerator( if (isCanceled()) return@flow - doContextDependentPreparationForTestGeneration() - concreteExecutionContext.getErrors().forEach { emit(it) } - if (concreteExecutionContext.preventsFurtherTestGeneration()) + val contextLoadingResult = loadConcreteExecutionContext() + emitAll(flowOf(*contextLoadingResult.utErrors.toTypedArray())) + if (!contextLoadingResult.contextLoaded) return@flow try { @@ -201,13 +173,13 @@ open class TestCaseGenerator( ): List = ConcreteExecutor.defaultPool.use { _ -> // TODO: think on appropriate way to close instrumented processes if (isCanceled()) return@use methods.map { UtMethodTestSet(it) } - doContextDependentPreparationForTestGeneration() + val contextLoadingResult = loadConcreteExecutionContext() val method2errors: Map> = methods.associateWith { - concreteExecutionContext.getErrors().associateTo(mutableMapOf()) { it.description to 1 } + contextLoadingResult.utErrors.associateTo(mutableMapOf()) { it.description to 1 } } - if (concreteExecutionContext.preventsFurtherTestGeneration()) + if (!contextLoadingResult.contextLoaded) return@use methods.map { method -> UtMethodTestSet(method, errors = method2errors.getValue(method)) } val executionStartInMillis = System.currentTimeMillis() @@ -340,7 +312,7 @@ open class TestCaseGenerator( mockStrategy = mockStrategyApi.toModel(), chosenClassesToMockAlways = chosenClassesToMockAlways, applicationContext = applicationContext, - executionInstrumentationFactory = executionInstrumentationFactory, + concreteExecutionContext = concreteExecutionContext, solverTimeoutInMillis = executionTimeEstimator.updatedSolverCheckTimeoutMillis, userTaintConfigurationProvider = userTaintConfigurationProvider, ) @@ -398,91 +370,9 @@ open class TestCaseGenerator( } } - private fun List.filterCoveredInstructions(classUnderTestId: ClassId): List { - // Do nothing when we were launched not from IDEA or when there are no executions - if (buildDirs.isEmpty() || this.isEmpty()) return this - - // List of annotations that we want to find in execution instructions - // in order to exclude such instructions for some reason - // E.g. we exclude instructions (which classes have @Entity) when it is not a class under test - // because we are not interested in coverage which was possibly produced by Spring itself - val annotationsToIgnoreCoverage = - entityClassIds.mapNotNull { utContext.classLoader.tryLoadClass(it.name) } - - val buildDirsClassLoader = createBuildDirsClassLoader() - val isClassOnUserClasspathCache = mutableMapOf() - - // Here we filter out instructions from third-party libraries - // Also, we filter out instructions that operate - // in classes marked with annotations from [annotationsToIgnore] - // and in standard java libs - return this.map { execution -> - val coverage = execution.coverage ?: return@map execution - - val filteredCoveredInstructions = - coverage.coveredInstructions - .filter { instruction -> - val instrClassName = instruction.className - - val isInstrClassOnClassPath = - isClassOnUserClasspathCache.getOrPut(instrClassName) { - buildDirsClassLoader.hasOnClasspath(instrClassName) - } - - // We want to - // - always keep instructions that are in class under test - // - ignore instructions in classes marked with annotations from [annotationsToIgnore] - return@filter instrClassName == classUnderTestId.name || - (isInstrClassOnClassPath && !hasAnnotations(instrClassName, annotationsToIgnoreCoverage)) - } - .ifEmpty { - coverage.coveredInstructions - .also { - logger.warn("Execution covered instruction list became empty. Proceeding with not filtered instruction list.") - } - } - - execution.copy( - coverage = Coverage( - coveredInstructions = filteredCoveredInstructions, - instructionsCount = coverage.instructionsCount, - missedInstructions = coverage.missedInstructions - ) - ) - } - } - - private fun createBuildDirsClassLoader(): URLClassLoader { - val urls = buildDirs.map { it.toURL() }.toTypedArray() - return URLClassLoader(urls, null) - } - - private fun hasAnnotations(className: String, annotations: List>): Boolean = - utContext - .classLoader - .loadClass(className) - .annotations - .any { existingAnnotation -> - annotations.any { annotation -> - annotation.isInstance(existingAnnotation) - } - } - - private fun doContextDependentPreparationForTestGeneration() { - when (applicationContext) { - is SpringApplicationContext -> when (applicationContext.springTestType) { - UNIT_TEST -> Unit - INTEGRATION_TEST -> - if (applicationContext.springContextLoadingResult == null) - // force pool to create an appropriate executor - applicationContext.springContextLoadingResult = ConcreteExecutor( - executionInstrumentationFactory, - classpathForEngine - ).tryLoadingSpringContext() - } - else -> Unit - } + private fun loadConcreteExecutionContext(): ConcreteContextLoadingResult { + // force pool to create an appropriate executor + val concreteExecutor = ConcreteExecutor(concreteExecutionContext.instrumentationFactory, classpathForEngine) + return concreteExecutionContext.loadContext(concreteExecutor) } } - - diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt index ddbbe76a71..5f80edec97 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt @@ -20,7 +20,7 @@ import org.utbot.framework.plugin.api.InstrumentedProcessDeathException import org.utbot.common.logException import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.FieldId -import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult import org.utbot.framework.plugin.api.SpringRepositoryId import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.signature @@ -293,7 +293,7 @@ fun ConcreteExecutor<*, *>.getRelevantSpringRepositories(classId: ClassId): Set< } } -fun ConcreteExecutor<*, *>.tryLoadingSpringContext(): SpringContextLoadingResult = runBlocking { +fun ConcreteExecutor<*, *>.tryLoadingSpringContext(): ConcreteContextLoadingResult = runBlocking { withProcess { val result = instrumentedProcessModel.tryLoadingSpringContext.startSuspending(lifetime, Unit) kryoHelper.readObject(result.springContextLoadingResult) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt index 64cc38c6fe..05e278dabc 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/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.FieldId -import org.utbot.framework.plugin.api.SpringContextLoadingResult +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult import org.utbot.framework.plugin.api.SpringRepositoryId import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.util.jClass @@ -48,9 +48,9 @@ class SpringUtExecutionInstrumentation( private const val SPRING_COMMONS_JAR_FILENAME = "utbot-spring-commons-shadow.jar" } - fun tryLoadingSpringContext(): SpringContextLoadingResult { + fun tryLoadingSpringContext(): ConcreteContextLoadingResult { val apiProviderResult = instrumentationContext.springApiProviderResult - return SpringContextLoadingResult( + return ConcreteContextLoadingResult( contextLoaded = apiProviderResult.result.isSuccess, exceptions = apiProviderResult.exceptions ) diff --git a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/UTSpringContextLoadingException.kt b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/UTSpringContextLoadingException.kt index 471c706497..d8bbf2b716 100644 --- a/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/UTSpringContextLoadingException.kt +++ b/utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/UTSpringContextLoadingException.kt @@ -6,6 +6,6 @@ package org.utbot.spring.api * and parts of stack trace inside Spring and user application. */ class UTSpringContextLoadingException(override val cause: Throwable) : Exception( - "UTBot failed to load Spring application context", + "Failed to load Spring application context", cause ) From 48d3586c5bc1ab3c34598df2fdaf88f2c3bbbbee Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 17 Jul 2023 17:47:21 +0300 Subject: [PATCH 12/20] Remove unused imports --- .../kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt | 2 -- 1 file changed, 2 deletions(-) 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 ff0b8962e2..7980c7e3be 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 @@ -14,7 +14,6 @@ import kotlinx.coroutines.yield import mu.KLogger import mu.KotlinLogging import org.utbot.common.* -import org.utbot.common.PathUtil.toURL import org.utbot.engine.EngineController import org.utbot.engine.Mocker import org.utbot.engine.UtBotSymbolicEngine @@ -45,7 +44,6 @@ import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.warmup import org.utbot.taint.TaintConfigurationProvider import java.io.File -import java.net.URLClassLoader import java.nio.file.Path import kotlin.coroutines.cancellation.CancellationException import kotlin.math.min From 10f5b659cc426a4af463552bfb8e9ec7f5feef5b Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 18 Jul 2023 15:50:16 +0300 Subject: [PATCH 13/20] Fix compilation after rebase --- .../src/main/kotlin/org/utbot/framework/plugin/api/Api.kt | 1 + 1 file changed, 1 insertion(+) 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 67b6a5f576..4626e1564f 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 @@ -8,6 +8,7 @@ package org.utbot.framework.plugin.api +import mu.KotlinLogging import org.utbot.common.FileUtil import org.utbot.common.isDefaultValue import org.utbot.common.withToStringThreadLocalReentrancyGuard From fbbddbf5af63079e49542b6816bd9903c42a5d3a Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 18 Jul 2023 16:48:56 +0300 Subject: [PATCH 14/20] Avoid when by `projectType` when choosing `CgVariableConstructor` --- .../codegen/generator/SpringCodeGenerator.kt | 9 +++- .../services/language/CgLanguageAssistant.kt | 46 +++++++++++-------- .../language/JavaCgLanguageAssistant.kt | 2 +- .../language/KotlinCgLanguageAssistant.kt | 2 +- .../codegen/JsCgLanguageAssistant.kt | 4 +- .../codegen/PythonCgLanguageAssistant.kt | 5 +- 6 files changed, 41 insertions(+), 27 deletions(-) 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 0fa4c449b1..5c0a61a3d1 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 @@ -7,11 +7,14 @@ import org.utbot.framework.codegen.domain.ProjectType 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.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.builders.SpringTestClassModelBuilder import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.codegen.tree.CgSpringIntegrationTestClassConstructor import org.utbot.framework.codegen.tree.CgSpringUnitTestClassConstructor +import org.utbot.framework.codegen.tree.CgSpringVariableConstructor +import org.utbot.framework.codegen.tree.CgVariableConstructor import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage @@ -50,7 +53,11 @@ class SpringCodeGenerator( forceStaticMocking, generateWarningsForStaticMocking, codegenLanguage, - cgLanguageAssistant, + cgLanguageAssistant = object : CgLanguageAssistant by cgLanguageAssistant { + override fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = + // TODO decorate original `cgLanguageAssistant.getVariableConstructorBy(context)` + CgSpringVariableConstructor(context) + }, parameterizedTestSource, runtimeExceptionTestsBehaviour, hangingTestsTimeout, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/CgLanguageAssistant.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/CgLanguageAssistant.kt index db1f942dcc..9efa0e1996 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/CgLanguageAssistant.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/CgLanguageAssistant.kt @@ -1,6 +1,5 @@ package org.utbot.framework.codegen.services.language -import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.context.TestClassContext import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.renderer.CgPrinter @@ -16,11 +15,10 @@ import org.utbot.framework.codegen.tree.CgMethodConstructor import org.utbot.framework.codegen.tree.CgStatementConstructor import org.utbot.framework.codegen.tree.CgStatementConstructorImpl import org.utbot.framework.codegen.tree.CgVariableConstructor -import org.utbot.framework.codegen.tree.CgSpringVariableConstructor import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage -abstract class CgLanguageAssistant { +interface CgLanguageAssistant { companion object { fun getByCodegenLanguage(language: CodegenLanguage) = when (language) { @@ -30,31 +28,41 @@ abstract class CgLanguageAssistant { } } - open val outerMostTestClassContent: TestClassContext? = null + val outerMostTestClassContent: TestClassContext? - abstract val extension: String + val extension: String - abstract val languageKeywords: Set + val languageKeywords: Set - abstract fun testClassName( + fun testClassName( testClassCustomName: String?, testClassPackageName: String, classUnderTest: ClassId ): Pair - open fun getNameGeneratorBy(context: CgContext): CgNameGenerator = CgNameGeneratorImpl(context) - open fun getCallableAccessManagerBy(context: CgContext): CgCallableAccessManager = - CgCallableAccessManagerImpl(context) - open fun getStatementConstructorBy(context: CgContext): CgStatementConstructor = CgStatementConstructorImpl(context) + fun getNameGeneratorBy(context: CgContext): CgNameGenerator + fun getCallableAccessManagerBy(context: CgContext): CgCallableAccessManager + fun getStatementConstructorBy(context: CgContext): CgStatementConstructor - open fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = when (context.projectType) { - ProjectType.Spring -> CgSpringVariableConstructor(context) - else -> CgVariableConstructor(context) - } + fun getVariableConstructorBy(context: CgContext): CgVariableConstructor + + fun getMethodConstructorBy(context: CgContext): CgMethodConstructor + fun getCgFieldStateManager(context: CgContext): CgFieldStateManager + + fun getLanguageTestFrameworkManager(): LanguageTestFrameworkManager + fun cgRenderer(context: CgRendererContext, printer: CgPrinter): CgAbstractRenderer +} + +abstract class AbstractCgLanguageAssistant : CgLanguageAssistant { + override val outerMostTestClassContent: TestClassContext? get() = null + + override fun getNameGeneratorBy(context: CgContext): CgNameGenerator = CgNameGeneratorImpl(context) + override fun getCallableAccessManagerBy(context: CgContext): CgCallableAccessManager = + CgCallableAccessManagerImpl(context) + override fun getStatementConstructorBy(context: CgContext): CgStatementConstructor = CgStatementConstructorImpl(context) - open fun getMethodConstructorBy(context: CgContext): CgMethodConstructor = CgMethodConstructor(context) - open fun getCgFieldStateManager(context: CgContext): CgFieldStateManager = CgFieldStateManagerImpl(context) + override fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = CgVariableConstructor(context) - abstract fun getLanguageTestFrameworkManager(): LanguageTestFrameworkManager - abstract fun cgRenderer(context: CgRendererContext, printer: CgPrinter): CgAbstractRenderer + override fun getMethodConstructorBy(context: CgContext): CgMethodConstructor = CgMethodConstructor(context) + override fun getCgFieldStateManager(context: CgContext): CgFieldStateManager = CgFieldStateManagerImpl(context) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/JavaCgLanguageAssistant.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/JavaCgLanguageAssistant.kt index db236ed252..4d084339cb 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/JavaCgLanguageAssistant.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/JavaCgLanguageAssistant.kt @@ -8,7 +8,7 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.JVMTestFrameworkManager import org.utbot.framework.plugin.api.utils.testClassNameGenerator -object JavaCgLanguageAssistant : CgLanguageAssistant() { +object JavaCgLanguageAssistant : AbstractCgLanguageAssistant() { override val extension: String get() = ".java" diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/KotlinCgLanguageAssistant.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/KotlinCgLanguageAssistant.kt index 1e5e40e474..2a37bfd5bf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/KotlinCgLanguageAssistant.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/language/KotlinCgLanguageAssistant.kt @@ -8,7 +8,7 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.JVMTestFrameworkManager import org.utbot.framework.plugin.api.utils.testClassNameGenerator -object KotlinCgLanguageAssistant : CgLanguageAssistant() { +object KotlinCgLanguageAssistant : AbstractCgLanguageAssistant() { override val extension: String get() = ".kt" diff --git a/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt b/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt index fd8e2a47dc..59e1f79d6c 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt @@ -10,11 +10,11 @@ import org.utbot.framework.codegen.domain.context.TestClassContext import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgPrinter import org.utbot.framework.codegen.renderer.CgRendererContext -import org.utbot.framework.codegen.services.language.CgLanguageAssistant +import org.utbot.framework.codegen.services.language.AbstractCgLanguageAssistant import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.utils.testClassNameGenerator -object JsCgLanguageAssistant : CgLanguageAssistant() { +object JsCgLanguageAssistant : AbstractCgLanguageAssistant() { override val outerMostTestClassContent: TestClassContext = TestClassContext() diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/PythonCgLanguageAssistant.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/PythonCgLanguageAssistant.kt index b6befec04d..7fbfa5b617 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/PythonCgLanguageAssistant.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/PythonCgLanguageAssistant.kt @@ -5,7 +5,7 @@ import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.renderer.CgPrinter import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgRendererContext -import org.utbot.framework.codegen.services.language.CgLanguageAssistant +import org.utbot.framework.codegen.services.language.AbstractCgLanguageAssistant import org.utbot.framework.plugin.api.ClassId import org.utbot.python.framework.api.python.PythonTree import org.utbot.python.framework.codegen.model.constructor.name.PythonCgNameGenerator @@ -16,8 +16,7 @@ import org.utbot.python.framework.codegen.model.constructor.tree.PythonCgVariabl import org.utbot.python.framework.codegen.model.constructor.visitor.CgPythonRenderer import org.utbot.python.framework.codegen.model.services.access.PythonCgFieldStateManager -object PythonCgLanguageAssistant : CgLanguageAssistant() { - +object PythonCgLanguageAssistant : AbstractCgLanguageAssistant() { override val extension: String get() = ".py" From 8ce19807226b42ad6ec0b01c54f65483a502f797 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 18 Jul 2023 17:19:54 +0300 Subject: [PATCH 15/20] Introduce `CodeGeneratorParams` data class, to avoid repeating same params in functions and constructors --- .../utbot/cli/GenerateTestsAbstractCommand.kt | 21 ++--- .../org/utbot/external/api/UtBotJavaApi.kt | 3 + .../generator/AbstractCodeGenerator.kt | 69 +++++----------- .../codegen/generator/CodeGenerator.kt | 48 +---------- .../codegen/generator/CodeGeneratorParams.kt | 33 ++++++++ .../codegen/generator/SpringCodeGenerator.kt | 61 +++----------- .../GenerateTestsAndSarifReportFacade.kt | 21 ++--- .../framework/process/EngineProcessMain.kt | 80 +++++++------------ .../main/kotlin/org/utbot/contest/Contest.kt | 3 + .../codegen/model/PythonCodeGenerator.kt | 33 ++++---- 10 files changed, 144 insertions(+), 228 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGeneratorParams.kt diff --git a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt index 0dbf64819b..4d39fd2c1c 100644 --- a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt +++ b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt @@ -23,6 +23,7 @@ import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.testFrameworkByName import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage @@ -210,15 +211,17 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) : val generateWarningsForStaticMocking = forceStaticMocking == ForceStaticMocking.FORCE && staticsMocking is NoStaticMocking return CodeGenerator( - testFramework = testFrameworkByName(testFramework), - classUnderTest = classUnderTest, - //TODO: Support Spring projects in utbot-cli if requested - projectType = ProjectType.PureJvm, - codegenLanguage = codegenLanguage, - cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), - staticsMocking = staticsMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = generateWarningsForStaticMocking, + CodeGeneratorParams( + testFramework = testFrameworkByName(testFramework), + classUnderTest = classUnderTest, + //TODO: Support Spring projects in utbot-cli if requested + projectType = ProjectType.PureJvm, + codegenLanguage = codegenLanguage, + cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), + staticsMocking = staticsMocking, + forceStaticMocking = forceStaticMocking, + generateWarningsForStaticMocking = generateWarningsForStaticMocking, + ) ) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt index 89b778fa2c..2168d67471 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt @@ -10,6 +10,7 @@ import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult @@ -85,6 +86,7 @@ object UtBotJavaApi { return withUtContext(utContext) { val codeGenerator = CodeGenerator( + CodeGeneratorParams( classUnderTest = classUnderTest.id, projectType = projectType, testFramework = testFramework, @@ -96,6 +98,7 @@ object UtBotJavaApi { generateWarningsForStaticMocking = generateWarningsForStaticMocking, testClassPackageName = testClassPackageName ) + ) codeGenerator.generateAsString(testSets, destinationClassName) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt index dca05eed0e..a7a05831f5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt @@ -1,64 +1,37 @@ package org.utbot.framework.codegen.generator import mu.KotlinLogging -import org.utbot.framework.codegen.domain.ForceStaticMocking -import org.utbot.framework.codegen.domain.HangingTestsTimeout -import org.utbot.framework.codegen.domain.ParametrizedTestSource -import org.utbot.framework.codegen.domain.ProjectType -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.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgClassFile import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.renderer.CgAbstractRenderer -import org.utbot.framework.codegen.services.language.CgLanguageAssistant -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.UtMethodTestSet import java.time.LocalDateTime import java.time.format.DateTimeFormatter -abstract class AbstractCodeGenerator( - classUnderTest: ClassId, - projectType: ProjectType, - paramNames: MutableMap> = mutableMapOf(), - generateUtilClassFile: Boolean = false, - testFramework: TestFramework = TestFramework.defaultItem, - mockFramework: MockFramework = MockFramework.defaultItem, - staticsMocking: StaticsMocking = StaticsMocking.defaultItem, - forceStaticMocking: ForceStaticMocking = ForceStaticMocking.defaultItem, - generateWarningsForStaticMocking: Boolean = true, - codegenLanguage: CodegenLanguage = CodegenLanguage.defaultItem, - cgLanguageAssistant: CgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), - parameterizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem, - runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.defaultItem, - hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(), - enableTestsTimeout: Boolean = true, - testClassPackageName: String = classUnderTest.packageName, -) { +abstract class AbstractCodeGenerator(params: CodeGeneratorParams) { protected val logger = KotlinLogging.logger {} - open var context: CgContext = CgContext( - classUnderTest = classUnderTest, - projectType = projectType, - generateUtilClassFile = generateUtilClassFile, - paramNames = paramNames, - testFramework = testFramework, - mockFramework = mockFramework, - codegenLanguage = codegenLanguage, - cgLanguageAssistant = cgLanguageAssistant, - parametrizedTestSource = parameterizedTestSource, - staticsMocking = staticsMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = generateWarningsForStaticMocking, - runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, - hangingTestsTimeout = hangingTestsTimeout, - enableTestsTimeout = enableTestsTimeout, - testClassPackageName = testClassPackageName - ) + open var context: CgContext = with(params) { + CgContext( + classUnderTest = classUnderTest, + projectType = projectType, + generateUtilClassFile = generateUtilClassFile, + paramNames = paramNames, + testFramework = testFramework, + mockFramework = mockFramework, + codegenLanguage = codegenLanguage, + cgLanguageAssistant = cgLanguageAssistant, + parametrizedTestSource = parameterizedTestSource, + staticsMocking = staticsMocking, + forceStaticMocking = forceStaticMocking, + generateWarningsForStaticMocking = generateWarningsForStaticMocking, + runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, + hangingTestsTimeout = hangingTestsTimeout, + enableTestsTimeout = enableTestsTimeout, + testClassPackageName = testClassPackageName + ) + } //TODO: we support custom test class name only in utbot-online, probably support them in plugin as well fun generateAsString(testSets: Collection, testClassCustomName: String? = null): String = diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt index 8b4b75f70c..6e87df4a24 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt @@ -1,57 +1,13 @@ package org.utbot.framework.codegen.generator -import org.utbot.framework.codegen.domain.ForceStaticMocking -import org.utbot.framework.codegen.domain.HangingTestsTimeout -import org.utbot.framework.codegen.domain.ParametrizedTestSource -import org.utbot.framework.codegen.domain.ProjectType -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.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.builders.SimpleTestClassModelBuilder -import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.codegen.tree.CgSimpleTestClassConstructor import org.utbot.framework.codegen.tree.ututils.UtilClassKind 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 -open class CodeGenerator( - val classUnderTest: ClassId, - val projectType: ProjectType, - paramNames: MutableMap> = mutableMapOf(), - generateUtilClassFile: Boolean = false, - testFramework: TestFramework = TestFramework.defaultItem, - mockFramework: MockFramework = MockFramework.defaultItem, - staticsMocking: StaticsMocking = StaticsMocking.defaultItem, - forceStaticMocking: ForceStaticMocking = ForceStaticMocking.defaultItem, - generateWarningsForStaticMocking: Boolean = true, - codegenLanguage: CodegenLanguage = CodegenLanguage.defaultItem, - cgLanguageAssistant: CgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), - parameterizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem, - runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.defaultItem, - hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(), - enableTestsTimeout: Boolean = true, - testClassPackageName: String = classUnderTest.packageName, -): AbstractCodeGenerator( - classUnderTest, - projectType, - paramNames, - generateUtilClassFile, - testFramework, - mockFramework, - staticsMocking, - forceStaticMocking, - generateWarningsForStaticMocking, - codegenLanguage, - cgLanguageAssistant, - parameterizedTestSource, - runtimeExceptionTestsBehaviour, - hangingTestsTimeout, - enableTestsTimeout, - testClassPackageName, -) { +open class CodeGenerator(params: CodeGeneratorParams): AbstractCodeGenerator(params) { + val classUnderTest: ClassId = params.classUnderTest override fun generate(testSets: List): CodeGeneratorResult { val testClassModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGeneratorParams.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGeneratorParams.kt new file mode 100644 index 0000000000..5bbc205307 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGeneratorParams.kt @@ -0,0 +1,33 @@ +package org.utbot.framework.codegen.generator + +import org.utbot.framework.codegen.domain.ForceStaticMocking +import org.utbot.framework.codegen.domain.HangingTestsTimeout +import org.utbot.framework.codegen.domain.ParametrizedTestSource +import org.utbot.framework.codegen.domain.ProjectType +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.codegen.services.language.CgLanguageAssistant +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 + +data class CodeGeneratorParams( + val classUnderTest: ClassId, + val projectType: ProjectType, + val paramNames: MutableMap> = mutableMapOf(), + val generateUtilClassFile: Boolean = false, + val testFramework: TestFramework = TestFramework.defaultItem, + val mockFramework: MockFramework = MockFramework.defaultItem, + val staticsMocking: StaticsMocking = StaticsMocking.defaultItem, + val forceStaticMocking: ForceStaticMocking = ForceStaticMocking.defaultItem, + val generateWarningsForStaticMocking: Boolean = true, + val codegenLanguage: CodegenLanguage = CodegenLanguage.defaultItem, + val cgLanguageAssistant: CgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), + val parameterizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem, + val runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.defaultItem, + val hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(), + val enableTestsTimeout: Boolean = true, + val testClassPackageName: String = classUnderTest.packageName, +) \ No newline at end of file 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 5c0a61a3d1..9f0f4e5f98 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 @@ -1,12 +1,5 @@ package org.utbot.framework.codegen.generator -import org.utbot.framework.codegen.domain.ForceStaticMocking -import org.utbot.framework.codegen.domain.HangingTestsTimeout -import org.utbot.framework.codegen.domain.ParametrizedTestSource -import org.utbot.framework.codegen.domain.ProjectType -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.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.builders.SpringTestClassModelBuilder @@ -17,53 +10,25 @@ import org.utbot.framework.codegen.tree.CgSpringVariableConstructor import org.utbot.framework.codegen.tree.CgVariableConstructor import org.utbot.framework.codegen.tree.ututils.UtilClassKind 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.SpringTestType import org.utbot.framework.plugin.api.SpringCodeGenerationContext -import org.utbot.framework.plugin.api.SpringSettings.* +import org.utbot.framework.plugin.api.SpringSettings.AbsentSpringSettings +import org.utbot.framework.plugin.api.SpringSettings.PresentSpringSettings +import org.utbot.framework.plugin.api.SpringTestType class SpringCodeGenerator( - val classUnderTest: ClassId, - val projectType: ProjectType, val springCodeGenerationContext: SpringCodeGenerationContext, - paramNames: MutableMap> = mutableMapOf(), - generateUtilClassFile: Boolean = false, - testFramework: TestFramework = TestFramework.defaultItem, - mockFramework: MockFramework = MockFramework.defaultItem, - staticsMocking: StaticsMocking = StaticsMocking.defaultItem, - forceStaticMocking: ForceStaticMocking = ForceStaticMocking.defaultItem, - generateWarningsForStaticMocking: Boolean = true, - codegenLanguage: CodegenLanguage = CodegenLanguage.defaultItem, - cgLanguageAssistant: CgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), - parameterizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem, - runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.defaultItem, - hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(), - enableTestsTimeout: Boolean = true, - testClassPackageName: String = classUnderTest.packageName, + params: CodeGeneratorParams ) : AbstractCodeGenerator( - classUnderTest, - projectType, - paramNames, - generateUtilClassFile, - testFramework, - mockFramework, - staticsMocking, - forceStaticMocking, - generateWarningsForStaticMocking, - codegenLanguage, - cgLanguageAssistant = object : CgLanguageAssistant by cgLanguageAssistant { - override fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = - // TODO decorate original `cgLanguageAssistant.getVariableConstructorBy(context)` - CgSpringVariableConstructor(context) - }, - parameterizedTestSource, - runtimeExceptionTestsBehaviour, - hangingTestsTimeout, - enableTestsTimeout, - testClassPackageName, + params.copy( + cgLanguageAssistant = object : CgLanguageAssistant by params.cgLanguageAssistant { + override fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = + // TODO decorate original `params.cgLanguageAssistant.getVariableConstructorBy(context)` + CgSpringVariableConstructor(context) + } + ) ) { + val classUnderTest: ClassId = params.classUnderTest + override fun generate(testSets: List): CodeGeneratorResult { val testClassModel = SpringTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt index ac50a76489..26547c212b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt @@ -3,6 +3,7 @@ package org.utbot.framework.plugin.sarif import org.utbot.framework.codegen.domain.ForceStaticMocking import org.utbot.framework.codegen.domain.NoStaticMocking import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.plugin.api.TestCaseGenerator import org.utbot.framework.plugin.api.UtMethodTestSet @@ -70,15 +71,17 @@ class GenerateTestsAndSarifReportFacade( val isForceStaticMocking = sarifProperties.forceStaticMocking == ForceStaticMocking.FORCE return CodeGenerator( - classUnderTest = targetClass.classUnderTest.id, - projectType = sarifProperties.projectType, - testFramework = sarifProperties.testFramework, - mockFramework = sarifProperties.mockFramework, - staticsMocking = sarifProperties.staticsMocking, - forceStaticMocking = sarifProperties.forceStaticMocking, - generateWarningsForStaticMocking = isNoStaticMocking && isForceStaticMocking, - codegenLanguage = sarifProperties.codegenLanguage, - cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(sarifProperties.codegenLanguage), + CodeGeneratorParams( + classUnderTest = targetClass.classUnderTest.id, + projectType = sarifProperties.projectType, + testFramework = sarifProperties.testFramework, + mockFramework = sarifProperties.mockFramework, + staticsMocking = sarifProperties.staticsMocking, + forceStaticMocking = sarifProperties.forceStaticMocking, + generateWarningsForStaticMocking = isNoStaticMocking && isForceStaticMocking, + codegenLanguage = sarifProperties.codegenLanguage, + cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(sarifProperties.codegenLanguage), + ) ) } 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 ae1fdd32c1..e0bae27c8e 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 @@ -15,6 +15,7 @@ import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.testFrameworkByName import org.utbot.framework.codegen.generator.AbstractCodeGenerator import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.codegen.reports.TestsGenerationReport import org.utbot.framework.codegen.services.language.CgLanguageAssistant @@ -299,61 +300,34 @@ private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, co val forceStaticMocking: ForceStaticMocking = kryoHelper.readObject(forceStaticMocking) val projectType = ProjectType.valueOf(projectType) - return when (codeGenerationContext) { - is SpringCodeGenerationContext -> { - SpringCodeGenerator( - classUnderTest = classUnderTest, - projectType = projectType, - springCodeGenerationContext = 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, + val codeGeneratorParams = CodeGeneratorParams( + 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, + ) - 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, - ) - } + return when (codeGenerationContext) { + is SpringCodeGenerationContext -> SpringCodeGenerator(codeGenerationContext, codeGeneratorParams) + else -> CodeGenerator(codeGeneratorParams) } } } \ No newline at end of file diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt index e0812048a0..896cd35002 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt @@ -50,6 +50,7 @@ import kotlinx.coroutines.withTimeoutOrNull import org.utbot.framework.SummariesGenerationType import org.utbot.framework.codegen.domain.* import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.minimization.minimizeExecutions import org.utbot.framework.plugin.api.* @@ -218,6 +219,7 @@ fun runGeneration( val statsForClass = StatsForClass(project, cut.fqn) val codeGenerator = CodeGenerator( + CodeGeneratorParams( cut.classId, projectType = ProjectType.PureJvm, testFramework = junitByVersion(junitVersion), @@ -227,6 +229,7 @@ fun runGeneration( cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(CodegenLanguage.defaultItem), runtimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.PASS, ) + ) logger.info().measureTime({ "class ${cut.fqn}" }, { statsForClass }) { diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt index fc809207a0..878dc54be4 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt @@ -14,6 +14,7 @@ import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgPrinterImpl import org.utbot.framework.codegen.renderer.CgRendererContext @@ -59,21 +60,23 @@ class PythonCodeGenerator( enableTestsTimeout: Boolean = true, testClassPackageName: String = classUnderTest.packageName ) : CodeGenerator( - classUnderTest = classUnderTest, - projectType = ProjectType.Python, - paramNames = paramNames, - generateUtilClassFile = true, - testFramework = testFramework, - mockFramework = mockFramework, - staticsMocking = staticsMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = generateWarningsForStaticMocking, - parameterizedTestSource = parameterizedTestSource, - runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, - hangingTestsTimeout = hangingTestsTimeout, - enableTestsTimeout = enableTestsTimeout, - testClassPackageName = testClassPackageName, - cgLanguageAssistant = PythonCgLanguageAssistant, + CodeGeneratorParams( + classUnderTest = classUnderTest, + projectType = ProjectType.Python, + paramNames = paramNames, + generateUtilClassFile = true, + testFramework = testFramework, + mockFramework = mockFramework, + staticsMocking = staticsMocking, + forceStaticMocking = forceStaticMocking, + generateWarningsForStaticMocking = generateWarningsForStaticMocking, + parameterizedTestSource = parameterizedTestSource, + runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, + hangingTestsTimeout = hangingTestsTimeout, + enableTestsTimeout = enableTestsTimeout, + testClassPackageName = testClassPackageName, + cgLanguageAssistant = PythonCgLanguageAssistant, + ) ) { fun pythonGenerateAsStringWithTestReport( cgTestSets: List, From 5f3902b676d926da53026782569a533622b788ff Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 18 Jul 2023 17:42:54 +0300 Subject: [PATCH 16/20] Make `ApplicationContext` be responsible for creating appropriate code generator --- .../kotlin/org/utbot/framework/plugin/api/Api.kt | 8 -------- .../framework/codegen/generator/CodeGenerator.kt | 2 +- .../codegen/generator/SpringCodeGenerator.kt | 15 +++++++++------ .../CgSpringIntegrationTestClassConstructor.kt | 14 ++++++-------- .../utbot/framework/context/ApplicationContext.kt | 7 +++++-- .../context/simple/SimpleApplicationContext.kt | 6 ++++++ .../context/spring/SpringApplicationContext.kt | 9 +++++---- .../spring/SpringApplicationContextImpl.kt | 14 +++++++++++++- .../utbot/framework/process/EngineProcessMain.kt | 13 +++---------- .../plugin/generator/CodeGenerationController.kt | 4 ---- .../plugin/generator/UtTestsDialogProcessor.kt | 2 +- 11 files changed, 49 insertions(+), 45 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 4626e1564f..de2420497a 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 @@ -1319,14 +1319,6 @@ enum class TypeReplacementMode { NoImplementors, } -interface CodeGenerationContext - -interface SpringCodeGenerationContext : CodeGenerationContext { - val springTestType: SpringTestType - val springSettings: SpringSettings - val concreteContextLoadingResult: ConcreteContextLoadingResult? -} - sealed class SpringConfiguration(val fullDisplayName: String) { class JavaConfiguration(val classBinaryName: String) : SpringConfiguration(classBinaryName) class XMLConfiguration(val absolutePath: String) : SpringConfiguration(absolutePath) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt index 6e87df4a24..5dc79b10e5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/CodeGenerator.kt @@ -7,7 +7,7 @@ import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.plugin.api.ClassId open class CodeGenerator(params: CodeGeneratorParams): AbstractCodeGenerator(params) { - val classUnderTest: ClassId = params.classUnderTest + protected val classUnderTest: ClassId = params.classUnderTest override fun generate(testSets: List): CodeGeneratorResult { val testClassModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) 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 9f0f4e5f98..937c841a26 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 @@ -10,13 +10,16 @@ import org.utbot.framework.codegen.tree.CgSpringVariableConstructor import org.utbot.framework.codegen.tree.CgVariableConstructor import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.SpringCodeGenerationContext +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult +import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.SpringSettings.AbsentSpringSettings import org.utbot.framework.plugin.api.SpringSettings.PresentSpringSettings import org.utbot.framework.plugin.api.SpringTestType class SpringCodeGenerator( - val springCodeGenerationContext: SpringCodeGenerationContext, + private val springTestType: SpringTestType, + private val springSettings: SpringSettings, + private val concreteContextLoadingResult: ConcreteContextLoadingResult?, params: CodeGeneratorParams ) : AbstractCodeGenerator( params.copy( @@ -27,17 +30,17 @@ class SpringCodeGenerator( } ) ) { - val classUnderTest: ClassId = params.classUnderTest + private val classUnderTest: ClassId = params.classUnderTest override fun generate(testSets: List): CodeGeneratorResult { val testClassModel = SpringTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) logger.info { "Code generation phase started at ${now()}" } - val astConstructor = when (springCodeGenerationContext.springTestType) { + val astConstructor = when (springTestType) { SpringTestType.UNIT_TEST -> CgSpringUnitTestClassConstructor(context) SpringTestType.INTEGRATION_TEST -> - when (val settings = springCodeGenerationContext.springSettings) { - is PresentSpringSettings -> CgSpringIntegrationTestClassConstructor(context, springCodeGenerationContext, settings) + when (val settings = springSettings) { + is PresentSpringSettings -> CgSpringIntegrationTestClassConstructor(context, concreteContextLoadingResult, settings) is AbsentSpringSettings -> error("No Spring settings were provided for Spring integration test generation.") } } 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 45fab74fe4..4935c85ee4 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 @@ -13,13 +13,12 @@ import org.utbot.framework.codegen.domain.models.CgTestMethodType.SUCCESSFUL import org.utbot.framework.codegen.util.escapeControlChars import org.utbot.framework.codegen.util.resolve import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.SpringCodeGenerationContext +import org.utbot.framework.plugin.api.ConcreteContextLoadingResult import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.framework.plugin.api.util.IndentUtil.TAB 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.crudRepositoryClassId @@ -37,7 +36,7 @@ import org.utbot.spring.api.UTSpringContextLoadingException class CgSpringIntegrationTestClassConstructor( context: CgContext, - private val springCodeGenerationContext: SpringCodeGenerationContext, + private val concreteContextLoadingResult: ConcreteContextLoadingResult?, private val springSettings: PresentSpringSettings, ) : CgAbstractSpringTestClassConstructor(context) { @@ -64,21 +63,20 @@ class CgSpringIntegrationTestClassConstructor( ) private fun constructContextLoadsMethod() : CgTestMethod { - val contextLoadingResult = springCodeGenerationContext.concreteContextLoadingResult - if (contextLoadingResult == null) + if (concreteContextLoadingResult == null) logger.error { "Missing contextLoadingResult" } - val exception = contextLoadingResult?.exceptions?.firstOrNull() + val exception = concreteContextLoadingResult?.exceptions?.firstOrNull() return CgTestMethod( name = "contextLoads", statements = listOfNotNull( exception?.let { e -> constructFailedContextLoadingTraceComment(e) }, - if (contextLoadingResult == null) CgSingleLineComment("Error: context loading result from concrete execution is missing") else null + if (concreteContextLoadingResult == null) CgSingleLineComment("Error: context loading result from concrete execution is missing") else null ), annotations = listOf(addAnnotation(context.testFramework.testAnnotationId, Method)), documentation = CgDocumentationComment(listOf( CgDocRegularLineStmt("This sanity check test fails if the application context cannot start.") ) + exception?.let { constructFailedContextLoadingDocComment() }.orEmpty()), - type = if (contextLoadingResult != null && exception == null) SUCCESSFUL else FAILING + type = if (concreteContextLoadingResult != null && exception == null) SUCCESSFUL else FAILING ) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt index 51ce384a20..8a17675ee5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/ApplicationContext.kt @@ -1,8 +1,9 @@ package org.utbot.framework.context -import org.utbot.framework.plugin.api.CodeGenerationContext +import org.utbot.framework.codegen.generator.AbstractCodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams -interface ApplicationContext : CodeGenerationContext { +interface ApplicationContext { val mockerContext: MockerContext val typeReplacer: TypeReplacer val nonNullSpeculator: NonNullSpeculator @@ -11,4 +12,6 @@ interface ApplicationContext : CodeGenerationContext { fullClasspath: String, classpathWithoutDependencies: String ): ConcreteExecutionContext + + fun createCodeGenerator(params: CodeGeneratorParams): AbstractCodeGenerator } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt index 21debdb4b5..e3f18b5cb7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt @@ -1,5 +1,8 @@ package org.utbot.framework.context.simple +import org.utbot.framework.codegen.generator.AbstractCodeGenerator +import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.context.MockerContext @@ -18,4 +21,7 @@ class SimpleApplicationContext( fullClasspath: String, classpathWithoutDependencies: String ): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath) + + override fun createCodeGenerator(params: CodeGeneratorParams): AbstractCodeGenerator = + CodeGenerator(params) } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt index 82b91e6ca7..458c9db3f6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt @@ -3,15 +3,16 @@ package org.utbot.framework.context.spring import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.SpringCodeGenerationContext import org.utbot.framework.plugin.api.ConcreteContextLoadingResult +import org.utbot.framework.plugin.api.SpringSettings /** * Data we get from Spring application context * to manage engine and code generator behaviour. */ -// TODO #2358 -interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationContext { +interface SpringApplicationContext : ApplicationContext { + val springSettings: SpringSettings + /** * Describes bean definitions (bean name, type, some optional additional data) */ @@ -19,6 +20,6 @@ interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationCon val injectedTypes: Set val allInjectedSuperTypes: Set - override var concreteContextLoadingResult: ConcreteContextLoadingResult? + var concreteContextLoadingResult: ConcreteContextLoadingResult? fun getBeansAssignableTo(classId: ClassId): List } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 4b0852ceeb..4e9bf11553 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -3,6 +3,9 @@ package org.utbot.framework.context.spring import mu.KotlinLogging import org.utbot.common.isAbstract import org.utbot.common.isStatic +import org.utbot.framework.codegen.generator.AbstractCodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams +import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.ConcreteExecutionContext import org.utbot.framework.context.NonNullSpeculator @@ -22,7 +25,7 @@ import org.utbot.framework.plugin.api.util.utContext class SpringApplicationContextImpl( private val delegateContext: ApplicationContext, override val beanDefinitions: List = emptyList(), - override val springTestType: SpringTestType, + private val springTestType: SpringTestType, override val springSettings: SpringSettings, ): ApplicationContext by delegateContext, SpringApplicationContext { companion object { @@ -64,6 +67,15 @@ class SpringApplicationContextImpl( } } + override fun createCodeGenerator(params: CodeGeneratorParams): AbstractCodeGenerator = + // TODO decorate original `delegateContext.createCodeGenerator(params)` + SpringCodeGenerator( + springTestType = springTestType, + springSettings = springSettings, + concreteContextLoadingResult = concreteContextLoadingResult, + params = params, + ) + override fun getBeansAssignableTo(classId: ClassId): List = beanDefinitions.filter { beanDef -> // some bean classes may fail to load runCatching { 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 e0bae27c8e..a2d54d6511 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 @@ -14,9 +14,7 @@ import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.testFrameworkByName import org.utbot.framework.codegen.generator.AbstractCodeGenerator -import org.utbot.framework.codegen.generator.CodeGenerator import org.utbot.framework.codegen.generator.CodeGeneratorParams -import org.utbot.framework.codegen.generator.SpringCodeGenerator import org.utbot.framework.codegen.reports.TestsGenerationReport import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.context.ApplicationContext @@ -291,7 +289,7 @@ private fun destinationWarningMessage(testPackageName: String?, classUnderTestPa } } -private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, codeGenerationContext: CodeGenerationContext): AbstractCodeGenerator { +private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, applicationContext: ApplicationContext): AbstractCodeGenerator { with(params) { val classUnderTest: ClassId = kryoHelper.readObject(classUnderTest) val paramNames: MutableMap> = kryoHelper.readObject(paramNames) @@ -300,7 +298,7 @@ private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, co val forceStaticMocking: ForceStaticMocking = kryoHelper.readObject(forceStaticMocking) val projectType = ProjectType.valueOf(projectType) - val codeGeneratorParams = CodeGeneratorParams( + return applicationContext.createCodeGenerator(CodeGeneratorParams( classUnderTest = classUnderTest, projectType = projectType, generateUtilClassFile = generateUtilClassFile, @@ -323,11 +321,6 @@ private fun createCodeGenerator(kryoHelper: KryoHelper, params: RenderParams, co hangingTestsTimeout = HangingTestsTimeout(hangingTestsTimeout), enableTestsTimeout = enableTestsTimeout, testClassPackageName = testClassPackageName, - ) - - return when (codeGenerationContext) { - is SpringCodeGenerationContext -> SpringCodeGenerator(codeGenerationContext, codeGeneratorParams) - else -> CodeGenerator(codeGeneratorParams) - } + )) } } \ No newline at end of file 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 9399ae1279..b58ce9595c 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,7 +71,6 @@ 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 @@ -116,7 +115,6 @@ object CodeGenerationController { fun generateTests( model: GenerateTestsModel, - codeGenerationContext: CodeGenerationContext, classesWithTests: Map, psi2KClass: Map, process: EngineProcess, @@ -163,7 +161,6 @@ object CodeGenerationController { testFilePointer, srcClassPathToSarifReport, model, - codeGenerationContext, latch, utilClassListener, indicator @@ -667,7 +664,6 @@ object CodeGenerationController { filePointer: SmartPsiElementPointer, srcClassPathToSarifReport: MutableMap, model: GenerateTestsModel, - codeGenerationContext: CodeGenerationContext, reportsCountDown: CountDownLatch, utilClassListener: UtilClassListener, indicator: ProgressIndicator 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 16d9874643..87e0da4865 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 @@ -446,7 +446,7 @@ object UtTestsDialogProcessor { // indicator.checkCanceled() invokeLater { - generateTests(model, applicationContext, testSetsByClass, psi2KClass, process, indicator) + generateTests(model, testSetsByClass, psi2KClass, process, indicator) logger.info { "Generation complete" } } } From fb4e31f65263969cb3d82809da8b70268b4bd431 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Wed, 19 Jul 2023 15:35:33 +0300 Subject: [PATCH 17/20] Improve equals overrides for `Instrumentation.Factory` implementations --- .../org/utbot/framework/plugin/api/Api.kt | 18 ++++++++--------- .../framework/coverage/CoverageCalculator.kt | 2 +- .../org/utbot/examples/TestConstructors.kt | 10 +++++----- .../examples/TestCoverageInstrumentation.kt | 16 +++++++-------- .../examples/TestInvokeInstrumentation.kt | 14 ++++++------- .../TestInvokeWithStaticsInstrumentation.kt | 8 ++++---- .../kotlin/org/utbot/examples/TestIsolated.kt | 12 +++++------ .../org/utbot/examples/TestStaticMethods.kt | 6 +++--- .../utbot/examples/TestWithInstrumentation.kt | 6 +++--- .../org/utbot/examples/benchmark/Benchmark.kt | 4 ++-- .../examples/benchmark/BenchmarkFibonacci.kt | 4 ++-- .../benchmark/TestBenchmarkClasses.kt | 4 ++-- .../org/utbot/examples/et/TestMixedExTrace.kt | 2 +- .../utbot/examples/et/TestSimpleExTrace.kt | 12 +++++------ .../org/utbot/examples/et/TestStaticsUsage.kt | 4 ++-- .../utbot/examples/jacoco/TestSameAsJaCoCo.kt | 2 +- .../instrumentation/InvokeInstrumentation.kt | 2 +- .../InvokeWithStaticsInstrumentation.kt | 2 +- .../coverage/CoverageInstrumentation.kt | 2 +- .../et/ExecutionTraceInstrumentation.kt | 2 +- .../execution/UtExecutionInstrumentation.kt | 13 ++++++++++++ .../spring/SpringInstrumentationContext.kt | 2 +- .../SpringUtExecutionInstrumentation.kt | 20 +++++++++++++++++++ .../plugin/ui/GenerateTestsDialogWindow.kt | 4 ++-- .../analyzer/SpringApplicationAnalyzer.kt | 2 +- 25 files changed, 102 insertions(+), 71 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 de2420497a..9ff4eebed3 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 @@ -1325,19 +1325,17 @@ sealed class SpringConfiguration(val fullDisplayName: String) { } 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 + object AbsentSpringSettings : SpringSettings { + // NOTE that overriding equals is required just because without it + // we will lose equality for objects after deserialization + override fun equals(other: Any?): Boolean = other is AbsentSpringSettings + + override fun hashCode(): Int = 0 } - class PresentSpringSettings( + data class PresentSpringSettings( val configuration: SpringConfiguration, - val profiles: Array + val profiles: List ) : SpringSettings } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt index 8c29eadb2f..c662da9b31 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/coverage/CoverageCalculator.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.runBlocking fun methodCoverage(executable: ExecutableId, executions: List>, classpath: String): Coverage { val methodSignature = executable.signature val classId = executable.classId - return ConcreteExecutor(CoverageInstrumentation.Factory(), classpath).let { executor -> + return ConcreteExecutor(CoverageInstrumentation.Factory, classpath).let { executor -> for (execution in executions) { val args = execution.stateBefore.params.map { it.value }.toMutableList() val caller = execution.stateBefore.caller diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt index 7d37d0c569..fea5acdb17 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestConstructors.kt @@ -28,7 +28,7 @@ class TestConstructors { @Test fun testDefaultConstructor() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, CLASSPATH ).use { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -43,7 +43,7 @@ class TestConstructors { @Test fun testIntConstructors() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, CLASSPATH ).use { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -65,7 +65,7 @@ class TestConstructors { @Test fun testStringConstructors() { withInstrumentation( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -86,7 +86,7 @@ class TestConstructors { @Test fun testCoverageConstructor() { withInstrumentation( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors @@ -106,7 +106,7 @@ class TestConstructors { @Test fun testExecutionTraceConstructor() { withInstrumentation( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ) { executor -> val constructors = ClassWithMultipleConstructors::class.constructors diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt index de520914c9..565ca75f12 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestCoverageInstrumentation.kt @@ -24,7 +24,7 @@ class TestCoverageInstrumentation { @Test fun testCatchTargetException() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -41,7 +41,7 @@ class TestCoverageInstrumentation { @Test fun testIfBranches() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -63,7 +63,7 @@ class TestCoverageInstrumentation { @Test fun testWrongArgumentsException() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -86,7 +86,7 @@ class TestCoverageInstrumentation { @Test fun testMultipleRunsInsideCoverage() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -121,7 +121,7 @@ class TestCoverageInstrumentation { @Test fun testSameResult() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -143,7 +143,7 @@ class TestCoverageInstrumentation { @Test fun testResult() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -160,7 +160,7 @@ class TestCoverageInstrumentation { @Test fun testEmptyMethod() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -176,7 +176,7 @@ class TestCoverageInstrumentation { @Test fun testTernaryOperator() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, StaticSubstitutionExamples::class.java.protectionDomain.codeSource.location.path ).use { val testObject = StaticSubstitutionExamples() diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt index 1bb05465e8..a585b2f45f 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeInstrumentation.kt @@ -21,7 +21,7 @@ class TestInvokeInstrumentation { @Test fun testCatchTargetException() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { @@ -36,7 +36,7 @@ class TestInvokeInstrumentation { @Test fun testWrongArgumentsException() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -57,7 +57,7 @@ class TestInvokeInstrumentation { @Test fun testSameResult() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -73,7 +73,7 @@ class TestInvokeInstrumentation { @Test fun testEmptyMethod() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -87,7 +87,7 @@ class TestInvokeInstrumentation { @Test fun testStaticMethodCall() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute(StaticExampleClass::inc, arrayOf()) @@ -105,7 +105,7 @@ class TestInvokeInstrumentation { @Test fun testNullableMethod() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( @@ -136,7 +136,7 @@ class TestInvokeInstrumentation { @Test fun testDifferentSignaturesButSameMethodNames() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ClassWithSameMethodNames::class.java.protectionDomain.codeSource.location.path ).use { val clazz = ClassWithSameMethodNames::class diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt index cda707c17a..c06143e38f 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestInvokeWithStaticsInstrumentation.kt @@ -35,7 +35,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testIfBranches() { ConcreteExecutor( - InvokeWithStaticsInstrumentation.Factory(), + InvokeWithStaticsInstrumentation.Factory, CLASSPATH ).use { val res = it.execute(StaticExampleClass::inc, arrayOf(), null) @@ -52,7 +52,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testHiddenClass1() { ConcreteExecutor( - InvokeWithStaticsInstrumentation.Factory(), + InvokeWithStaticsInstrumentation.Factory, CLASSPATH ).use { val res = it.execute(TestedClass::slomayInts, arrayOf(), null) @@ -71,7 +71,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testHiddenClassRepeatCall() { ConcreteExecutor( - InvokeWithStaticsInstrumentation.Factory(), + InvokeWithStaticsInstrumentation.Factory, CLASSPATH ).use { val se = StaticEnvironment( @@ -89,7 +89,7 @@ class TestInvokeWithStaticsInstrumentation { @Test fun testReferenceEquality() { ConcreteExecutor( - InvokeWithStaticsInstrumentation.Factory(), + InvokeWithStaticsInstrumentation.Factory, CLASSPATH ).use { diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt index 3538e2979b..96b3047f6e 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestIsolated.kt @@ -21,7 +21,7 @@ class TestIsolated { fun testCatchTargetException() { val javaClass = ExampleClass::class.java ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, javaClass.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -37,7 +37,7 @@ class TestIsolated { @Test fun testWrongArgumentsException() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -63,7 +63,7 @@ class TestIsolated { @Test fun testSameResult() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -81,7 +81,7 @@ class TestIsolated { @Test fun testEmptyMethod() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val testObject = ExampleClass() @@ -97,7 +97,7 @@ class TestIsolated { @Test fun testStaticMethodCall() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val isolatedFunctionInc = Isolated(StaticExampleClass::inc, it) @@ -116,7 +116,7 @@ class TestIsolated { @Test fun testNullableMethod() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val isolatedFunction = Isolated(StaticExampleClass::canBeNull, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt index bc33834f80..0a75292636 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestStaticMethods.kt @@ -17,7 +17,7 @@ class TestStaticMethods { @Test fun testStaticMethodCall() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute(StaticExampleClass::inc, arrayOf()) @@ -44,7 +44,7 @@ class TestStaticMethods { @Test fun testNullableMethod() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( @@ -75,7 +75,7 @@ class TestStaticMethods { @Test fun testNullableMethodWithoutAnnotations() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ).use { val res1 = it.execute( diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt index 22e6308c52..ae00e0f7a8 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/TestWithInstrumentation.kt @@ -20,7 +20,7 @@ class TestWithInstrumentation { @Test fun testStaticMethodCall() { withInstrumentation( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, StaticExampleClass::class.java.protectionDomain.codeSource.location.path ) { executor -> val res1 = executor.execute(StaticExampleClass::inc, arrayOf()) @@ -47,7 +47,7 @@ class TestWithInstrumentation { @Test fun testDifferentSignaturesButSameMethodNames() { withInstrumentation( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, ClassWithSameMethodNames::class.java.protectionDomain.codeSource.location.path ) { executor -> val clazz = ClassWithSameMethodNames::class @@ -70,7 +70,7 @@ class TestWithInstrumentation { @Test fun testInnerClasses() { withInstrumentation( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, ClassWithInnerClasses::class.java.protectionDomain.codeSource.location.path ) { executor -> val innerClazz = ClassWithInnerClasses.InnerClass::class.java diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt index 55da2d91df..d4e9ba2028 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/Benchmark.kt @@ -12,7 +12,7 @@ import org.junit.jupiter.api.Assertions.assertEquals fun getBasicCoverageTime(count: Int): Double { var time: Long ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, Repeater::class.java.protectionDomain.codeSource.location.path ).use { executor -> val dc0 = Repeater(", ") @@ -51,7 +51,7 @@ fun getNativeCallTime(count: Int): Double { fun getJustResultTime(count: Int): Double { var time: Long ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, Repeater::class.java.protectionDomain.codeSource.location.path ).use { val dc0 = Repeater(", ") diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt index e65de088a2..07d788e4ce 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/BenchmarkFibonacci.kt @@ -13,7 +13,7 @@ import kotlin.system.measureNanoTime fun getBasicCoverageTime_fib(count: Int): Double { var time: Long ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val fib = Isolated(Fibonacci::calc, it) @@ -47,7 +47,7 @@ fun getNativeCallTime_fib(count: Int): Double { fun getJustResultTime_fib(count: Int): Double { var time: Long ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val fib = Isolated(Fibonacci::calc, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt index c660d9291a..f189907c5d 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/benchmark/TestBenchmarkClasses.kt @@ -18,7 +18,7 @@ class TestBenchmarkClasses { @Disabled("Ask Sergey to check") fun testRepeater() { ConcreteExecutor( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, Repeater::class.java.protectionDomain.codeSource.location.path ).use { val dc0 = Repeater(", ") @@ -36,7 +36,7 @@ class TestBenchmarkClasses { @Test fun testFibonacci() { ConcreteExecutor( - InvokeInstrumentation.Factory(), + InvokeInstrumentation.Factory, Fibonacci::class.java.protectionDomain.codeSource.location.path ).use { val res = diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt index cedaf15539..c5ecefeded 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestMixedExTrace.kt @@ -25,7 +25,7 @@ class TestMixedExTrace { @Test fun testMixedDoesNotThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassMixedWithNotInstrumented_Instr::a, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt index dbb732eb7c..f8b7224de0 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestSimpleExTrace.kt @@ -34,7 +34,7 @@ class TestSimpleExTrace { @Test fun testClassSimple() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val alwaysThrows = Isolated(ClassSimple::alwaysThrows, it) @@ -89,7 +89,7 @@ class TestSimpleExTrace { @Test fun testClasSimpleCatch() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassSimpleCatch::A, it) @@ -159,7 +159,7 @@ class TestSimpleExTrace { @Test fun testClassSimpleRecursive() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassSimpleRecursive::A, it) @@ -228,7 +228,7 @@ class TestSimpleExTrace { @Test fun testClassBinaryRecursionWithTrickyThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassBinaryRecursionWithTrickyThrow::A, it) @@ -347,7 +347,7 @@ class TestSimpleExTrace { @Test fun testClassBinaryRecursionWithThrow() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassBinaryRecursionWithThrow::A, it) @@ -436,7 +436,7 @@ class TestSimpleExTrace { @Test fun testClassSimpleNPE() { ConcreteExecutor( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, CLASSPATH ).use { val A = Isolated(ClassSimpleNPE::A, it) diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt index 1375cc898f..22ade07a8c 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt @@ -31,7 +31,7 @@ class StaticsUsageDetectionTest { @Test fun testStaticsUsageOneUsage() { withInstrumentation( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, ObjectWithStaticFieldsExample::class.java.protectionDomain.codeSource.location.path ) { val instance = ObjectWithStaticFieldsExample() @@ -46,7 +46,7 @@ class StaticsUsageDetectionTest { @Test fun testStaticsUsageZeroUsages() { withInstrumentation( - ExecutionTraceInstrumentation.Factory(), + ExecutionTraceInstrumentation.Factory, ObjectWithStaticFieldsExample::class.java.protectionDomain.codeSource.location.path ) { val instance = ObjectWithStaticFieldsExample() diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt index 88187068d1..a289e1d5fa 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/jacoco/TestSameAsJaCoCo.kt @@ -123,7 +123,7 @@ private fun methodCoverageWithJaCoCo(kClass: KClass<*>, method: KCallable<*>, ex private fun methodCoverage(kClass: KClass<*>, method: KCallable<*>, executions: List): Pair { return withInstrumentation( - CoverageInstrumentation.Factory(), + CoverageInstrumentation.Factory, kClass.java.protectionDomain.codeSource.location.path ) { executor -> for (execution in executions) { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt index 73e11d7114..96a1ef9109 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt @@ -118,7 +118,7 @@ class InvokeInstrumentation : Instrumentation> { classfileBuffer: ByteArray ) = null - class Factory : Instrumentation.Factory, InvokeInstrumentation> { + object Factory : Instrumentation.Factory, InvokeInstrumentation> { override fun create(): InvokeInstrumentation = InvokeInstrumentation() } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt index 5bd1253128..9572944aeb 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt @@ -90,7 +90,7 @@ class InvokeWithStaticsInstrumentation : Instrumentation> { } } - class Factory : Instrumentation.Factory, InvokeWithStaticsInstrumentation> { + object Factory : Instrumentation.Factory, InvokeWithStaticsInstrumentation> { override fun create(): InvokeWithStaticsInstrumentation = InvokeWithStaticsInstrumentation() } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt index 98fbcb0e37..ab3238a97b 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt @@ -95,7 +95,7 @@ class CoverageInstrumentation : Instrumentation> { return instrumenter.classByteCode } - class Factory : Instrumentation.Factory, CoverageInstrumentation> { + object Factory : Instrumentation.Factory, CoverageInstrumentation> { override fun create(): CoverageInstrumentation = CoverageInstrumentation() } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt index 9424d9f8d9..f62eff9b47 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt @@ -58,7 +58,7 @@ class ExecutionTraceInstrumentation : Instrumentation { } } - class Factory : Instrumentation.Factory { + object Factory : Instrumentation.Factory { override fun create(): ExecutionTraceInstrumentation = ExecutionTraceInstrumentation() } } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt index c7a7185f9c..8485e9055a 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt @@ -210,5 +210,18 @@ class SimpleUtExecutionInstrumentation( override fun create(instrumentationContext: InstrumentationContext): UtExecutionInstrumentation = SimpleUtExecutionInstrumentation(pathsToUserClasses, instrumentationContext) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Factory + + return pathsToUserClasses == other.pathsToUserClasses + } + + override fun hashCode(): Int { + return pathsToUserClasses.hashCode() + } } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt index 9a43204246..eaf119b571 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt @@ -30,7 +30,7 @@ class SpringInstrumentationContext( ?: error("JavaConfiguration was expected, but ${springSettings.configuration.javaClass.name} was provided.") ) ), - profiles = springSettings.profiles, + profiles = springSettings.profiles.toTypedArray(), ) SpringApiProviderFacade diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt index 05e278dabc..b30c60d931 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt @@ -148,5 +148,25 @@ class SpringUtExecutionInstrumentation( beanDefinitions, buildDirs ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Factory + + if (delegateInstrumentationFactory != other.delegateInstrumentationFactory) return false + if (springSettings != other.springSettings) return false + if (beanDefinitions != other.beanDefinitions) return false + return buildDirs.contentEquals(other.buildDirs) + } + + override fun hashCode(): Int { + var result = delegateInstrumentationFactory.hashCode() + result = 31 * result + springSettings.hashCode() + result = 31 * result + beanDefinitions.hashCode() + result = 31 * result + buildDirs.contentHashCode() + return result + } } } \ No newline at end of file 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 9e621d1fad..547ab7090b 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 @@ -694,7 +694,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m model.springSettings = when (springConfig.item) { - NO_SPRING_CONFIGURATION_OPTION -> AbsentSpringSettings() + NO_SPRING_CONFIGURATION_OPTION -> AbsentSpringSettings else -> { val shortConfigName = springConfig.item.toString() val config = @@ -708,7 +708,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m PresentSpringSettings( configuration = config, - profiles = parseProfileExpression(profileNames.text, DEFAULT_SPRING_PROFILE_NAME) + profiles = parseProfileExpression(profileNames.text, DEFAULT_SPRING_PROFILE_NAME).toList() ) } } 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 706ad79efd..ba81bff3c1 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 @@ -14,7 +14,7 @@ class SpringApplicationAnalyzer { val configurationClasses = SourceFinder(applicationData).findSources() val instantiationSettings = InstantiationSettings( configurationClasses, - applicationData.springSettings.profiles, + applicationData.springSettings.profiles.toTypedArray(), ) return SpringApiProviderFacade.getInstance(this::class.java.classLoader) From c8dffffdc49eeeb25c575411bfc559869bd2ab22 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Wed, 19 Jul 2023 15:37:04 +0300 Subject: [PATCH 18/20] Move `SimpleUtExecutionInstrumentation` to a separate file --- .../SimpleUtExecutionInstrumentation.kt | 174 ++++++++++++++++++ .../execution/UtExecutionInstrumentation.kt | 165 ----------------- 2 files changed, 174 insertions(+), 165 deletions(-) create mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt new file mode 100644 index 0000000000..7c21311731 --- /dev/null +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt @@ -0,0 +1,174 @@ +package org.utbot.instrumentation.instrumentation.execution + +import org.utbot.framework.plugin.api.EnvironmentModels +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.util.singleExecutableId +import org.utbot.instrumentation.instrumentation.ArgumentList +import org.utbot.instrumentation.instrumentation.InvokeInstrumentation +import org.utbot.instrumentation.instrumentation.et.TraceHandler +import org.utbot.instrumentation.instrumentation.execution.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor +import org.utbot.instrumentation.instrumentation.execution.context.InstrumentationContext +import org.utbot.instrumentation.instrumentation.execution.context.SimpleInstrumentationContext +import org.utbot.instrumentation.instrumentation.execution.ndd.NonDeterministicClassVisitor +import org.utbot.instrumentation.instrumentation.execution.ndd.NonDeterministicDetector +import org.utbot.instrumentation.instrumentation.execution.phases.PhasesController +import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter +import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor +import java.security.ProtectionDomain +import kotlin.reflect.jvm.javaMethod + +class SimpleUtExecutionInstrumentation( + private val pathsToUserClasses: Set, + private val instrumentationContext: InstrumentationContext = SimpleInstrumentationContext() +) : UtExecutionInstrumentation { + private val delegateInstrumentation = InvokeInstrumentation() + + private val traceHandler = TraceHandler() + private val ndDetector = NonDeterministicDetector() + + /** + * Ignores [arguments], because concrete arguments will be constructed + * from models passed via [parameters]. + * + * Argument [parameters] must be of type [UtConcreteExecutionData]. + */ + override fun invoke( + clazz: Class<*>, + methodSignature: String, + arguments: ArgumentList, + parameters: Any?, + phasesWrapper: PhasesController.(invokeBasePhases: () -> UtConcreteExecutionResult) -> UtConcreteExecutionResult + ): UtConcreteExecutionResult { + if (parameters !is UtConcreteExecutionData) { + throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}") + } + val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData + + return PhasesController( + instrumentationContext, + traceHandler, + delegateInstrumentation, + timeout + ).computeConcreteExecutionResult { + phasesWrapper { + try { + // some preparation actions for concrete execution + val constructedData = applyPreprocessing(parameters) + + val (params, statics, cache) = constructedData + + // invocation + val concreteResult = executePhaseInTimeout(invocationPhase) { + invoke(clazz, methodSignature, params.map { it.value }) + } + + // statistics collection + val (coverage, ndResults) = executePhaseInTimeout(statisticsCollectionPhase) { + getCoverage(clazz) to getNonDeterministicResults() + } + + // model construction + val (executionResult, stateAfter, newInstrumentation) = executePhaseInTimeout(modelConstructionPhase) { + configureConstructor { + this.cache = cache + strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy( + pathsToUserClasses, + cache + ) + } + + val ndStatics = constructStaticInstrumentation(ndResults.statics) + val ndNews = constructNewInstrumentation(ndResults.news, ndResults.calls) + val newInstrumentation = mergeInstrumentations(instrumentations, ndStatics, ndNews) + + val returnType = clazz.singleExecutableId(methodSignature).returnType + val executionResult = convertToExecutionResult(concreteResult, returnType) + + val stateAfterParametersWithThis = constructParameters(params) + val stateAfterStatics = constructStatics(stateBefore, statics) + val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) { + null to stateAfterParametersWithThis + } else { + stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1) + } + val stateAfter = EnvironmentModels(stateAfterThis, stateAfterParameters, stateAfterStatics) + + Triple(executionResult, stateAfter, newInstrumentation) + } + + UtConcreteExecutionResult( + stateAfter, + executionResult, + coverage, + newInstrumentation + ) + } finally { + // restoring data after concrete execution + applyPostprocessing() + } + } + } + } + + override fun getStaticField(fieldId: FieldId): Result = + delegateInstrumentation.getStaticField(fieldId).map { value -> + UtModelConstructor.createOnlyUserClassesConstructor(pathsToUserClasses) + .construct(value, fieldId.type) + } + + override fun transform( + loader: ClassLoader?, + className: String, + classBeingRedefined: Class<*>?, + protectionDomain: ProtectionDomain, + classfileBuffer: ByteArray + ): ByteArray { + val instrumenter = Instrumenter(classfileBuffer, loader) + + traceHandler.registerClass(className) + instrumenter.visitInstructions(traceHandler.computeInstructionVisitor(className)) + + instrumenter.visitClass { writer -> + NonDeterministicClassVisitor(writer, ndDetector) + } + + val mockClassVisitor = instrumenter.visitClass { writer -> + MockClassVisitor( + writer, + InstrumentationContext.MockGetter::getMock.javaMethod!!, + InstrumentationContext.MockGetter::checkCallSite.javaMethod!!, + InstrumentationContext.MockGetter::hasMock.javaMethod!! + ) + } + + mockClassVisitor.signatureToId.forEach { (method, id) -> + instrumentationContext.methodSignatureToId += method to id + } + + return instrumenter.classByteCode + } + + class Factory( + private val pathsToUserClasses: Set + ) : UtExecutionInstrumentation.Factory { + override fun create(): UtExecutionInstrumentation = SimpleUtExecutionInstrumentation(pathsToUserClasses) + + override fun create(instrumentationContext: InstrumentationContext): UtExecutionInstrumentation = + SimpleUtExecutionInstrumentation(pathsToUserClasses, instrumentationContext) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Factory + + return pathsToUserClasses == other.pathsToUserClasses + } + + override fun hashCode(): Int { + return pathsToUserClasses.hashCode() + } + } +} diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt index 8485e9055a..adc9c180f9 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt @@ -2,22 +2,11 @@ package org.utbot.instrumentation.instrumentation.execution import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.* -import org.utbot.framework.plugin.api.util.singleExecutableId import org.utbot.instrumentation.instrumentation.ArgumentList import org.utbot.instrumentation.instrumentation.Instrumentation -import org.utbot.instrumentation.instrumentation.InvokeInstrumentation -import org.utbot.instrumentation.instrumentation.et.TraceHandler -import org.utbot.instrumentation.instrumentation.execution.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy -import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor import org.utbot.instrumentation.instrumentation.execution.context.InstrumentationContext import org.utbot.instrumentation.instrumentation.execution.context.SimpleInstrumentationContext -import org.utbot.instrumentation.instrumentation.execution.ndd.NonDeterministicClassVisitor -import org.utbot.instrumentation.instrumentation.execution.ndd.NonDeterministicDetector import org.utbot.instrumentation.instrumentation.execution.phases.PhasesController -import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter -import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor -import java.security.ProtectionDomain -import kotlin.reflect.jvm.javaMethod /** * Consists of the data needed to execute the method concretely. Also includes method arguments stored in models. @@ -71,157 +60,3 @@ interface UtExecutionInstrumentation : Instrumentation, - private val instrumentationContext: InstrumentationContext = SimpleInstrumentationContext() -) : UtExecutionInstrumentation { - private val delegateInstrumentation = InvokeInstrumentation() - - private val traceHandler = TraceHandler() - private val ndDetector = NonDeterministicDetector() - - /** - * Ignores [arguments], because concrete arguments will be constructed - * from models passed via [parameters]. - * - * Argument [parameters] must be of type [UtConcreteExecutionData]. - */ - override fun invoke( - clazz: Class<*>, - methodSignature: String, - arguments: ArgumentList, - parameters: Any?, - phasesWrapper: PhasesController.(invokeBasePhases: () -> UtConcreteExecutionResult) -> UtConcreteExecutionResult - ): UtConcreteExecutionResult { - if (parameters !is UtConcreteExecutionData) { - throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}") - } - val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData - - return PhasesController( - instrumentationContext, - traceHandler, - delegateInstrumentation, - timeout - ).computeConcreteExecutionResult { - phasesWrapper { - try { - // some preparation actions for concrete execution - val constructedData = applyPreprocessing(parameters) - - val (params, statics, cache) = constructedData - - // invocation - val concreteResult = executePhaseInTimeout(invocationPhase) { - invoke(clazz, methodSignature, params.map { it.value }) - } - - // statistics collection - val (coverage, ndResults) = executePhaseInTimeout(statisticsCollectionPhase) { - getCoverage(clazz) to getNonDeterministicResults() - } - - // model construction - val (executionResult, stateAfter, newInstrumentation) = executePhaseInTimeout(modelConstructionPhase) { - configureConstructor { - this.cache = cache - strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy( - pathsToUserClasses, - cache - ) - } - - val ndStatics = constructStaticInstrumentation(ndResults.statics) - val ndNews = constructNewInstrumentation(ndResults.news, ndResults.calls) - val newInstrumentation = mergeInstrumentations(instrumentations, ndStatics, ndNews) - - val returnType = clazz.singleExecutableId(methodSignature).returnType - val executionResult = convertToExecutionResult(concreteResult, returnType) - - val stateAfterParametersWithThis = constructParameters(params) - val stateAfterStatics = constructStatics(stateBefore, statics) - val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) { - null to stateAfterParametersWithThis - } else { - stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1) - } - val stateAfter = EnvironmentModels(stateAfterThis, stateAfterParameters, stateAfterStatics) - - Triple(executionResult, stateAfter, newInstrumentation) - } - - UtConcreteExecutionResult( - stateAfter, - executionResult, - coverage, - newInstrumentation - ) - } finally { - // restoring data after concrete execution - applyPostprocessing() - } - } - } - } - - override fun getStaticField(fieldId: FieldId): Result = - delegateInstrumentation.getStaticField(fieldId).map { value -> - UtModelConstructor.createOnlyUserClassesConstructor(pathsToUserClasses) - .construct(value, fieldId.type) - } - - override fun transform( - loader: ClassLoader?, - className: String, - classBeingRedefined: Class<*>?, - protectionDomain: ProtectionDomain, - classfileBuffer: ByteArray - ): ByteArray { - val instrumenter = Instrumenter(classfileBuffer, loader) - - traceHandler.registerClass(className) - instrumenter.visitInstructions(traceHandler.computeInstructionVisitor(className)) - - instrumenter.visitClass { writer -> - NonDeterministicClassVisitor(writer, ndDetector) - } - - val mockClassVisitor = instrumenter.visitClass { writer -> - MockClassVisitor( - writer, - InstrumentationContext.MockGetter::getMock.javaMethod!!, - InstrumentationContext.MockGetter::checkCallSite.javaMethod!!, - InstrumentationContext.MockGetter::hasMock.javaMethod!! - ) - } - - mockClassVisitor.signatureToId.forEach { (method, id) -> - instrumentationContext.methodSignatureToId += method to id - } - - return instrumenter.classByteCode - } - - class Factory( - private val pathsToUserClasses: Set - ) : UtExecutionInstrumentation.Factory { - override fun create(): UtExecutionInstrumentation = SimpleUtExecutionInstrumentation(pathsToUserClasses) - - override fun create(instrumentationContext: InstrumentationContext): UtExecutionInstrumentation = - SimpleUtExecutionInstrumentation(pathsToUserClasses, instrumentationContext) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Factory - - return pathsToUserClasses == other.pathsToUserClasses - } - - override fun hashCode(): Int { - return pathsToUserClasses.hashCode() - } - } -} From 6b705146e2671f94453179dd8defcf5b3cdfc304 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Wed, 19 Jul 2023 17:53:46 +0300 Subject: [PATCH 19/20] Fix compilation after rebase and decouple Spring tests --- ...iceWithInjectedAndNonInjectedFieldTests.kt | 7 +-- .../ServiceWithInjectedFieldTests.kt | 5 +- .../SpringNoConfigUtValueTestCaseChecker.kt | 14 +++++ .../utils/SpringTestingConfiguration.kt | 3 -- .../testing/CodeGenerationIntegrationTest.kt | 4 +- .../org/utbot/testing/Configurations.kt | 52 +++++++++++++------ .../testing/TestCodeGeneratorPipeline.kt | 40 ++++---------- .../testing/TestSpecificTestCaseGenerator.kt | 5 +- .../utbot/testing/UtValueTestCaseChecker.kt | 14 ++--- 9 files changed, 73 insertions(+), 71 deletions(-) create mode 100644 utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/SpringNoConfigUtValueTestCaseChecker.kt diff --git a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedAndNonInjectedFieldTests.kt b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedAndNonInjectedFieldTests.kt index 266c999150..ad94545d4b 100644 --- a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedAndNonInjectedFieldTests.kt +++ b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedAndNonInjectedFieldTests.kt @@ -4,19 +4,14 @@ import org.junit.jupiter.api.Test import org.utbot.examples.spring.utils.findAllRepositoryCall import org.utbot.examples.spring.utils.springAdditionalDependencies import org.utbot.examples.spring.utils.springMockStrategy -import org.utbot.examples.spring.utils.standardSpringTestingConfigurations -import org.utbot.framework.plugin.api.MockStrategyApi -import org.utbot.testcheckers.eq import org.utbot.testing.DoNotCalculate -import org.utbot.testing.UtValueTestCaseChecker import org.utbot.testing.ignoreExecutionsNumber import org.utbot.testing.isException import org.utbot.testing.singleMock import org.utbot.testing.value -internal class ServiceWithInjectedAndNonInjectedFieldTests: UtValueTestCaseChecker( +internal class ServiceWithInjectedAndNonInjectedFieldTests : SpringNoConfigUtValueTestCaseChecker( testClass = ServiceWithInjectedAndNonInjectedField::class, - configurations = standardSpringTestingConfigurations ) { @Test fun testGetOrdersSize() { diff --git a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedFieldTests.kt b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedFieldTests.kt index 20c59bb9e8..b051d491f6 100644 --- a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedFieldTests.kt +++ b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/ServiceWithInjectedFieldTests.kt @@ -5,14 +5,11 @@ import org.utbot.examples.spring.utils.findAllRepositoryCall import org.utbot.examples.spring.utils.saveRepositoryCall import org.utbot.examples.spring.utils.springAdditionalDependencies import org.utbot.examples.spring.utils.springMockStrategy -import org.utbot.examples.spring.utils.standardSpringTestingConfigurations -import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.testcheckers.eq import org.utbot.testing.* -internal class ServiceWithInjectedFieldTests : UtValueTestCaseChecker( +internal class ServiceWithInjectedFieldTests : SpringNoConfigUtValueTestCaseChecker( testClass = ServiceWithInjectedField::class, - configurations = standardSpringTestingConfigurations ) { @Test fun testGetOrders() { diff --git a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/SpringNoConfigUtValueTestCaseChecker.kt b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/SpringNoConfigUtValueTestCaseChecker.kt new file mode 100644 index 0000000000..3e0e66241b --- /dev/null +++ b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/autowiring/oneBeanForOneType/SpringNoConfigUtValueTestCaseChecker.kt @@ -0,0 +1,14 @@ +package org.utbot.examples.spring.autowiring.oneBeanForOneType + +import org.utbot.examples.spring.utils.standardSpringTestingConfigurations +import org.utbot.testing.UtValueTestCaseChecker +import org.utbot.testing.springNoConfigApplicationContext +import kotlin.reflect.KClass + +abstract class SpringNoConfigUtValueTestCaseChecker( + testClass: KClass<*> +) : UtValueTestCaseChecker( + testClass, + configurations = standardSpringTestingConfigurations, + applicationContext = springNoConfigApplicationContext +) \ No newline at end of file diff --git a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/utils/SpringTestingConfiguration.kt b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/utils/SpringTestingConfiguration.kt index d311a46dde..3a967775a1 100644 --- a/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/utils/SpringTestingConfiguration.kt +++ b/utbot-spring-test/src/test/kotlin/org/utbot/examples/spring/utils/SpringTestingConfiguration.kt @@ -5,9 +5,6 @@ import org.springframework.data.repository.PagingAndSortingRepository import org.utbot.framework.codegen.domain.ParametrizedTestSource import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.MockStrategyApi -import org.utbot.framework.plugin.api.SpringApplicationContext -import org.utbot.framework.plugin.api.SpringSettings -import org.utbot.framework.plugin.api.SpringTestType import org.utbot.testing.SpringConfiguration import org.utbot.testing.TestExecution diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/CodeGenerationIntegrationTest.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/CodeGenerationIntegrationTest.kt index 3fabd147ff..021a5d6417 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/CodeGenerationIntegrationTest.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/CodeGenerationIntegrationTest.kt @@ -22,6 +22,7 @@ import org.junit.jupiter.api.fail import org.junit.jupiter.engine.descriptor.ClassTestDescriptor import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor import org.utbot.framework.codegen.domain.ParametrizedTestSource +import org.utbot.framework.context.ApplicationContext import java.nio.file.Path @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -31,6 +32,7 @@ abstract class CodeGenerationIntegrationTest( private val testClass: KClass<*>, private var testCodeGeneration: Boolean = true, private val configurationsToTest: List, + private val applicationContext: ApplicationContext = defaultApplicationContext, ) { private val testSets: MutableList = arrayListOf() @@ -102,7 +104,7 @@ abstract class CodeGenerationIntegrationTest( ) val pipelineConfig = TestCodeGeneratorPipeline.configurePipeline(configuration) - TestCodeGeneratorPipeline(pipelineConfig).runClassesCodeGenerationTests(classStages) + TestCodeGeneratorPipeline(pipelineConfig, applicationContext).runClassesCodeGenerationTests(classStages) } catch (e: RuntimeException) { logger.warn(e) { "error in test pipeline" } pipelineErrors.add(e.message) diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/Configurations.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/Configurations.kt index 8fe673c418..d468673abd 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/Configurations.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/Configurations.kt @@ -2,34 +2,56 @@ package org.utbot.testing import org.utbot.framework.codegen.domain.ParametrizedTestSource import org.utbot.framework.codegen.domain.ProjectType +import org.utbot.framework.context.simple.SimpleApplicationContext +import org.utbot.framework.context.simple.SimpleMockerContext +import org.utbot.framework.context.spring.SpringApplicationContextImpl import org.utbot.framework.plugin.api.CodegenLanguage -import org.utbot.framework.plugin.api.SpringApplicationContext +import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.framework.plugin.api.SpringSettings import org.utbot.framework.plugin.api.SpringTestType -abstract class AbstractConfiguration( - val projectType: ProjectType, - open val language: CodegenLanguage, - open val parametrizedTestSource: ParametrizedTestSource, - open val lastStage: Stage, -) +interface AbstractConfiguration { + val projectType: ProjectType + val mockStrategy: MockStrategyApi + val language: CodegenLanguage + val parametrizedTestSource: ParametrizedTestSource + val lastStage: Stage +} data class Configuration( override val language: CodegenLanguage, override val parametrizedTestSource: ParametrizedTestSource, override val lastStage: Stage, -): AbstractConfiguration(ProjectType.PureJvm, language, parametrizedTestSource, lastStage) +): AbstractConfiguration { + override val projectType: ProjectType + get() = ProjectType.PureJvm + + override val mockStrategy: MockStrategyApi + get() = MockStrategyApi.defaultItem +} data class SpringConfiguration( override val language: CodegenLanguage, override val parametrizedTestSource: ParametrizedTestSource, override val lastStage: Stage, -): AbstractConfiguration(ProjectType.Spring, language, parametrizedTestSource, lastStage) +): AbstractConfiguration { + override val projectType: ProjectType + get() = ProjectType.Spring + + override val mockStrategy: MockStrategyApi + get() = MockStrategyApi.springDefaultItem +} -val defaultSpringApplicationContext = SpringApplicationContext( - mockInstalled = true, - staticsMockingIsConfigured = true, - shouldUseImplementors = false, +val defaultApplicationContext = SimpleApplicationContext( + SimpleMockerContext( + mockFrameworkInstalled = true, + staticsMockingIsConfigured = true, + ) +) + +val springNoConfigApplicationContext = SpringApplicationContextImpl( + delegateContext = defaultApplicationContext, springTestType = SpringTestType.UNIT_TEST, - springSettings = SpringSettings.AbsentSpringSettings(), -) \ No newline at end of file + springSettings = SpringSettings.AbsentSpringSettings, + beanDefinitions = emptyList() +) diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt index 9f51ad1582..4e1d16a386 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/TestCodeGeneratorPipeline.kt @@ -8,14 +8,13 @@ import org.utbot.common.info import org.utbot.framework.codegen.generator.CodeGeneratorResult import org.utbot.framework.codegen.domain.ForceStaticMocking import org.utbot.framework.codegen.domain.ParametrizedTestSource -import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework -import org.utbot.framework.codegen.generator.CodeGenerator -import org.utbot.framework.codegen.generator.SpringCodeGenerator +import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant 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.context.ApplicationContext import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.description @@ -27,7 +26,10 @@ import kotlin.reflect.KClass internal val logger = KotlinLogging.logger {} -class TestCodeGeneratorPipeline(private val testInfrastructureConfiguration: TestInfrastructureConfiguration) { +class TestCodeGeneratorPipeline( + private val testInfrastructureConfiguration: TestInfrastructureConfiguration, + private val applicationContext: ApplicationContext +) { fun runClassesCodeGenerationTests(classesStages: ClassStages) { val pipeline = with(classesStages) { @@ -252,10 +254,10 @@ class TestCodeGeneratorPipeline(private val testInfrastructureConfiguration: Tes withUtContext(UtContext(classUnderTest.java.classLoader)) { val codeGenerator = with(testInfrastructureConfiguration) { - when (projectType) { - ProjectType.Spring -> SpringCodeGenerator( + applicationContext.createCodeGenerator( + CodeGeneratorParams( classUnderTest.id, - projectType = ProjectType.Spring, + projectType = projectType, generateUtilClassFile = generateUtilClassFile, paramNames = params, testFramework = testFramework, @@ -267,25 +269,8 @@ class TestCodeGeneratorPipeline(private val testInfrastructureConfiguration: Tes parameterizedTestSource = parametrizedTestSource, runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, enableTestsTimeout = enableTestsTimeout, - springCodeGenerationContext = defaultSpringApplicationContext, ) - ProjectType.PureJvm -> CodeGenerator( - classUnderTest.id, - projectType = ProjectType.PureJvm, - generateUtilClassFile = generateUtilClassFile, - paramNames = params, - testFramework = testFramework, - staticsMocking = staticsMocking, - forceStaticMocking = forceStaticMocking, - generateWarningsForStaticMocking = false, - codegenLanguage = codegenLanguage, - cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage), - parameterizedTestSource = parametrizedTestSource, - runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour, - enableTestsTimeout = enableTestsTimeout - ) - else -> error("Unsupported project type $projectType in code generator instantiation") - } + ) } val testClassCustomName = "${classUnderTest.java.simpleName}GeneratedTest" @@ -331,10 +316,7 @@ class TestCodeGeneratorPipeline(private val testInfrastructureConfiguration: Tes testFramework = TestFramework.defaultItem, codegenLanguage = configuration.language, mockFramework = MockFramework.defaultItem, - mockStrategy = when (configuration.projectType) { - ProjectType.Spring -> MockStrategyApi.springDefaultItem - else -> MockStrategyApi.defaultItem - }, + mockStrategy = configuration.mockStrategy, staticsMocking = StaticsMocking.defaultItem, parametrizedTestSource = configuration.parametrizedTestSource, forceStaticMocking = ForceStaticMocking.defaultItem, diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/TestSpecificTestCaseGenerator.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/TestSpecificTestCaseGenerator.kt index 1cadbad0b1..4f2af2dccd 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/TestSpecificTestCaseGenerator.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/TestSpecificTestCaseGenerator.kt @@ -9,11 +9,10 @@ import org.utbot.engine.UtBotSymbolicEngine import org.utbot.engine.util.mockListeners.ForceMockListener import org.utbot.engine.util.mockListeners.ForceStaticMockListener import org.utbot.framework.UtSettings -import org.utbot.framework.plugin.api.ApplicationContext +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.MockStrategyApi -import org.utbot.framework.plugin.api.SpringApplicationContext import org.utbot.framework.plugin.api.TestCaseGenerator import org.utbot.framework.plugin.api.UtError import org.utbot.framework.plugin.api.UtExecution @@ -37,7 +36,7 @@ class TestSpecificTestCaseGenerator( engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(), isCanceled: () -> Boolean = { false }, private val taintConfigurationProvider: TaintConfigurationProvider? = null, - applicationContext: ApplicationContext = ApplicationContext(), + applicationContext: ApplicationContext = defaultApplicationContext, ): TestCaseGenerator( listOf(buildDir), classpath, diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt index 8a25900d8c..bc77d9de81 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt @@ -11,11 +11,11 @@ import org.utbot.engine.prettify import org.utbot.framework.SummariesGenerationType import org.utbot.framework.UtSettings import org.utbot.framework.UtSettings.daysLimitForTempFiles +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.coverage.Coverage import org.utbot.framework.coverage.counters import org.utbot.framework.coverage.methodCoverage import org.utbot.framework.coverage.toAtLeast -import org.utbot.framework.plugin.api.ApplicationContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.FieldId @@ -26,9 +26,6 @@ import org.utbot.framework.plugin.api.MockStrategyApi import org.utbot.framework.plugin.api.MockStrategyApi.NO_MOCKS import org.utbot.framework.plugin.api.ObjectMockTarget import org.utbot.framework.plugin.api.ParameterMockTarget -import org.utbot.framework.plugin.api.SpringApplicationContext -import org.utbot.framework.plugin.api.SpringSettings -import org.utbot.framework.plugin.api.SpringTestType import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtInstrumentation @@ -66,6 +63,7 @@ abstract class UtValueTestCaseChecker( testClass: KClass<*>, testCodeGeneration: Boolean = true, val configurations: List = standardTestingConfigurations, + val applicationContext: ApplicationContext = defaultApplicationContext, ) : CodeGenerationIntegrationTest(testClass, testCodeGeneration, configurations) { // contains already analyzed by the engine methods private val analyzedMethods: MutableMap = mutableMapOf() @@ -2018,7 +2016,7 @@ abstract class UtValueTestCaseChecker( ) val classStages = ClassStages(classUnderTest, stageStatusCheck, listOf(testSet)) - TestCodeGeneratorPipeline(testInfrastructureConfiguration).runClassesCodeGenerationTests(classStages) + TestCodeGeneratorPipeline(testInfrastructureConfiguration, applicationContext).runClassesCodeGenerationTests(classStages) } } } @@ -2163,11 +2161,7 @@ abstract class UtValueTestCaseChecker( buildInfo.buildDir, buildInfo.dependencyPath, System.getProperty("java.class.path"), - applicationContext = if (configurations.any { it is SpringConfiguration }) { - defaultSpringApplicationContext - } else { - ApplicationContext() - } + applicationContext = applicationContext ) } From dbf4da72b0ca4e89a86ceb8a5e17a01c3b4663e4 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Wed, 19 Jul 2023 19:23:04 +0300 Subject: [PATCH 20/20] Remove unused and outdated imports left after rebase --- utbot-testing/src/main/kotlin/org/utbot/testing/Utils.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/utbot-testing/src/main/kotlin/org/utbot/testing/Utils.kt b/utbot-testing/src/main/kotlin/org/utbot/testing/Utils.kt index a912eb9791..60ced254e9 100644 --- a/utbot-testing/src/main/kotlin/org/utbot/testing/Utils.kt +++ b/utbot-testing/src/main/kotlin/org/utbot/testing/Utils.kt @@ -1,8 +1,5 @@ package org.utbot.testing -import org.utbot.framework.plugin.api.SpringApplicationContext -import org.utbot.framework.plugin.api.SpringSettings -import org.utbot.framework.plugin.api.SpringTestType import org.utbot.framework.plugin.api.UtExecutionFailure import org.utbot.framework.plugin.api.UtExecutionResult import org.utbot.framework.plugin.api.UtExecutionSuccess