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 a40128503a..8dc5706567 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -1502,7 +1502,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, @@ -1520,14 +1520,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..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 @@ -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.withExecutionId(executionId: Int = -1) = 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..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 @@ -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.withExecutionId 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: MutableMap + 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: MutableMap = mutableMapOf() + /** * This property cannot be accessed outside of test class file scope * (i.e. outside of [CgContextOwner.withTestClassFileScope]). @@ -556,6 +571,8 @@ data class CgContext( } } + override fun getIdByModel(model: UtModel): ModelId = modelIds.getOrPut(model) { model.withExecutionId() } + private fun createClassIdForNestedClass(testClassModel: SimpleTestClassModel): ClassId { val simpleName = "${testClassModel.classUnderTest.simpleName}Test" return BuiltinClassId( @@ -574,13 +591,14 @@ data class CgContext( requiredUtilMethods.clear() valueByModel.clear() valueByModelId.clear() + modelIds.clear() mockFrameworkUsed = false } 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 e71e43239c..894db6db9f 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..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 @@ -1,6 +1,9 @@ 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]. @@ -13,7 +16,7 @@ abstract class TestClassModel( val nestedClasses: List, ) -open class SimpleTestClassModel( +class SimpleTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List = listOf(), @@ -29,7 +32,7 @@ class SpringTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List, - val injectingMocksClass: ClassId? = null, - val mockedClasses: Set = setOf(), + 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/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..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 @@ -1,7 +1,10 @@ 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.withExecutionId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel @@ -10,64 +13,80 @@ 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, - testSets: List, - ): Set { - val allModelsInExecution = mutableListOf() + private fun collectInjectedAndMockedModels(testSets: List): Pair { + 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 thisInstances.groupByClassId() to dependentMockModels.groupByClassId() + } + + private fun collectByThisInstanceModel(model: UtModel, executionIndex: Int): Set { + context.modelIds[model] = model.withExecutionId(executionIndex) + + val dependentModels = mutableSetOf() + collectRecursively(model, dependentModels) + + dependentModels.forEach { model -> + context.modelIds[model] = model.withExecutionId(executionIndex) + } + + return dependentModels + } + + private fun Set.groupByClassId(): ClassModels { + val classModels = mutableMapOf>() - return allConstructedModels - .filter { it.isMockComposite() || it.isMockAssemble() } - .map { it.classId } - .filter { it != classUnderTest } - .toSet() + for (modelGroup in this.groupBy { it.classId }) { + classModels[modelGroup.key] = modelGroup.value.toSet() + } + return classModels } 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 +123,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 8cc5cb3adc..1b19e575dd 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..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 @@ -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,13 @@ 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.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 3dcb3f7f91..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 @@ -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 ") + VisibilityModifier.PACKAGE_PRIVATE -> 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 5b19cd6671..3ecfb1ed6f 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 $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..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 @@ -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 @@ -17,14 +20,18 @@ 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 +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,11 +39,16 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst // TODO: support inner classes here - // TODO: create class variables with Mock/InjectMock annotations using testClassModel + 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) @@ -77,7 +89,35 @@ class CgSpringTestClassConstructor(context: CgContext): CgAbstractTestClassConst return if (regions.any()) regions else null } - private fun constructMockitoCloseables(): Pair { + private fun constructClassFields( + groupedModelsByClassId: ClassModels, + annotationClassId: ClassId + ): MutableList { + require(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, but $model was found") + + 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 +129,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 +168,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..347f009e8a --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt @@ -0,0 +1,53 @@ +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) } + .entries + .singleOrNull() + ?.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..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 @@ -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, + PACKAGE_PRIVATE, } \ 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..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 @@ -39,7 +40,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 +131,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() }