From a88dc9135502835035f647f8a099c61937d78790 Mon Sep 17 00:00:00 2001 From: Andrey Tarbeev <54685068+sofurihafe@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:28:31 +0300 Subject: [PATCH 1/6] Add support for class fields rendering with annotations --- .../main/kotlin/org/utbot/engine/Traverser.kt | 14 ++-- .../utbot/framework/codegen/CodeGenerator.kt | 4 +- .../utbot/framework/codegen/domain/Domain.kt | 17 +++++ .../codegen/domain/builtin/MockitoBuiltins.kt | 10 +++ .../codegen/domain/context/CgContext.kt | 30 +++++++- .../codegen/domain/models/CgElement.kt | 27 ++++++- .../codegen/domain/models/TestClassModel.kt | 7 +- .../builders/SimpleTestClassModelBuilder.kt | 8 +- .../builders/SpringTestClassModelBuilder.kt | 73 +++++++++++-------- .../codegen/renderer/CgAbstractRenderer.kt | 12 ++- .../codegen/renderer/CgJavaRenderer.kt | 38 ++++++---- .../codegen/renderer/CgKotlinRenderer.kt | 20 +++-- .../framework/codegen/renderer/CgVisitor.kt | 4 + .../framework/MockFrameworkManager.kt | 14 +++- .../services/language/CgLanguageAssistant.kt | 9 ++- .../utbot/framework/codegen/tree/Builders.kt | 7 +- .../tree/CgSpringTestClassConstructor.kt | 46 ++++++++++-- .../tree/CgSpringVariableConstructor.kt | 52 +++++++++++++ .../codegen/tree/CgVariableConstructor.kt | 19 +++-- .../codegen/tree/DeclarationUtils.kt | 11 +++ .../tree/JsCgVariableConstructor.kt | 8 +- .../model/constructor/visitor/CgJsRenderer.kt | 4 +- .../constructor/visitor/CgPythonRenderer.kt | 3 +- 23 files changed, 340 insertions(+), 97 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.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 a82de5812f..20d31a2012 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -1503,7 +1503,7 @@ class Traverser( return createMockedObject(addr, type, mockInfoGenerator, nullEqualityConstraint) } - val concreteImplementation = when (applicationContext.typeReplacementMode) { + val concreteImplementation: Concrete? = when (applicationContext.typeReplacementMode) { AnyImplementor -> findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint) // If our type is not abstract, both in `KnownImplementors` and `NoImplementors` mode, @@ -1521,14 +1521,14 @@ class Traverser( NoImplementors -> { if (!type.isAbstractType) { findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint) - } + } else { + mockInfoGenerator?.let { + return createMockedObject(addr, type, it, nullEqualityConstraint) + } - mockInfoGenerator?.let { - return createMockedObject(addr, type, it, nullEqualityConstraint) + queuedSymbolicStateUpdates += mkFalse().asHardConstraint() + null } - - queuedSymbolicStateUpdates += mkFalse().asHardConstraint() - null } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/CodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/CodeGenerator.kt index ec5b7c16e3..e0769f6cc8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/CodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/CodeGenerator.kt @@ -90,7 +90,7 @@ open class CodeGenerator( private fun generateForSimpleClass(testSets: List): CodeGeneratorResult { val astConstructor = CgSimpleTestClassConstructor(context) - val testClassModel = SimpleTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) + val testClassModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) logger.info { "Code generation phase started at ${now()}" } val testClassFile = astConstructor.construct(testClassModel) @@ -107,7 +107,7 @@ open class CodeGenerator( private fun generateForSpringClass(testSets: List): CodeGeneratorResult { val astConstructor = CgSpringTestClassConstructor(context) - val testClassModel = SpringTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) + val testClassModel = SpringTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) logger.info { "Code generation phase started at ${now()}" } val testClassFile = astConstructor.construct(testClassModel) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt index 79403dbdda..a9299f88d5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt @@ -3,6 +3,7 @@ package org.utbot.framework.codegen.domain import org.utbot.framework.DEFAULT_EXECUTION_TIMEOUT_IN_INSTRUMENTED_PROCESS_MS import org.utbot.framework.codegen.domain.builtin.mockitoClassId import org.utbot.framework.codegen.domain.builtin.ongoingStubbingClassId +import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgClassId import org.utbot.framework.codegen.tree.argumentsClassId import org.utbot.framework.plugin.api.BuiltinClassId @@ -11,6 +12,8 @@ import org.utbot.framework.plugin.api.CodeGenerationSettingBox import org.utbot.framework.plugin.api.CodeGenerationSettingItem import org.utbot.framework.plugin.api.MethodId import org.utbot.framework.plugin.api.TypeParameters +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.idOrNull import org.utbot.framework.plugin.api.isolateCommandLineArgumentsToArgumentFile import org.utbot.framework.plugin.api.util.booleanArrayClassId import org.utbot.framework.plugin.api.util.booleanClassId @@ -773,3 +776,17 @@ object SpringBoot : DependencyInjectionFramework( id = "spring-boot", displayName = "Spring Boot" ) + +/** + * Extended id of [UtModel], unique for whole test set. + * + * Allows to distinguish models from different executions, + * even if they have the same value of `UtModel.id`. + */ +data class ModelId( + private val id: Int?, + private val executionId: Int, +) + +fun UtModel.withId(executionId: Int = -1) = this to ModelId(this.idOrNull(), executionId) + diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt index e1a7c5f9ff..02476acfc4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt @@ -20,6 +20,16 @@ internal val mockitoClassId = BuiltinClassId( simpleName = "Mockito", ) +internal val mockClassId = BuiltinClassId( + canonicalName = "org.mockito.Mock", + simpleName = "Mock", +) + +internal val injectMocksClassId = BuiltinClassId( + canonicalName = "org.mockito.InjectMocks", + simpleName = "InjectMocks", +) + internal val ongoingStubbingClassId = BuiltinClassId( canonicalName = "org.mockito.stubbing.OngoingStubbing", simpleName = "OngoingStubbing", diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt index 8245fc2119..22f5580936 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt @@ -22,6 +22,7 @@ import kotlinx.collections.immutable.PersistentSet import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentSetOf +import org.utbot.framework.codegen.domain.ModelId import org.utbot.framework.codegen.domain.ProjectType import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider @@ -29,6 +30,7 @@ import org.utbot.framework.codegen.domain.builtin.UtilClassFileMethodProvider import org.utbot.framework.codegen.domain.builtin.UtilMethodProvider import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.models.CgParameterKind +import org.utbot.framework.codegen.domain.withId import org.utbot.framework.codegen.services.access.Block import org.utbot.framework.codegen.tree.EnvironmentFieldStateCache import org.utbot.framework.codegen.tree.importIfNeeded @@ -197,7 +199,7 @@ interface CgContextOwner { var valueByModel: IdentityHashMap // use it to compare stateBefore and result variables - in case of equality do not create new variable - var valueByModelId: MutableMap + var valueByModelId: MutableMap // parameters of the method currently being generated val currentMethodParameters: MutableMap @@ -226,6 +228,12 @@ interface CgContextOwner { */ var successfulExecutionsModels: List + /** + * Gives a unique identifier to model in test set. + * Determines which execution current model belongs to. + */ + var modelIds: Map + fun block(init: () -> Unit): Block { val prevBlock = currentBlock return try { @@ -311,7 +319,10 @@ interface CgContextOwner { model?.let { valueByModel[it] = variable (model as UtReferenceModel).let { refModel -> - refModel.id.let { id -> valueByModelId[id] = variable } + refModel.id.let { + val modelId = getIdByModel(model) + valueByModelId[modelId] = variable + } } } } @@ -428,6 +439,8 @@ interface CgContextOwner { val getLambdaMethod: MethodId get() = utilMethodProvider.getLambdaMethodMethodId + + fun getIdByModel(model: UtModel): ModelId } /** @@ -479,6 +492,8 @@ data class CgContext( override lateinit var actual: CgVariable override lateinit var successfulExecutionsModels: List + override var modelIds: Map = mapOf() + /** * This property cannot be accessed outside of test class file scope * (i.e. outside of [CgContextOwner.withTestClassFileScope]). @@ -556,6 +571,15 @@ data class CgContext( } } + override fun getIdByModel(model: UtModel): ModelId { + if (model !in this.modelIds) { + this.modelIds += model.withId() + } + + return modelIds[model] + ?: error("ModelId for $model should have also been created") + } + private fun createClassIdForNestedClass(testClassModel: SimpleTestClassModel): ClassId { val simpleName = "${testClassModel.classUnderTest.simpleName}Test" return BuiltinClassId( @@ -580,7 +604,7 @@ data class CgContext( override var valueByModel: IdentityHashMap = IdentityHashMap() - override var valueByModelId: MutableMap = mutableMapOf() + override var valueByModelId: MutableMap = mutableMapOf() override val currentMethodParameters: MutableMap = mutableMapOf() diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt index e049f21f3a..c85c35aef6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt @@ -7,6 +7,7 @@ import org.utbot.framework.codegen.renderer.CgRendererContext import org.utbot.framework.codegen.renderer.CgVisitor import org.utbot.framework.codegen.renderer.auxiliaryClassTextById import org.utbot.framework.codegen.renderer.utilMethodTextById +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.plugin.api.BuiltinClassId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId @@ -82,6 +83,7 @@ interface CgElement { is CgBreakStatement -> visit(element) is CgContinueStatement -> visit(element) is CgDeclaration -> visit(element) + is CgFieldDeclaration -> visit(element) is CgAssignment -> visit(element) is CgTypeCast -> visit(element) is CgIsInstance -> visit(element) @@ -134,6 +136,7 @@ class CgClass( val body: CgClassBody, val isStatic: Boolean, val isNested: Boolean, + val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, ): CgElement { val packageName get() = id.packageName @@ -156,8 +159,21 @@ class CgClassBody( val methodRegions: List, val staticDeclarationRegions: List, val nestedClassRegions: List>, - //TODO: use [CgFieldDeclaration] after PR-1788 merge - val fields: List = emptyList(), + val fields: Set = emptySet(), +) : CgElement + +/** + * Field of a class. + * @property ownerClassId [ClassId] of the field owner class. + * @property declaration declaration itself. + * @property annotation optional annotation. + * @property visibility field visibility. + */ +class CgFieldDeclaration( + val ownerClassId: ClassId, + val declaration: CgDeclaration, + val annotation: CgAnnotation? = null, + val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, ) : CgElement /** @@ -272,6 +288,7 @@ sealed class CgMethod(open val isStatic: Boolean) : CgElement { abstract val annotations: List abstract val documentation: CgDocumentationComment abstract val requiredFields: List + abstract val visibility: VisibilityModifier } class CgTestMethod( @@ -281,6 +298,7 @@ class CgTestMethod( override val statements: List, override val exceptions: Set, override val annotations: List, + override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, val type: CgTestMethodType, override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()), override val requiredFields: List = emptyList(), @@ -291,6 +309,7 @@ class CgFrameworkUtilMethod( override val statements: List, override val exceptions: Set, override val annotations: List, + override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, ) : CgMethod(isStatic = false) { override val returnType: ClassId = voidClassId override val parameters: List = emptyList() @@ -301,7 +320,8 @@ class CgFrameworkUtilMethod( class CgErrorTestMethod( override val name: String, override val statements: List, - override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()) + override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()), + override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, ) : CgMethod(isStatic = false) { override val exceptions: Set = emptySet() override val returnType: ClassId = voidClassId @@ -316,6 +336,7 @@ class CgParameterizedTestDataProviderMethod( override val returnType: ClassId, override val annotations: List, override val exceptions: Set, + override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC, ) : CgMethod(isStatic = true) { override val parameters: List = emptyList() override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt index c3adea18e8..1f596125e2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt @@ -1,6 +1,7 @@ package org.utbot.framework.codegen.domain.models import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtModel /** * Stores method test sets in a structure that replicates structure of their methods in [classUnderTest]. @@ -13,7 +14,7 @@ abstract class TestClassModel( val nestedClasses: List, ) -open class SimpleTestClassModel( +class SimpleTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List = listOf(), @@ -29,7 +30,7 @@ class SpringTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List, - val injectingMocksClass: ClassId? = null, - val mockedClasses: Set = setOf(), + val injectedMockModels: Map> = mapOf(), + val mockedModels: Map> = mapOf(), ): TestClassModel(classUnderTest, methodTestSets, nestedClasses) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt index cefcc27249..4c43d8a62f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt @@ -1,12 +1,16 @@ package org.utbot.framework.codegen.domain.models.builders +import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.util.enclosingClass -open class SimpleTestClassModelBuilder: TestClassModelBuilder() { - override fun createTestClassModel(classUnderTest: ClassId, testSets: List): SimpleTestClassModel { +open class SimpleTestClassModelBuilder(context: CgContext): TestClassModelBuilder() { + override fun createTestClassModel( + classUnderTest: ClassId, + testSets: List, + ): SimpleTestClassModel { // For each class stores list of methods declared in this class (methods from nested classes are excluded) val class2methodTestSets = testSets.groupBy { it.executableId.classId } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt index fe7c0e820e..823ecf9005 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt @@ -1,7 +1,9 @@ package org.utbot.framework.codegen.domain.models.builders +import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.SpringTestClassModel +import org.utbot.framework.codegen.domain.withId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel @@ -10,64 +12,76 @@ import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtDirectSetFieldModel import org.utbot.framework.plugin.api.UtEnumConstantModel import org.utbot.framework.plugin.api.UtExecutableCallModel -import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtLambdaModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtVoidModel +import org.utbot.framework.plugin.api.isMockModel -class SpringTestClassModelBuilder: TestClassModelBuilder() { +class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder() { override fun createTestClassModel(classUnderTest: ClassId, testSets: List): SpringTestClassModel { - val baseModel = SimpleTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) - val mockedClasses = collectMockedClassIds(classUnderTest, testSets) + val baseModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) + val (injectedModels, mockedModels) = collectInjectedAndMockedModels(testSets) return SpringTestClassModel( baseModel.classUnderTest, baseModel.methodTestSets, baseModel.nestedClasses, - classUnderTest, - mockedClasses, + injectedModels, + mockedModels, ) } - private fun collectMockedClassIds( - classUnderTest: ClassId, + private fun collectInjectedAndMockedModels( testSets: List, - ): Set { - val allModelsInExecution = mutableListOf() + ): Pair>, Map>> { + val thisInstances = mutableSetOf() + val thisInstancesDependentModels = mutableSetOf() for (testSet in testSets) { - for (execution in testSet.executions) { - execution.stateBefore.thisInstance?.let { allModelsInExecution += it } - execution.stateAfter.thisInstance?.let { allModelsInExecution += it } - - allModelsInExecution += execution.stateBefore.parameters - allModelsInExecution += execution.stateAfter.parameters + for ((index, execution) in testSet.executions.withIndex()) { + execution.stateBefore.thisInstance?.let { model -> + thisInstances += model + thisInstancesDependentModels += collectByThisInstanceModel(model, index) + } - (execution.result as? UtExecutionSuccess)?.model?.let { allModelsInExecution += it } + execution.stateAfter.thisInstance?.let { model -> + thisInstances += model + thisInstancesDependentModels += collectByThisInstanceModel(model, index) + } } } - val allConstructedModels = mutableSetOf() - allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) } + val dependentMockModels = + thisInstancesDependentModels.filterTo(mutableSetOf()) { it.isMockModel() && it !in thisInstances } - return allConstructedModels - .filter { it.isMockComposite() || it.isMockAssemble() } - .map { it.classId } - .filter { it != classUnderTest } - .toSet() + return thisInstances.groupByClassId() to dependentMockModels.groupByClassId() + } + private fun collectByThisInstanceModel(model: UtModel, executionIndex: Int): Set { + context.modelIds += model.withId(executionIndex) + + val dependentModels = mutableSetOf() + collectRecursively(model, dependentModels) + + dependentModels.forEach { model -> + context.modelIds += model.withId(executionIndex) + } + + return dependentModels + } + + private fun Set.groupByClassId(): Map> { + return this.groupBy { it.classId }.mapValues { it.value.toSet() } } private fun collectRecursively(currentModel: UtModel, allModels: MutableSet) { - if (currentModel in allModels) { + if (!allModels.add(currentModel)) { return } - allModels += currentModel - when (currentModel) { is UtNullModel, is UtPrimitiveModel, @@ -104,9 +118,4 @@ class SpringTestClassModelBuilder: TestClassModelBuilder() { //Python, JavaScript, Go models are not required in Spring } } - - private fun UtModel.isMockComposite(): Boolean = this is UtCompositeModel && this.isMock - - //TODO: Having an assemble model often means that we do not use its origin, so is this composite mock redundant? - private fun UtModel.isMockAssemble(): Boolean = this is UtAssembleModel && this.origin?.isMock == true } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt index 0f0917cc5c..780245e9c1 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt @@ -41,6 +41,7 @@ import org.utbot.framework.codegen.domain.models.CgExecutableCall import org.utbot.framework.codegen.domain.models.CgMethodsCluster import org.utbot.framework.codegen.domain.models.CgExpression import org.utbot.framework.codegen.domain.models.CgFieldAccess +import org.utbot.framework.codegen.domain.models.CgFieldDeclaration import org.utbot.framework.codegen.domain.models.CgForEachLoop import org.utbot.framework.codegen.domain.models.CgForLoop import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod @@ -83,6 +84,7 @@ import org.utbot.framework.codegen.domain.models.CgTryCatch import org.utbot.framework.codegen.domain.models.CgUtilMethod import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.domain.models.CgWhileLoop +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage @@ -574,6 +576,14 @@ abstract class CgAbstractRenderer( println(statementEnding) } + // Class field declaration + + override fun visit(element: CgFieldDeclaration) { + element.annotation?.accept(this) + renderVisibility(element.visibility) + element.declaration.accept(this) + } + // Variable assignment override fun visit(element: CgAssignment) { @@ -891,7 +901,7 @@ abstract class CgAbstractRenderer( } } - protected abstract fun renderClassVisibility(classId: ClassId) + protected abstract fun renderVisibility(modifier: VisibilityModifier) protected abstract fun renderClassModality(aClass: CgClass) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt index 456e00b373..064eb48df4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt @@ -38,13 +38,11 @@ import org.utbot.framework.codegen.domain.models.CgLiteral import org.utbot.framework.codegen.domain.models.CgTestMethod import org.utbot.framework.codegen.domain.models.CgTypeCast import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.codegen.util.nullLiteral import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeParameters import org.utbot.framework.plugin.api.util.isFinal -import org.utbot.framework.plugin.api.util.isPrivate -import org.utbot.framework.plugin.api.util.isProtected -import org.utbot.framework.plugin.api.util.isPublic import org.utbot.framework.plugin.api.util.wrapperByPrimitive internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = CgPrinterImpl()) : @@ -70,7 +68,7 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C annotation.accept(this) } - renderClassVisibility(element.id) + renderVisibility(element.visibility) renderClassModality(element) if (element.isStatic) { print("static ") @@ -92,6 +90,12 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C } override fun visit(element: CgClassBody) { + // render class fields + for (field in element.fields) { + field.accept(this) + println() + } + // render regions for test methods and utils val allRegions = element.methodRegions + element.nestedClassRegions + element.staticDeclarationRegions for ((i, region) in allRegions.withIndex()) { @@ -230,8 +234,9 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C } override fun renderMethodSignature(element: CgTestMethod) { + renderVisibility(element.visibility) // test methods always have void return type - print("public void ") + print("void ") print(element.name) print("(") @@ -243,21 +248,25 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C } override fun renderMethodSignature(element: CgErrorTestMethod) { + renderVisibility(element.visibility) // error test methods always have void return type - println("public void ${element.name}()") + println("void ${element.name}()") } override fun renderMethodSignature(element: CgParameterizedTestDataProviderMethod) { //we do not have a good string representation for two-dimensional array, so this strange if-else is required val returnType = if (element.returnType.simpleName == "Object[][]") "java.lang.Object[][]" else "${element.returnType}" - print("public static $returnType ${element.name}()") + + renderVisibility(element.visibility) + print("static $returnType ${element.name}()") renderExceptions(element) } override fun renderMethodSignature(element: CgFrameworkUtilMethod) { + renderVisibility(element.visibility) // framework util methods always have void return type - print("public void ") + print("void ") print(element.name) print("()") @@ -388,11 +397,14 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C override fun escapeNamePossibleKeywordImpl(s: String): String = s - override fun renderClassVisibility(classId: ClassId) { - when { - classId.isPublic -> print("public ") - classId.isProtected -> print("protected ") - classId.isPrivate -> print("private ") + override fun renderVisibility(modifier: VisibilityModifier) { + when (modifier) { + VisibilityModifier.PUBLIC -> print("public ") + VisibilityModifier.PRIVATE -> print("private ") + VisibilityModifier.PROTECTED -> print("protected ") + VisibilityModifier.INTERNAL -> print("internal ") + VisibilityModifier.PACKAGEPRIVATE -> Unit + else -> error("Java: unexpected visibility modifier -- $modifier") } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt index 3dcb3f7f91..b3a8f43a8e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt @@ -43,17 +43,14 @@ import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod import org.utbot.framework.codegen.domain.models.CgLiteral import org.utbot.framework.codegen.domain.models.CgTestMethod import org.utbot.framework.codegen.domain.models.CgTypeCast -import org.utbot.framework.codegen.domain.models.CgValue import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.codegen.util.nullLiteral import org.utbot.framework.plugin.api.BuiltinClassId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeParameters import org.utbot.framework.plugin.api.WildcardTypeParameter import org.utbot.framework.plugin.api.util.isFinal -import org.utbot.framework.plugin.api.util.isPrivate -import org.utbot.framework.plugin.api.util.isProtected -import org.utbot.framework.plugin.api.util.isPublic import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.isArray import org.utbot.framework.plugin.api.util.isKotlinFile @@ -85,7 +82,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = annotation.accept(this) } - renderClassVisibility(element.id) + renderVisibility(element.visibility) renderClassModality(element) if (!element.isStatic && element.isNested) { print("inner ") @@ -569,12 +566,13 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = override fun escapeNamePossibleKeywordImpl(s: String): String = if (isLanguageKeyword(s, context.cgLanguageAssistant)) "`$s`" else s - override fun renderClassVisibility(classId: ClassId) { - when { - // Kotlin classes are public by default - classId.isPublic -> Unit - classId.isProtected -> print("protected ") - classId.isPrivate -> print("private ") + override fun renderVisibility(modifier: VisibilityModifier) { + when (modifier) { + VisibilityModifier.PUBLIC -> Unit + VisibilityModifier.PRIVATE -> print("private ") + VisibilityModifier.PROTECTED -> print("protected ") + VisibilityModifier.INTERNAL -> print("internal ") + else -> error("Kotlin: unexpected visibility modifier -- $modifier") } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgVisitor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgVisitor.kt index 42258bc453..fe75905f06 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgVisitor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgVisitor.kt @@ -76,6 +76,7 @@ import org.utbot.framework.codegen.domain.models.CgSwitchCaseLabel import org.utbot.framework.codegen.domain.models.CgClass import org.utbot.framework.codegen.domain.models.CgClassBody import org.utbot.framework.codegen.domain.models.CgDocRegularLineStmt +import org.utbot.framework.codegen.domain.models.CgFieldDeclaration import org.utbot.framework.codegen.domain.models.CgFormattedString import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod import org.utbot.framework.codegen.domain.models.CgNestedClassesRegion @@ -185,6 +186,9 @@ interface CgVisitor { // Variable declaration fun visit(element: CgDeclaration): R + // Field declaration + fun visit(element: CgFieldDeclaration): R + // Variable assignment fun visit(element: CgAssignment): R diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt index e12d0b7d47..1693a7644b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt @@ -138,6 +138,12 @@ class MockFrameworkManager(context: CgContext) : CgVariableConstructorComponent( objectMocker.createMock(model, baseName) } + fun createMockForVariable(model: UtCompositeModel, variable: CgVariable) = + withMockFramework { + require(model.isMock) { "Mock model is expected in MockObjectConstructor" } + objectMocker.mockForVariable(model, variable) + } + fun mockNewInstance(mock: UtNewInstanceInstrumentation) { staticMocker?.mockNewInstance(mock) } @@ -177,6 +183,12 @@ private class MockitoMocker(context: CgContext) : ObjectMocker(context) { val modelClass = getClassOf(model.classId) val mockObject = newVar(model.classId, baseName = baseName, isMock = true) { mock(modelClass) } + mockForVariable(model, mockObject) + + return mockObject + } + + fun mockForVariable(model: UtCompositeModel, mockObject: CgVariable) { for ((executable, values) in model.mocks) { // void method if (executable.returnType == voidClassId) { @@ -201,8 +213,6 @@ private class MockitoMocker(context: CgContext) : ObjectMocker(context) { else -> error("ConstructorId was not expected to appear in simple mocker but got $executable") } } - - return mockObject } override fun mock(clazz: CgExpression): CgMethodCall = 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 6d924b600f..db1f942dcc 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,5 +1,6 @@ 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 @@ -15,6 +16,7 @@ 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 @@ -44,7 +46,12 @@ abstract class CgLanguageAssistant { open fun getCallableAccessManagerBy(context: CgContext): CgCallableAccessManager = CgCallableAccessManagerImpl(context) open fun getStatementConstructorBy(context: CgContext): CgStatementConstructor = CgStatementConstructorImpl(context) - open fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = CgVariableConstructor(context) + + open fun getVariableConstructorBy(context: CgContext): CgVariableConstructor = when (context.projectType) { + ProjectType.Spring -> CgSpringVariableConstructor(context) + else -> CgVariableConstructor(context) + } + open fun getMethodConstructorBy(context: CgContext): CgMethodConstructor = CgMethodConstructor(context) open fun getCgFieldStateManager(context: CgContext): CgFieldStateManager = CgFieldStateManagerImpl(context) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/Builders.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/Builders.kt index 1eb81a76b1..89838ade7d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/Builders.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/Builders.kt @@ -13,6 +13,7 @@ import org.utbot.framework.codegen.domain.models.CgElement import org.utbot.framework.codegen.domain.models.CgErrorTestMethod import org.utbot.framework.codegen.domain.models.CgExceptionHandler import org.utbot.framework.codegen.domain.models.CgExpression +import org.utbot.framework.codegen.domain.models.CgFieldDeclaration import org.utbot.framework.codegen.domain.models.CgForEachLoop import org.utbot.framework.codegen.domain.models.CgForLoop import org.utbot.framework.codegen.domain.models.CgLoop @@ -66,7 +67,7 @@ class CgClassBodyBuilder(val classId: ClassId) : CgBuilder { val methodRegions: MutableList = mutableListOf() val staticDeclarationRegions: MutableList = mutableListOf() val nestedClassRegions: MutableList> = mutableListOf() - val fields: MutableList = mutableListOf() + val fields: MutableSet = mutableSetOf() override fun build() = CgClassBody(classId, methodRegions, staticDeclarationRegions, nestedClassRegions, fields) } @@ -101,8 +102,8 @@ class CgTestMethodBuilder : CgMethodBuilder { statements, exceptions, annotations, - methodType, - documentation, + type = methodType, + documentation = documentation, ) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt index c63241a4ae..192f93ef42 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt @@ -2,11 +2,14 @@ package org.utbot.framework.codegen.tree import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider import org.utbot.framework.codegen.domain.builtin.closeMethodId +import org.utbot.framework.codegen.domain.builtin.injectMocksClassId +import org.utbot.framework.codegen.domain.builtin.mockClassId import org.utbot.framework.codegen.domain.builtin.openMocksMethodId import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgAssignment import org.utbot.framework.codegen.domain.models.CgClassBody import org.utbot.framework.codegen.domain.models.CgDeclaration +import org.utbot.framework.codegen.domain.models.CgFieldDeclaration import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod import org.utbot.framework.codegen.domain.models.CgMethod import org.utbot.framework.codegen.domain.models.CgMethodCall @@ -18,13 +21,16 @@ import org.utbot.framework.codegen.domain.models.CgStatementExecutableCall import org.utbot.framework.codegen.domain.models.CgStaticsRegion import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.domain.models.SpringTestClassModel +import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtCompositeModel +import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.objectClassId class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConstructor(context) { - private val variableConstructor: CgVariableConstructor = CgComponents.getVariableConstructorBy(context) + private val variableConstructor: CgSpringVariableConstructor = + CgComponents.getVariableConstructorBy(context) as CgSpringVariableConstructor private val statementConstructor: CgStatementConstructor = CgComponents.getStatementConstructorBy(context) override fun constructTestClassBody(testClassModel: SpringTestClassModel): CgClassBody { @@ -32,7 +38,8 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst // TODO: support inner classes here - // TODO: create class variables with Mock/InjectMock annotations using testClassModel + fields += constructClassFields(testClassModel.injectedMockModels, injectMocksClassId) + fields += constructClassFields(testClassModel.mockedModels, mockClassId) val (closeableField, closeableMethods) = constructMockitoCloseables() fields += closeableField @@ -77,7 +84,35 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst return if (regions.any()) regions else null } - private fun constructMockitoCloseables(): Pair { + private fun constructClassFields( + groupedModelsByClassId: Map>, + annotationClassId: ClassId + ): MutableList { + if (annotationClassId != injectMocksClassId && annotationClassId != mockClassId) { + error("Unexpected annotation ClassId -- $annotationClassId") + } + + val annotation = statementConstructor.annotation(annotationClassId) + + val constructedDeclarations = mutableListOf() + for ((classId, listOfUtModels) in groupedModelsByClassId) { + val model = listOfUtModels.firstOrNull() ?: continue + val createdVariable = variableConstructor.getOrCreateVariable(model) as? CgVariable + ?: error("[UtCompositeModel] model was expected") + + val declaration = CgDeclaration(classId, variableName = createdVariable.name, initializer = null) + constructedDeclarations += CgFieldDeclaration(ownerClassId = currentTestClass, declaration, annotation) + + when (annotationClassId) { + injectMocksClassId -> variableConstructor.injectedMocksModelsVariables += listOfUtModels to createdVariable + mockClassId -> variableConstructor.mockedModelsVariables += listOfUtModels to createdVariable + } + } + + return constructedDeclarations + } + + private fun constructMockitoCloseables(): Pair { val mockitoCloseableVarName = "mockitoCloseable" val mockitoCloseableVarType = java.lang.AutoCloseable::class.id @@ -89,7 +124,8 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst val mockitoCloseableVariable = variableConstructor.getOrCreateVariable(mockitoCloseableModel, mockitoCloseableVarName) - val mockitoCloseableField = CgDeclaration(mockitoCloseableVarType, mockitoCloseableVarName, initializer = null) + val mockitoCloseableDeclaration = CgDeclaration(mockitoCloseableVarType, mockitoCloseableVarName, initializer = null) + val mockitoCloseableFieldDeclaration = CgFieldDeclaration(ownerClassId = currentTestClass, mockitoCloseableDeclaration) importIfNeeded(openMocksMethodId) @@ -127,6 +163,6 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst listOf(CgSimpleRegion(header = null, listOf(beforeMethod, afterMethod))) ) - return mockitoCloseableField to methodCluster + return mockitoCloseableFieldDeclaration to methodCluster } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt new file mode 100644 index 0000000000..0e803ba7c0 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt @@ -0,0 +1,52 @@ +package org.utbot.framework.codegen.tree + +import com.jetbrains.rd.util.firstOrNull +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.CgValue +import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.plugin.api.UtAssembleModel +import org.utbot.framework.plugin.api.UtCompositeModel +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.isMockModel + +class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(context) { + val injectedMocksModelsVariables: MutableMap, CgValue> = mutableMapOf() + val mockedModelsVariables: MutableMap, CgValue> = mutableMapOf() + + private val mockFrameworkManager = CgComponents.getMockFrameworkManagerBy(context) + + override fun getOrCreateVariable(model: UtModel, name: String?): CgValue { + val alreadyCreatedInjectMocks = findCgValueByModel(model, injectedMocksModelsVariables) + if (alreadyCreatedInjectMocks != null) { + val fields: Collection = when (model) { + is UtCompositeModel -> model.fields.values + is UtAssembleModel -> model.origin?.fields?.values ?: emptyList() + else -> emptyList() + } + + fields.forEach { getOrCreateVariable(it) } + + return alreadyCreatedInjectMocks + } + + val alreadyCreatedMock = findCgValueByModel(model, mockedModelsVariables) + if (alreadyCreatedMock != null) { + if (model.isMockModel()) { + mockFrameworkManager.createMockForVariable( + model as UtCompositeModel, + alreadyCreatedMock as CgVariable, + ) + } + + return alreadyCreatedMock + } + + return super.getOrCreateVariable(model, name) + } + + private fun findCgValueByModel(model: UtModel, modelToValueMap: Map, CgValue>): CgValue? = + modelToValueMap + .filter { it.key.contains(model) } + .firstOrNull() + ?.value +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt index 1036ed0f39..465d90471f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt @@ -1,6 +1,7 @@ package org.utbot.framework.codegen.tree import org.utbot.common.isStatic +import org.utbot.framework.codegen.domain.ModelId import org.utbot.framework.codegen.domain.builtin.forName import org.utbot.framework.codegen.domain.builtin.setArrayElement import org.utbot.framework.codegen.domain.context.CgContext @@ -102,7 +103,9 @@ open class CgVariableConstructor(val context: CgContext) : open fun getOrCreateVariable(model: UtModel, name: String? = null): CgValue { // name could be taken from existing names, or be specified manually, or be created from generator val baseName = name ?: nameGenerator.nameFrom(model.classId) - return if (model is UtReferenceModel) valueByModelId.getOrPut(model.id) { + val modelId: ModelId = context.getIdByModel(model) + + return if (model is UtReferenceModel) valueByModelId.getOrPut(modelId) { when (model) { is UtCompositeModel -> constructComposite(model, baseName) is UtAssembleModel -> constructAssemble(model, baseName) @@ -172,7 +175,8 @@ open class CgVariableConstructor(val context: CgContext) : newVar(variableType, baseName) { utilsClassId[createInstance](model.classId.name) } } - valueByModelId[model.id] = obj + val modelId = context.getIdByModel(model) + valueByModelId[modelId] = obj require(obj.type !is BuiltinClassId) { "Unexpected BuiltinClassId ${obj.type} found while constructing from composite model" @@ -225,7 +229,8 @@ open class CgVariableConstructor(val context: CgContext) : } } - return valueByModelId.getValue(model.id) + val modelId = context.getIdByModel(model) + return valueByModelId.getValue(modelId) } private fun processInstantiationStatement( @@ -248,7 +253,10 @@ open class CgVariableConstructor(val context: CgContext) : } newVar(type, model, baseName) { initExpr - }.also { valueByModelId[model.id] = it } + }.also { + val modelId = context.getIdByModel(model) + valueByModelId[modelId] = it + } } @@ -345,7 +353,8 @@ open class CgVariableConstructor(val context: CgContext) : } val array = newVar(arrayModel.classId, baseName) { initializer } - valueByModelId[arrayModel.id] = array + val arrayModelId = context.getIdByModel(arrayModel) + valueByModelId[arrayModelId] = array if (canInitWithValues) { return array diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt index e2072cc5b3..c1d69a6de4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt @@ -12,4 +12,15 @@ fun needExpectedDeclaration(model: UtModel): Boolean { val representsNull = model is UtNullModel val representsBoolean = model is UtPrimitiveModel && model.value is Boolean return !(representsNull || representsBoolean) +} + +/** + * Contains all possible visibility modifiers that may be used in code generation. + */ +enum class VisibilityModifier { + PUBLIC, + PRIVATE, + PROTECTED, + INTERNAL, + PACKAGEPRIVATE, } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt index e95cc06b86..7b442a28d8 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt @@ -39,7 +39,9 @@ class JsCgVariableConstructor(ctx: CgContext) : CgVariableConstructor(ctx) { private val nameGenerator = CgComponents.getNameGeneratorBy(context) override fun getOrCreateVariable(model: UtModel, name: String?): CgValue { - return if (model is UtAssembleModel) valueByModelId.getOrPut(model.id) { + val modelId: ModelId = context.getIdByModel(model) + + return if (model is UtAssembleModel) valueByModelId.getOrPut(modelId) { // TODO SEVERE: May lead to unexpected behavior in case of changes to the original method super.getOrCreateVariable(model, name) } else valueByModel.getOrPut(model) { @@ -128,7 +130,9 @@ class JsCgVariableConstructor(ctx: CgContext) : CgVariableConstructor(ctx) { } val array = newVar(arrayModel.classId, baseName) { initializer } - valueByModelId[arrayModel.id] = array + val arrayModelId = context.getIdByModel(arrayModel) + + valueByModelId[arrayModelId] = array if (canInitWithValues) { return array diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt index 2eaad9149d..d4e71da534 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt @@ -50,6 +50,8 @@ import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgPrinter import org.utbot.framework.codegen.renderer.CgPrinterImpl import org.utbot.framework.codegen.renderer.CgRendererContext +import org.utbot.framework.codegen.services.language.isLanguageKeyword +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeParameters @@ -410,7 +412,7 @@ internal class CgJsRenderer(context: CgRendererContext, printer: CgPrinter = CgP override fun escapeNamePossibleKeywordImpl(s: String): String = s - override fun renderClassVisibility(classId: ClassId) { + override fun renderVisibility(modifier: VisibilityModifier) { TODO("Not yet implemented") } diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt index 5b2379d5a7..01ed426d20 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt @@ -58,6 +58,7 @@ import org.utbot.framework.codegen.renderer.CgPrinter import org.utbot.framework.codegen.renderer.CgPrinterImpl import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgRendererContext +import org.utbot.framework.codegen.tree.VisibilityModifier import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeParameters import org.utbot.framework.plugin.api.WildcardTypeParameter @@ -420,7 +421,7 @@ internal class CgPythonRenderer( } override fun escapeNamePossibleKeywordImpl(s: String): String = s - override fun renderClassVisibility(classId: ClassId) { + override fun renderVisibility(modifier: VisibilityModifier) { throw UnsupportedOperationException() } From 11a817baca5a083d9ef64f7b7d907b55d2a7ad88 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 21 Mar 2023 23:28:28 +0300 Subject: [PATCH 2/6] Apply review fixes --- .../utbot/framework/codegen/domain/Domain.kt | 2 +- .../codegen/domain/context/CgContext.kt | 15 ++++++------- .../codegen/domain/models/TestClassModel.kt | 6 ++++-- .../builders/SpringTestClassModelBuilder.kt | 21 ++++++++++++------- .../codegen/renderer/CgJavaRenderer.kt | 5 ++--- .../codegen/renderer/CgKotlinRenderer.kt | 2 +- .../framework/MockFrameworkManager.kt | 2 +- .../tree/CgSpringTestClassConstructor.kt | 5 +++-- .../tree/CgSpringVariableConstructor.kt | 3 ++- .../codegen/tree/DeclarationUtils.kt | 2 +- 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt index a9299f88d5..142ae27d79 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt @@ -788,5 +788,5 @@ data class ModelId( private val executionId: Int, ) -fun UtModel.withId(executionId: Int = -1) = this to ModelId(this.idOrNull(), executionId) +fun UtModel.withExecutionId(executionId: Int = -1) = ModelId(this.idOrNull(), executionId) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt index 22f5580936..702b49d729 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt @@ -30,7 +30,7 @@ import org.utbot.framework.codegen.domain.builtin.UtilClassFileMethodProvider import org.utbot.framework.codegen.domain.builtin.UtilMethodProvider import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.models.CgParameterKind -import org.utbot.framework.codegen.domain.withId +import org.utbot.framework.codegen.domain.withExecutionId import org.utbot.framework.codegen.services.access.Block import org.utbot.framework.codegen.tree.EnvironmentFieldStateCache import org.utbot.framework.codegen.tree.importIfNeeded @@ -232,7 +232,7 @@ interface CgContextOwner { * Gives a unique identifier to model in test set. * Determines which execution current model belongs to. */ - var modelIds: Map + var modelIds: PersistentMap fun block(init: () -> Unit): Block { val prevBlock = currentBlock @@ -492,7 +492,7 @@ data class CgContext( override lateinit var actual: CgVariable override lateinit var successfulExecutionsModels: List - override var modelIds: Map = mapOf() + override var modelIds: PersistentMap = persistentMapOf() /** * This property cannot be accessed outside of test class file scope @@ -572,12 +572,13 @@ data class CgContext( } override fun getIdByModel(model: UtModel): ModelId { - if (model !in this.modelIds) { - this.modelIds += model.withId() + if (model !in modelIds) { + modelIds.put(model, model.withExecutionId()) } - return modelIds[model] - ?: error("ModelId for $model should have also been created") + return modelIds.getOrElse(model) { + error("ModelId for $model should have also been created") + } } private fun createClassIdForNestedClass(testClassModel: SimpleTestClassModel): ClassId { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt index 1f596125e2..c7b2e54792 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt @@ -3,6 +3,8 @@ package org.utbot.framework.codegen.domain.models import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtModel +typealias ClassModels = Map> + /** * Stores method test sets in a structure that replicates structure of their methods in [classUnderTest]. * I.e., if some method is declared in nested class of [classUnderTest], its testset will be put @@ -30,7 +32,7 @@ class SpringTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List, - val injectedMockModels: Map> = mapOf(), - val mockedModels: Map> = mapOf(), + val injectedMockModels: ClassModels = mapOf(), + val mockedModels: ClassModels = mapOf(), ): TestClassModel(classUnderTest, methodTestSets, nestedClasses) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt index 823ecf9005..332f0e557e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt @@ -2,8 +2,9 @@ package org.utbot.framework.codegen.domain.models.builders import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet +import org.utbot.framework.codegen.domain.models.ClassModels import org.utbot.framework.codegen.domain.models.SpringTestClassModel -import org.utbot.framework.codegen.domain.withId +import org.utbot.framework.codegen.domain.withExecutionId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel @@ -34,9 +35,7 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder ) } - private fun collectInjectedAndMockedModels( - testSets: List, - ): Pair>, Map>> { + private fun collectInjectedAndMockedModels(testSets: List): Pair { val thisInstances = mutableSetOf() val thisInstancesDependentModels = mutableSetOf() @@ -61,20 +60,26 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder } private fun collectByThisInstanceModel(model: UtModel, executionIndex: Int): Set { - context.modelIds += model.withId(executionIndex) + context.modelIds.put(model, model.withExecutionId(executionIndex)) val dependentModels = mutableSetOf() collectRecursively(model, dependentModels) dependentModels.forEach { model -> - context.modelIds += model.withId(executionIndex) + context.modelIds.put(model, model.withExecutionId(executionIndex)) } return dependentModels } - private fun Set.groupByClassId(): Map> { - return this.groupBy { it.classId }.mapValues { it.value.toSet() } + private fun Set.groupByClassId(): ClassModels { + val classModels = mutableMapOf>() + + for (modelGroup in this.groupBy { it.classId }) { + classModels[modelGroup.key] = modelGroup.value.toSet() + } + + return classModels } private fun collectRecursively(currentModel: UtModel, allModels: MutableSet) { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt index 064eb48df4..8b26785a87 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt @@ -402,9 +402,8 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C VisibilityModifier.PUBLIC -> print("public ") VisibilityModifier.PRIVATE -> print("private ") VisibilityModifier.PROTECTED -> print("protected ") - VisibilityModifier.INTERNAL -> print("internal ") - VisibilityModifier.PACKAGEPRIVATE -> Unit - else -> error("Java: unexpected visibility modifier -- $modifier") + VisibilityModifier.PACKAGE_PRIVATE -> Unit + VisibilityModifier.INTERNAL -> error("Java: unexpected visibility modifier -- $modifier") } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt index b3a8f43a8e..8a92d09617 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgKotlinRenderer.kt @@ -572,7 +572,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = VisibilityModifier.PRIVATE -> print("private ") VisibilityModifier.PROTECTED -> print("protected ") VisibilityModifier.INTERNAL -> print("internal ") - else -> error("Kotlin: unexpected visibility modifier -- $modifier") + VisibilityModifier.PACKAGE_PRIVATE -> error("Kotlin: unexpected visibility modifier -- $modifier") } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt index 1693a7644b..32136f49ba 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt @@ -140,7 +140,7 @@ class MockFrameworkManager(context: CgContext) : CgVariableConstructorComponent( fun createMockForVariable(model: UtCompositeModel, variable: CgVariable) = withMockFramework { - require(model.isMock) { "Mock model is expected in MockObjectConstructor" } + require(model.isMock) { "Mock model $model is expected in MockObjectConstructor" } objectMocker.mockForVariable(model, variable) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt index 192f93ef42..ef94026636 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt @@ -20,6 +20,7 @@ import org.utbot.framework.codegen.domain.models.CgSimpleRegion import org.utbot.framework.codegen.domain.models.CgStatementExecutableCall import org.utbot.framework.codegen.domain.models.CgStaticsRegion import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.domain.models.ClassModels import org.utbot.framework.codegen.domain.models.SpringTestClassModel import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtCompositeModel @@ -85,7 +86,7 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst } private fun constructClassFields( - groupedModelsByClassId: Map>, + groupedModelsByClassId: ClassModels, annotationClassId: ClassId ): MutableList { if (annotationClassId != injectMocksClassId && annotationClassId != mockClassId) { @@ -98,7 +99,7 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst for ((classId, listOfUtModels) in groupedModelsByClassId) { val model = listOfUtModels.firstOrNull() ?: continue val createdVariable = variableConstructor.getOrCreateVariable(model) as? CgVariable - ?: error("[UtCompositeModel] model was expected") + ?: error("`UtCompositeModel` model was expected, but $model was found") val declaration = CgDeclaration(classId, variableName = createdVariable.name, initializer = null) constructedDeclarations += CgFieldDeclaration(ownerClassId = currentTestClass, declaration, annotation) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt index 0e803ba7c0..b14623cafc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt @@ -47,6 +47,7 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co private fun findCgValueByModel(model: UtModel, modelToValueMap: Map, CgValue>): CgValue? = modelToValueMap .filter { it.key.contains(model) } - .firstOrNull() + .asSequence() + .singleOrNull() ?.value } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt index c1d69a6de4..abf2e4d4b5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/DeclarationUtils.kt @@ -22,5 +22,5 @@ enum class VisibilityModifier { PRIVATE, PROTECTED, INTERNAL, - PACKAGEPRIVATE, + PACKAGE_PRIVATE, } \ No newline at end of file From 2d88d209ca6aa80159964df2c8aa90b45aed4d07 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Wed, 22 Mar 2023 11:58:18 +0300 Subject: [PATCH 3/6] Replace PersistentMap with MutableMap --- .../org/utbot/framework/codegen/domain/context/CgContext.kt | 6 +++--- .../domain/models/builders/SpringTestClassModelBuilder.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt index 702b49d729..c8ecf54406 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt @@ -232,7 +232,7 @@ interface CgContextOwner { * Gives a unique identifier to model in test set. * Determines which execution current model belongs to. */ - var modelIds: PersistentMap + var modelIds: MutableMap fun block(init: () -> Unit): Block { val prevBlock = currentBlock @@ -492,7 +492,7 @@ data class CgContext( override lateinit var actual: CgVariable override lateinit var successfulExecutionsModels: List - override var modelIds: PersistentMap = persistentMapOf() + override var modelIds: MutableMap = mutableMapOf() /** * This property cannot be accessed outside of test class file scope @@ -573,7 +573,7 @@ data class CgContext( override fun getIdByModel(model: UtModel): ModelId { if (model !in modelIds) { - modelIds.put(model, model.withExecutionId()) + modelIds[model] = model.withExecutionId() } return modelIds.getOrElse(model) { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt index 332f0e557e..91544ecda2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt @@ -60,13 +60,13 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder } private fun collectByThisInstanceModel(model: UtModel, executionIndex: Int): Set { - context.modelIds.put(model, model.withExecutionId(executionIndex)) + context.modelIds[model] = model.withExecutionId(executionIndex) val dependentModels = mutableSetOf() collectRecursively(model, dependentModels) dependentModels.forEach { model -> - context.modelIds.put(model, model.withExecutionId(executionIndex)) + context.modelIds[model] = model.withExecutionId(executionIndex) } return dependentModels From bb04eb2a0d6008761fa0269c973aeec84900eb6f Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Wed, 22 Mar 2023 13:14:57 +0300 Subject: [PATCH 4/6] Avoid InjectMocks if not required --- .../tree/CgSpringTestClassConstructor.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt index ef94026636..c87431cf89 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt @@ -39,12 +39,16 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst // TODO: support inner classes here - fields += constructClassFields(testClassModel.injectedMockModels, injectMocksClassId) - fields += constructClassFields(testClassModel.mockedModels, mockClassId) + val mockedFields = constructClassFields(testClassModel.mockedModels, mockClassId) - val (closeableField, closeableMethods) = constructMockitoCloseables() - fields += closeableField - methodRegions += closeableMethods + if (mockedFields.isNotEmpty()) { + fields += constructClassFields(testClassModel.injectedMockModels, injectMocksClassId) + fields += mockedFields + + val (closeableField, closeableMethods) = constructMockitoCloseables() + fields += closeableField + methodRegions += closeableMethods + } for (testSet in testClassModel.methodTestSets) { updateCurrentExecutable(testSet.executableId) @@ -89,8 +93,8 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst groupedModelsByClassId: ClassModels, annotationClassId: ClassId ): MutableList { - if (annotationClassId != injectMocksClassId && annotationClassId != mockClassId) { - error("Unexpected annotation ClassId -- $annotationClassId") + require(annotationClassId == injectMocksClassId || annotationClassId == mockClassId) { + error("Unexpected annotation classId -- $annotationClassId") } val annotation = statementConstructor.annotation(annotationClassId) From 7c6ed6b65476ead679bc24a86a0d7c4ddb9b5b47 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Wed, 22 Mar 2023 14:55:00 +0300 Subject: [PATCH 5/6] Fix compilation --- .../codegen/model/constructor/tree/JsCgVariableConstructor.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt index 7b442a28d8..f863cbcc52 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt @@ -9,6 +9,7 @@ import framework.api.js.util.jsDoubleClassId import framework.api.js.util.jsNumberClassId import framework.api.js.util.jsStringClassId import framework.api.js.util.jsUndefinedClassId +import org.utbot.framework.codegen.domain.ModelId import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgAllocateArray import org.utbot.framework.codegen.domain.models.CgArrayInitializer From 9094c6073f4c03acac925401b6346484d5a1808a Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Wed, 22 Mar 2023 15:15:32 +0300 Subject: [PATCH 6/6] Fix review comments --- .../framework/codegen/domain/context/CgContext.kt | 11 ++--------- .../codegen/tree/CgSpringVariableConstructor.kt | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt index c8ecf54406..616305e393 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/context/CgContext.kt @@ -571,15 +571,7 @@ data class CgContext( } } - override fun getIdByModel(model: UtModel): ModelId { - if (model !in modelIds) { - modelIds[model] = model.withExecutionId() - } - - return modelIds.getOrElse(model) { - error("ModelId for $model should have also been created") - } - } + override fun getIdByModel(model: UtModel): ModelId = modelIds.getOrPut(model) { model.withExecutionId() } private fun createClassIdForNestedClass(testClassModel: SimpleTestClassModel): ClassId { val simpleName = "${testClassModel.classUnderTest.simpleName}Test" @@ -599,6 +591,7 @@ data class CgContext( requiredUtilMethods.clear() valueByModel.clear() valueByModelId.clear() + modelIds.clear() mockFrameworkUsed = false } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt index b14623cafc..347f009e8a 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt @@ -47,7 +47,7 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co private fun findCgValueByModel(model: UtModel, modelToValueMap: Map, CgValue>): CgValue? = modelToValueMap .filter { it.key.contains(model) } - .asSequence() + .entries .singleOrNull() ?.value } \ No newline at end of file