From dd8d4912fc8fd9c8e31496eea4ed2c66a0791d40 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 14 Feb 2023 10:46:51 +0300 Subject: [PATCH 1/5] Collect mocked class variables in Spring tests --- .../utbot/framework/codegen/CodeGenerator.kt | 6 +- .../codegen/domain/context/CgContext.kt | 4 + .../codegen/domain/models/TestClassModel.kt | 56 ++----- .../domain/models/TestClassModelBuilder.kt | 151 ++++++++++++++++++ 4 files changed, 168 insertions(+), 49 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt 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 ebb662c064..dedd1564db 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 @@ -8,8 +8,8 @@ import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.domain.models.CgMethodTestSet -import org.utbot.framework.codegen.domain.models.TestClassModel import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.TestClassModelBuilder import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.reports.TestsGenerationReport import org.utbot.framework.codegen.tree.CgSimpleTestClassConstructor @@ -75,7 +75,9 @@ open class CodeGenerator( context.withTestClassFileScope { val astConstructor = CgSimpleTestClassConstructor(context) val renderer = CgAbstractRenderer.makeRenderer(context) - val testClassModel = TestClassModel.fromTestSets(classUnderTest, cgTestSets) + val testClassModelBuilder = TestClassModelBuilder(context.isSpringClass) + + val testClassModel = testClassModelBuilder.createClassModel(classUnderTest, cgTestSets) fun now() = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) 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 356d07270a..4ca4b09af6 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 @@ -66,6 +66,9 @@ interface CgContextOwner { // current class under test val classUnderTest: ClassId + // If test class is configured with Spring, we should do some extra analysis + val isSpringClass: Boolean + // test class currently being generated (if series of nested classes is generated, it is the outermost one) val outerMostTestClass: ClassId @@ -431,6 +434,7 @@ interface CgContextOwner { */ data class CgContext( override val classUnderTest: ClassId, + override val isSpringClass: Boolean = true, val generateUtilClassFile: Boolean = false, override var currentExecutable: ExecutableId? = null, override val collectedExceptions: MutableSet = mutableSetOf(), 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 1786212e9d..c6fdeddee4 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,58 +1,20 @@ package org.utbot.framework.codegen.domain.models import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.util.enclosingClass // TODO: seems like this class needs to be renamed /** - * Stores method testsets in a structure that replicates structure of their methods in [classUnderTest]. + * 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 * in [TestClassModel] in one of [nestedClasses] + * + * @param injectingMocksClass a class to inject other mocks into + * @param mockedClasses variables of test class to represent mocked instances */ -data class TestClassModel( +class TestClassModel( val classUnderTest: ClassId, val methodTestSets: List, - val nestedClasses: List = listOf() -) { - companion object { - fun fromTestSets(classUnderTest: ClassId, testSets: List): TestClassModel { - // For each class stores list of methods declared in this class (methods from nested classes are excluded) - val class2methodTestSets = testSets.groupBy { it.executableId.classId } - - val classesWithMethodsUnderTest = testSets - .map { it.executableId.classId } - .distinct() - - // For each class stores list of its "direct" nested classes - val class2nestedClasses = mutableMapOf>() - - for (classId in classesWithMethodsUnderTest) { - var currentClass = classId - var enclosingClass = currentClass.enclosingClass - // while we haven't reached the top of nested class hierarchy or the main class under test - while (enclosingClass != null && currentClass != classUnderTest) { - class2nestedClasses.getOrPut(enclosingClass) { mutableSetOf() } += currentClass - currentClass = enclosingClass - enclosingClass = enclosingClass.enclosingClass - } - } - return constructRecursively(classUnderTest, class2methodTestSets, class2nestedClasses) - } - - private fun constructRecursively( - clazz: ClassId, - class2methodTestSets: Map>, - class2nestedClasses: Map> - ): TestClassModel { - val currentNestedClasses = class2nestedClasses.getOrDefault(clazz, listOf()) - val currentMethodTestSets = class2methodTestSets.getOrDefault(clazz, listOf()) - return TestClassModel( - clazz, - currentMethodTestSets, - currentNestedClasses.map { - constructRecursively(it, class2methodTestSets, class2nestedClasses) - } - ) - } - } -} \ No newline at end of file + val nestedClasses: List = listOf(), + val injectingMocksClass: ClassId? = null, + val mockedClasses: Set = setOf(), +) \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt new file mode 100644 index 0000000000..4e3688592f --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt @@ -0,0 +1,151 @@ +package org.utbot.framework.codegen.domain.models + +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtArrayModel +import org.utbot.framework.plugin.api.UtAssembleModel +import org.utbot.framework.plugin.api.UtClassRefModel +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.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.util.enclosingClass + +class TestClassModelBuilder( + private val isSpringClass: Boolean +) { + fun createClassModel(classUnderTest: ClassId, testSets: List): TestClassModel { + // For each class stores list of methods declared in this class (methods from nested classes are excluded) + val class2methodTestSets = testSets.groupBy { it.executableId.classId } + + val classesWithMethodsUnderTest = testSets + .map { it.executableId.classId } + .distinct() + + // For each class stores list of its "direct" nested classes + val class2nestedClasses = mutableMapOf>() + + for (classId in classesWithMethodsUnderTest) { + var currentClass = classId + var enclosingClass = currentClass.enclosingClass + // while we haven't reached the top of nested class hierarchy or the main class under test + while (enclosingClass != null && currentClass != classUnderTest) { + class2nestedClasses.getOrPut(enclosingClass) { mutableSetOf() } += currentClass + currentClass = enclosingClass + enclosingClass = enclosingClass.enclosingClass + } + } + + val baseModel = constructRecursively(classUnderTest, class2methodTestSets, class2nestedClasses) + + return if (!isSpringClass) { + baseModel + } else { + val mockedClasses = collectMockedClassIds(classUnderTest, testSets) + + TestClassModel( + baseModel.classUnderTest, + baseModel.methodTestSets, + baseModel.nestedClasses, + classUnderTest, + mockedClasses, + ) + } + } + + private fun constructRecursively( + clazz: ClassId, + class2methodTestSets: Map>, + class2nestedClasses: Map> + ): TestClassModel { + val currentNestedClasses = class2nestedClasses.getOrDefault(clazz, listOf()) + val currentMethodTestSets = class2methodTestSets.getOrDefault(clazz, listOf()) + return TestClassModel( + clazz, + currentMethodTestSets, + currentNestedClasses.map { + constructRecursively(it, class2methodTestSets, class2nestedClasses) + } + ) + } + + private fun collectMockedClassIds( + classUnderTest: ClassId, + testSets: List, + ): Set { + val allModelsInExecution = mutableListOf() + + 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 + } + } + + val allConstructedModels = HashSet() + allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) } + + return allConstructedModels + .filter { it.isMockComposite() || it.isMockAssemble() } + .map { it.classId } + .filter { it != classUnderTest } + .toSet() + + } + + private fun collectRecursively(currentModel: UtModel, allModels: HashSet) { + if (currentModel in allModels) { + return + } + + allModels += currentModel + + when (currentModel) { + is UtNullModel, + is UtPrimitiveModel, + is UtClassRefModel, + is UtVoidModel, + is UtEnumConstantModel -> {} + is UtLambdaModel -> { + currentModel.capturedValues.forEach { collectRecursively(it, allModels) } + } + is UtArrayModel -> { + collectRecursively(currentModel.constModel, allModels) + currentModel.stores.values.forEach { collectRecursively(it, allModels) } + } + is UtCompositeModel -> { + currentModel.fields.values.forEach { collectRecursively(it, allModels) } + currentModel.mocks.values.flatten().forEach { collectRecursively(it, allModels) } + } + is UtAssembleModel -> { + if (currentModel.origin != null) { + collectRecursively(currentModel.origin!!, allModels) + } else { + currentModel.instantiationCall.instance?.let { collectRecursively(it, allModels) } + currentModel.instantiationCall.params.forEach { collectRecursively(it, allModels) } + + currentModel.modificationsChain.forEach { stmt -> + stmt.instance?.let { collectRecursively(it, allModels) } + when (stmt) { + is UtExecutableCallModel -> stmt.params.forEach { collectRecursively(it, allModels) } + is UtDirectSetFieldModel -> collectRecursively(stmt.fieldModel, allModels) + } + } + } + } + //Python, JavaScript, Go models are not required in Spring + else -> {} + } + } + + private fun UtModel.isMockComposite(): Boolean = this is UtCompositeModel && this.isMock + + private fun UtModel.isMockAssemble(): Boolean = + this is UtAssembleModel && this.origin?.let { it.isMock } == true +} \ No newline at end of file From 49814bffff420da06e8d5deebe0eefcaa18552f1 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 14 Feb 2023 12:34:52 +0300 Subject: [PATCH 2/5] Temporarily disable functionality --- .../org/utbot/framework/codegen/domain/context/CgContext.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4ca4b09af6..c1d61f29df 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 @@ -434,7 +434,7 @@ interface CgContextOwner { */ data class CgContext( override val classUnderTest: ClassId, - override val isSpringClass: Boolean = true, + override val isSpringClass: Boolean = false, val generateUtilClassFile: Boolean = false, override var currentExecutable: ExecutableId? = null, override val collectedExceptions: MutableSet = mutableSetOf(), From ab3daede62b3fb7ae2bc5e73b818f8f18b404a27 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 14 Feb 2023 17:01:47 +0300 Subject: [PATCH 3/5] Apply review fixes --- .../assemble/AssembleModelGenerator.kt | 10 +- .../utbot/framework/codegen/CodeGenerator.kt | 70 +++++--- .../codegen/domain/context/CgContext.kt | 10 +- .../codegen/domain/models/TestClassModel.kt | 27 +++- .../domain/models/TestClassModelBuilder.kt | 151 ------------------ .../builders/SimpleTestClassModelBuilder.kt | 49 ++++++ .../builders/SpringTestClassModelBuilder.kt | 112 +++++++++++++ .../models/builders/TestClassModelBuilder.kt | 9 ++ .../tree/CgSimpleTestClassConstructor.kt | 96 ++++++----- .../tree/CgSpringTestClassConstructor.kt | 15 ++ .../tree/CgTestClassConstructorBase.kt | 13 +- .../codegen/model/PythonCodeGenerator.kt | 4 +- .../tree/PythonCgTestClassConstructor.kt | 4 +- 13 files changed, 330 insertions(+), 240 deletions(-) delete mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/TestClassModelBuilder.kt create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt index 1a8175da76..20afe58a83 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt @@ -343,23 +343,23 @@ class AssembleModelGenerator(private val basePackageName: String) { private fun assembleMockCompositeModel(compositeModel: UtCompositeModel): UtCompositeModel { // We have to create a model before the construction of the fields to avoid // infinite recursion when some mock contains itself as a field. - val assembledModel = UtCompositeModel( + val assembledCompositeModel = UtCompositeModel( compositeModel.id, compositeModel.classId, isMock = true, ) - instantiatedModels[compositeModel] = assembledModel + instantiatedModels[compositeModel] = assembledCompositeModel val fields = compositeModel.fields.mapValues { assembleModel(it.value) }.toMutableMap() val mockBehaviour = compositeModel.mocks .mapValues { models -> models.value.map { assembleModel(it) } } .toMutableMap() - assembledModel.fields += fields - assembledModel.mocks += mockBehaviour + assembledCompositeModel.fields += fields + assembledCompositeModel.mocks += mockBehaviour - return assembledModel + return assembledCompositeModel } /** 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 dedd1564db..f921cec3b0 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 @@ -9,12 +9,15 @@ import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.context.CgContext -import org.utbot.framework.codegen.domain.models.TestClassModelBuilder +import org.utbot.framework.codegen.domain.models.CgClassFile +import org.utbot.framework.codegen.domain.models.builders.SimpleTestClassModelBuilder +import org.utbot.framework.codegen.domain.models.builders.SpringTestClassModelBuilder import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.reports.TestsGenerationReport import org.utbot.framework.codegen.tree.CgSimpleTestClassConstructor import org.utbot.framework.codegen.tree.ututils.UtilClassKind import org.utbot.framework.codegen.services.language.CgLanguageAssistant +import org.utbot.framework.codegen.tree.CgSpringTestClassConstructor import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.ExecutableId @@ -73,31 +76,60 @@ open class CodeGenerator( val cgTestSets = testSets.map { CgMethodTestSet(it) }.toList() return withCustomContext(testClassCustomName) { context.withTestClassFileScope { - val astConstructor = CgSimpleTestClassConstructor(context) - val renderer = CgAbstractRenderer.makeRenderer(context) - val testClassModelBuilder = TestClassModelBuilder(context.isSpringClass) + if (context.isSpringClass) { + generateForSpringClass(cgTestSets) + } else { + generateForSimpleClass(cgTestSets) + } + } + } + } - val testClassModel = testClassModelBuilder.createClassModel(classUnderTest, cgTestSets) + private fun generateForSimpleClass(testSets: List): CodeGeneratorResult { + val astConstructor = CgSimpleTestClassConstructor(context) + val testClassModel = SimpleTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) - fun now() = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) + logger.info { "Code generation phase started at ${now()}" } + val testClassFile = astConstructor.construct(testClassModel) + logger.info { "Code generation phase finished at ${now()}" } - logger.info { "Code generation phase started at ${now()}" } - val testClassFile = astConstructor.construct(testClassModel) - logger.info { "Code generation phase finished at ${now()}" } + val generatedCode = renderToString(testClassFile) - logger.info { "Rendering phase started at ${now()}" } - testClassFile.accept(renderer) - logger.info { "Rendering phase finished at ${now()}" } + return CodeGeneratorResult( + generatedCode = generatedCode, + utilClassKind = UtilClassKind.fromCgContextOrNull(context), + testsGenerationReport = astConstructor.testsGenerationReport + ) + } - CodeGeneratorResult( - generatedCode = renderer.toString(), - utilClassKind = UtilClassKind.fromCgContextOrNull(context), - testsGenerationReport = astConstructor.testsGenerationReport - ) - } - } + private fun generateForSpringClass(testSets: List): CodeGeneratorResult { + val astConstructor = CgSpringTestClassConstructor(context) + val testClassModel = SpringTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) + + logger.info { "Code generation phase started at ${now()}" } + val testClassFile = astConstructor.construct(testClassModel) + logger.info { "Code generation phase finished at ${now()}" } + + val generatedCode = renderToString(testClassFile) + + return CodeGeneratorResult( + generatedCode = generatedCode, + utilClassKind = UtilClassKind.fromCgContextOrNull(context), + testsGenerationReport = TestsGenerationReport() + ) + } + + private fun renderToString(testClassFile: CgClassFile): String { + logger.info { "Rendering phase started at ${now()}" } + val renderer = CgAbstractRenderer.makeRenderer(context) + testClassFile.accept(renderer) + logger.info { "Rendering phase finished at ${now()}" } + + return renderer.toString() } + private fun now() = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) + /** * Wrapper function that configures context as needed for utbot-online: * - turns on imports optimization in code generator 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 c1d61f29df..1664144230 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 @@ -26,7 +26,7 @@ import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider import org.utbot.framework.codegen.domain.builtin.UtilClassFileMethodProvider import org.utbot.framework.codegen.domain.builtin.UtilMethodProvider -import org.utbot.framework.codegen.domain.models.TestClassModel +import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.models.CgParameterKind import org.utbot.framework.codegen.services.access.Block import org.utbot.framework.codegen.tree.EnvironmentFieldStateCache @@ -295,7 +295,7 @@ interface CgContextOwner { * This method does almost all the same as [withTestClassScope], but for nested test classes. * The difference is that instead of working with [outerMostTestClassContext] it works with [currentTestClassContext]. */ - fun withNestedClassScope(testClassModel: TestClassModel, block: () -> R): R + fun withNestedClassScope(testClassModel: SimpleTestClassModel, block: () -> R): R /** * Set [mockFrameworkUsed] flag to true if the block is successfully executed @@ -434,7 +434,7 @@ interface CgContextOwner { */ data class CgContext( override val classUnderTest: ClassId, - override val isSpringClass: Boolean = false, + override val isSpringClass: Boolean = true, val generateUtilClassFile: Boolean = false, override var currentExecutable: ExecutableId? = null, override val collectedExceptions: MutableSet = mutableSetOf(), @@ -542,7 +542,7 @@ data class CgContext( } } - override fun withNestedClassScope(testClassModel: TestClassModel, block: () -> R): R { + override fun withNestedClassScope(testClassModel: SimpleTestClassModel, block: () -> R): R { val previousCurrentTestClassInfo = currentTestClassContext val previousCurrentTestClass = currentTestClass currentTestClass = createClassIdForNestedClass(testClassModel) @@ -555,7 +555,7 @@ data class CgContext( } } - private fun createClassIdForNestedClass(testClassModel: TestClassModel): ClassId { + private fun createClassIdForNestedClass(testClassModel: SimpleTestClassModel): ClassId { val simpleName = "${testClassModel.classUnderTest.simpleName}Test" return BuiltinClassId( canonicalName = currentTestClass.canonicalName + "." + simpleName, 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 c6fdeddee4..c3adea18e8 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 @@ -2,19 +2,34 @@ package org.utbot.framework.codegen.domain.models import org.utbot.framework.plugin.api.ClassId -// TODO: seems like this class needs to be renamed /** * 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 * in [TestClassModel] in one of [nestedClasses] + */ +abstract class TestClassModel( + val classUnderTest: ClassId, + val methodTestSets: List, + val nestedClasses: List, +) + +open class SimpleTestClassModel( + classUnderTest: ClassId, + methodTestSets: List, + nestedClasses: List = listOf(), +): TestClassModel(classUnderTest, methodTestSets, nestedClasses) + +/** + * Extended [SimpleTestClassModel] for Spring analysis reasons * * @param injectingMocksClass a class to inject other mocks into * @param mockedClasses variables of test class to represent mocked instances */ -class TestClassModel( - val classUnderTest: ClassId, - val methodTestSets: List, - val nestedClasses: List = listOf(), +class SpringTestClassModel( + classUnderTest: ClassId, + methodTestSets: List, + nestedClasses: List, val injectingMocksClass: ClassId? = null, val mockedClasses: Set = setOf(), -) \ No newline at end of file +): TestClassModel(classUnderTest, methodTestSets, nestedClasses) + diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt deleted file mode 100644 index 4e3688592f..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModelBuilder.kt +++ /dev/null @@ -1,151 +0,0 @@ -package org.utbot.framework.codegen.domain.models - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtArrayModel -import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtClassRefModel -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.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.util.enclosingClass - -class TestClassModelBuilder( - private val isSpringClass: Boolean -) { - fun createClassModel(classUnderTest: ClassId, testSets: List): TestClassModel { - // For each class stores list of methods declared in this class (methods from nested classes are excluded) - val class2methodTestSets = testSets.groupBy { it.executableId.classId } - - val classesWithMethodsUnderTest = testSets - .map { it.executableId.classId } - .distinct() - - // For each class stores list of its "direct" nested classes - val class2nestedClasses = mutableMapOf>() - - for (classId in classesWithMethodsUnderTest) { - var currentClass = classId - var enclosingClass = currentClass.enclosingClass - // while we haven't reached the top of nested class hierarchy or the main class under test - while (enclosingClass != null && currentClass != classUnderTest) { - class2nestedClasses.getOrPut(enclosingClass) { mutableSetOf() } += currentClass - currentClass = enclosingClass - enclosingClass = enclosingClass.enclosingClass - } - } - - val baseModel = constructRecursively(classUnderTest, class2methodTestSets, class2nestedClasses) - - return if (!isSpringClass) { - baseModel - } else { - val mockedClasses = collectMockedClassIds(classUnderTest, testSets) - - TestClassModel( - baseModel.classUnderTest, - baseModel.methodTestSets, - baseModel.nestedClasses, - classUnderTest, - mockedClasses, - ) - } - } - - private fun constructRecursively( - clazz: ClassId, - class2methodTestSets: Map>, - class2nestedClasses: Map> - ): TestClassModel { - val currentNestedClasses = class2nestedClasses.getOrDefault(clazz, listOf()) - val currentMethodTestSets = class2methodTestSets.getOrDefault(clazz, listOf()) - return TestClassModel( - clazz, - currentMethodTestSets, - currentNestedClasses.map { - constructRecursively(it, class2methodTestSets, class2nestedClasses) - } - ) - } - - private fun collectMockedClassIds( - classUnderTest: ClassId, - testSets: List, - ): Set { - val allModelsInExecution = mutableListOf() - - 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 - } - } - - val allConstructedModels = HashSet() - allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) } - - return allConstructedModels - .filter { it.isMockComposite() || it.isMockAssemble() } - .map { it.classId } - .filter { it != classUnderTest } - .toSet() - - } - - private fun collectRecursively(currentModel: UtModel, allModels: HashSet) { - if (currentModel in allModels) { - return - } - - allModels += currentModel - - when (currentModel) { - is UtNullModel, - is UtPrimitiveModel, - is UtClassRefModel, - is UtVoidModel, - is UtEnumConstantModel -> {} - is UtLambdaModel -> { - currentModel.capturedValues.forEach { collectRecursively(it, allModels) } - } - is UtArrayModel -> { - collectRecursively(currentModel.constModel, allModels) - currentModel.stores.values.forEach { collectRecursively(it, allModels) } - } - is UtCompositeModel -> { - currentModel.fields.values.forEach { collectRecursively(it, allModels) } - currentModel.mocks.values.flatten().forEach { collectRecursively(it, allModels) } - } - is UtAssembleModel -> { - if (currentModel.origin != null) { - collectRecursively(currentModel.origin!!, allModels) - } else { - currentModel.instantiationCall.instance?.let { collectRecursively(it, allModels) } - currentModel.instantiationCall.params.forEach { collectRecursively(it, allModels) } - - currentModel.modificationsChain.forEach { stmt -> - stmt.instance?.let { collectRecursively(it, allModels) } - when (stmt) { - is UtExecutableCallModel -> stmt.params.forEach { collectRecursively(it, allModels) } - is UtDirectSetFieldModel -> collectRecursively(stmt.fieldModel, allModels) - } - } - } - } - //Python, JavaScript, Go models are not required in Spring - else -> {} - } - } - - private fun UtModel.isMockComposite(): Boolean = this is UtCompositeModel && this.isMock - - private fun UtModel.isMockAssemble(): Boolean = - this is UtAssembleModel && this.origin?.let { it.isMock } == true -} \ No newline at end of file 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 new file mode 100644 index 0000000000..cefcc27249 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SimpleTestClassModelBuilder.kt @@ -0,0 +1,49 @@ +package org.utbot.framework.codegen.domain.models.builders + +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 { + // For each class stores list of methods declared in this class (methods from nested classes are excluded) + val class2methodTestSets = testSets.groupBy { it.executableId.classId } + + val classesWithMethodsUnderTest = testSets + .map { it.executableId.classId } + .distinct() + + // For each class stores list of its "direct" nested classes + val class2nestedClasses = mutableMapOf>() + + for (classId in classesWithMethodsUnderTest) { + var currentClass = classId + var enclosingClass = currentClass.enclosingClass + // while we haven't reached the top of nested class hierarchy or the main class under test + while (enclosingClass != null && currentClass != classUnderTest) { + class2nestedClasses.getOrPut(enclosingClass) { mutableSetOf() } += currentClass + currentClass = enclosingClass + enclosingClass = enclosingClass.enclosingClass + } + } + + return constructRecursively(classUnderTest, class2methodTestSets, class2nestedClasses) + } + + private fun constructRecursively( + clazz: ClassId, + class2methodTestSets: Map>, + class2nestedClasses: Map> + ): SimpleTestClassModel { + val currentNestedClasses = class2nestedClasses.getOrDefault(clazz, listOf()) + val currentMethodTestSets = class2methodTestSets.getOrDefault(clazz, listOf()) + return SimpleTestClassModel( + clazz, + currentMethodTestSets, + currentNestedClasses.map { + constructRecursively(it, class2methodTestSets, class2nestedClasses) + } + ) + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..fe7c0e820e --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt @@ -0,0 +1,112 @@ +package org.utbot.framework.codegen.domain.models.builders + +import org.utbot.framework.codegen.domain.models.CgMethodTestSet +import org.utbot.framework.codegen.domain.models.SpringTestClassModel +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtArrayModel +import org.utbot.framework.plugin.api.UtAssembleModel +import org.utbot.framework.plugin.api.UtClassRefModel +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 + +class SpringTestClassModelBuilder: TestClassModelBuilder() { + + override fun createTestClassModel(classUnderTest: ClassId, testSets: List): SpringTestClassModel { + val baseModel = SimpleTestClassModelBuilder().createTestClassModel(classUnderTest, testSets) + val mockedClasses = collectMockedClassIds(classUnderTest, testSets) + + return SpringTestClassModel( + baseModel.classUnderTest, + baseModel.methodTestSets, + baseModel.nestedClasses, + classUnderTest, + mockedClasses, + ) + } + + private fun collectMockedClassIds( + classUnderTest: ClassId, + testSets: List, + ): Set { + val allModelsInExecution = mutableListOf() + + 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 + + (execution.result as? UtExecutionSuccess)?.model?.let { allModelsInExecution += it } + } + } + + val allConstructedModels = mutableSetOf() + allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) } + + return allConstructedModels + .filter { it.isMockComposite() || it.isMockAssemble() } + .map { it.classId } + .filter { it != classUnderTest } + .toSet() + + } + + private fun collectRecursively(currentModel: UtModel, allModels: MutableSet) { + if (currentModel in allModels) { + return + } + + allModels += currentModel + + when (currentModel) { + is UtNullModel, + is UtPrimitiveModel, + is UtClassRefModel, + is UtVoidModel, + is UtEnumConstantModel -> {} + is UtLambdaModel -> { + currentModel.capturedValues.forEach { collectRecursively(it, allModels) } + } + is UtArrayModel -> { + currentModel.stores.values.forEach { collectRecursively(it, allModels) } + if (currentModel.stores.count() < currentModel.length) { + collectRecursively(currentModel.constModel, allModels) + } + } + is UtCompositeModel -> { + currentModel.fields.values.forEach { collectRecursively(it, allModels) } + currentModel.mocks.values.asSequence().flatten().forEach { collectRecursively(it, allModels) } + } + is UtAssembleModel -> { + currentModel.origin?.let { collectRecursively(it, allModels) } + + currentModel.instantiationCall.instance?.let { collectRecursively(it, allModels) } + currentModel.instantiationCall.params.forEach { collectRecursively(it, allModels) } + + currentModel.modificationsChain.forEach { stmt -> + stmt.instance?.let { collectRecursively(it, allModels) } + when (stmt) { + is UtExecutableCallModel -> stmt.params.forEach { collectRecursively(it, allModels) } + is UtDirectSetFieldModel -> collectRecursively(stmt.fieldModel, allModels) + } + } + } + //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/domain/models/builders/TestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/TestClassModelBuilder.kt new file mode 100644 index 0000000000..a1f47e873e --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/TestClassModelBuilder.kt @@ -0,0 +1,9 @@ +package org.utbot.framework.codegen.domain.models.builders + +import org.utbot.framework.codegen.domain.models.CgMethodTestSet +import org.utbot.framework.codegen.domain.models.TestClassModel +import org.utbot.framework.plugin.api.ClassId + +abstract class TestClassModelBuilder { + abstract fun createTestClassModel(classUnderTest: ClassId, testSets: List): TestClassModel +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt index 78711d867b..ecd92b05d0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt @@ -8,6 +8,7 @@ import org.utbot.framework.codegen.domain.TestNg import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgAuxiliaryClass +import org.utbot.framework.codegen.domain.models.CgClassBody import org.utbot.framework.codegen.domain.models.CgMethod import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.CgMethodsCluster @@ -20,6 +21,7 @@ import org.utbot.framework.codegen.domain.models.CgTestMethodCluster import org.utbot.framework.codegen.domain.models.CgTripleSlashMultilineComment import org.utbot.framework.codegen.domain.models.CgUtilEntity import org.utbot.framework.codegen.domain.models.CgUtilMethod +import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.models.TestClassModel import org.utbot.framework.codegen.renderer.importUtilMethodDependencies import org.utbot.framework.codegen.reports.TestsGenerationReport @@ -37,7 +39,7 @@ import org.utbot.fuzzer.UtFuzzedExecution /** * This test class constructor is used for pure Java/Kotlin applications. */ -open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstructorBase(context) { +open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstructorBase(context) { init { clearContextRelatedStorage() @@ -47,53 +49,59 @@ open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstruc val testsGenerationReport = TestsGenerationReport() - override fun constructTestClassBody(testClassModel: TestClassModel) = buildClassBody(currentTestClass) { - val notYetConstructedTestSets = testClassModel.methodTestSets.toMutableList() - - for (nestedClass in testClassModel.nestedClasses) { - // It is not possible to run tests for both outer and inner class in JUnit4 at once, - // so we locate all test methods in outer test class for JUnit4. - // see https://stackoverflow.com/questions/69770700/how-to-run-tests-from-outer-class-and-nested-inner-classes-simultaneously-in-jun - // or https://stackoverflow.com/questions/28230277/test-cases-in-inner-class-and-outer-class-with-junit4 - when (testFramework) { - Junit4 -> { - notYetConstructedTestSets += collectTestSetsFromInnerClasses(nestedClass) - } - Junit5, - TestNg -> { - nestedClassRegions += CgRealNestedClassesRegion( - "Tests for ${nestedClass.classUnderTest.simpleName}", - listOf(withNestedClassScope(nestedClass) { constructTestClass(nestedClass) }) - ) - } - } + override fun constructTestClassBody(testClassModel: SimpleTestClassModel): CgClassBody { + if (testClassModel !is SimpleTestClassModel) { + error("Test class model $testClassModel can't be constructed with ${this::class.simpleName}") } - for (testSet in notYetConstructedTestSets) { - updateCurrentExecutable(testSet.executableId) - val currentMethodUnderTestRegions = constructTestSet(testSet) ?: continue - val executableUnderTestCluster = CgMethodsCluster( - "Test suites for executable $currentExecutable", - currentMethodUnderTestRegions - ) - methodRegions += executableUnderTestCluster - } + return buildClassBody(currentTestClass) { + val notYetConstructedTestSets = testClassModel.methodTestSets.toMutableList() + + for (nestedClass in testClassModel.nestedClasses) { + // It is not possible to run tests for both outer and inner class in JUnit4 at once, + // so we locate all test methods in outer test class for JUnit4. + // see https://stackoverflow.com/questions/69770700/how-to-run-tests-from-outer-class-and-nested-inner-classes-simultaneously-in-jun + // or https://stackoverflow.com/questions/28230277/test-cases-in-inner-class-and-outer-class-with-junit4 + when (testFramework) { + Junit4 -> { + notYetConstructedTestSets += collectTestSetsFromInnerClasses(nestedClass) + } + Junit5, + TestNg -> { + nestedClassRegions += CgRealNestedClassesRegion( + "Tests for ${nestedClass.classUnderTest.simpleName}", + listOf(withNestedClassScope(nestedClass) { constructTestClass(nestedClass) }) + ) + } + } + } - val currentTestClassDataProviderMethods = currentTestClassContext.cgDataProviderMethods - if (currentTestClassDataProviderMethods.isNotEmpty()) { - staticDeclarationRegions += - CgStaticsRegion( - "Data provider methods for parametrized tests", - currentTestClassDataProviderMethods, + for (testSet in notYetConstructedTestSets) { + updateCurrentExecutable(testSet.executableId) + val currentMethodUnderTestRegions = constructTestSet(testSet) ?: continue + val executableUnderTestCluster = CgMethodsCluster( + "Test suites for executable $currentExecutable", + currentMethodUnderTestRegions ) - } + methodRegions += executableUnderTestCluster + } - if (currentTestClass == outerMostTestClass) { - val utilEntities = collectUtilEntities() - // If utilMethodProvider is TestClassUtilMethodProvider, then util entities should be declared - // in the test class. Otherwise, util entities will be located elsewhere (e.g. another class). - if (utilMethodProvider is TestClassUtilMethodProvider && utilEntities.isNotEmpty()) { - staticDeclarationRegions += CgStaticsRegion("Util methods", utilEntities) + val currentTestClassDataProviderMethods = currentTestClassContext.cgDataProviderMethods + if (currentTestClassDataProviderMethods.isNotEmpty()) { + staticDeclarationRegions += + CgStaticsRegion( + "Data provider methods for parametrized tests", + currentTestClassDataProviderMethods, + ) + } + + if (currentTestClass == outerMostTestClass) { + val utilEntities = collectUtilEntities() + // If utilMethodProvider is TestClassUtilMethodProvider, then util entities should be declared + // in the test class. Otherwise, util entities will be located elsewhere (e.g. another class). + if (utilMethodProvider is TestClassUtilMethodProvider && utilEntities.isNotEmpty()) { + staticDeclarationRegions += CgStaticsRegion("Util methods", utilEntities) + } } } } @@ -128,7 +136,7 @@ open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstruc return if (regions.any()) regions else null } - private fun collectTestSetsFromInnerClasses(model: TestClassModel): List { + private fun collectTestSetsFromInnerClasses(model: SimpleTestClassModel): List { val testSets = model.methodTestSets.toMutableList() for (nestedClass in model.nestedClasses) { testSets += collectTestSetsFromInnerClasses(nestedClass) 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 new file mode 100644 index 0000000000..b11b48bae8 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringTestClassConstructor.kt @@ -0,0 +1,15 @@ +package org.utbot.framework.codegen.tree + +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.CgClassBody +import org.utbot.framework.codegen.domain.models.SpringTestClassModel + +class CgSpringTestClassConstructor(context: CgContext): CgTestClassConstructorBase(context) { + + override val methodConstructor: CgMethodConstructor + get() = TODO("Not yet implemented") + + override fun constructTestClassBody(testClassModel: SpringTestClassModel): CgClassBody { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt index dcf5d24c7d..2e63e30762 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt @@ -5,11 +5,12 @@ import org.utbot.framework.codegen.domain.context.CgContextOwner import org.utbot.framework.codegen.domain.models.CgClass import org.utbot.framework.codegen.domain.models.CgClassBody import org.utbot.framework.codegen.domain.models.CgClassFile +import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.models.TestClassModel import org.utbot.framework.codegen.services.CgNameGenerator import org.utbot.framework.codegen.services.framework.TestFrameworkManager -abstract class CgTestClassConstructorBase(val context: CgContext): +abstract class CgTestClassConstructorBase(val context: CgContext): CgContextOwner by context, CgStatementConstructor by CgComponents.getStatementConstructorBy(context){ @@ -18,9 +19,9 @@ abstract class CgTestClassConstructorBase(val context: CgContext): protected open val testFrameworkManager: TestFrameworkManager = CgComponents.getTestFrameworkManagerBy(context) /** - * Constructs a file with the test class corresponding to [TestClassModel]. + * Constructs a file with the test class corresponding to [SimpleTestClassModel]. */ - open fun construct(testClassModel: TestClassModel): CgClassFile { + open fun construct(testClassModel: T): CgClassFile { return buildClassFile { this.declaredClass = withTestClassScope { constructTestClass(testClassModel) } imports += context.collectedImports @@ -28,9 +29,9 @@ abstract class CgTestClassConstructorBase(val context: CgContext): } /** - * Constructs [CgClass] corresponding to [TestClassModel]. + * Constructs [CgClass] corresponding to [SimpleTestClassModel]. */ - open fun constructTestClass(testClassModel: TestClassModel): CgClass { + open fun constructTestClass(testClassModel: T): CgClass { return buildClass { id = currentTestClass @@ -54,5 +55,5 @@ abstract class CgTestClassConstructorBase(val context: CgContext): } } - abstract fun constructTestClassBody(testClassModel: TestClassModel): CgClassBody + abstract fun constructTestClassBody(testClassModel: T): CgClassBody } \ No newline at end of file diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt index 60767d1cef..2e911830f6 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonCodeGenerator.kt @@ -12,7 +12,7 @@ import org.utbot.framework.codegen.domain.models.CgAssignment import org.utbot.framework.codegen.domain.models.CgLiteral import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.codegen.domain.models.CgVariable -import org.utbot.framework.codegen.domain.models.TestClassModel +import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.renderer.CgAbstractRenderer import org.utbot.framework.codegen.renderer.CgPrinterImpl import org.utbot.framework.codegen.renderer.CgRendererContext @@ -79,7 +79,7 @@ class PythonCodeGenerator( ): CodeGeneratorResult = withCustomContext(testClassCustomName) { context.withTestClassFileScope { (context.cgLanguageAssistant as PythonCgLanguageAssistant).clear() - val testClassModel = TestClassModel(classUnderTest, cgTestSets) + val testClassModel = SimpleTestClassModel(classUnderTest, cgTestSets) context.collectedImports.addAll(importModules) val astConstructor = PythonCgTestClassConstructor(context) diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgTestClassConstructor.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgTestClassConstructor.kt index 593f64613f..665b1c9f16 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgTestClassConstructor.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgTestClassConstructor.kt @@ -1,13 +1,13 @@ package org.utbot.python.framework.codegen.model.constructor.tree -import org.utbot.framework.codegen.domain.models.TestClassModel +import org.utbot.framework.codegen.domain.models.SimpleTestClassModel import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgClassFile import org.utbot.framework.codegen.tree.CgSimpleTestClassConstructor import org.utbot.framework.codegen.tree.buildClassFile internal class PythonCgTestClassConstructor(context: CgContext) : CgSimpleTestClassConstructor(context) { - override fun construct(testClassModel: TestClassModel): CgClassFile { + override fun construct(testClassModel: SimpleTestClassModel): CgClassFile { return buildClassFile { this.declaredClass = withTestClassScope { with(currentTestClassContext) { testClassSuperclass = testFramework.testSuperClass } From 82e864be06ff8030a3d3874a9b0f8a9dc2182a37 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 14 Feb 2023 18:30:58 +0300 Subject: [PATCH 4/5] Set default value for main --- .../org/utbot/framework/codegen/domain/context/CgContext.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1664144230..7a7ebc5309 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 @@ -434,7 +434,7 @@ interface CgContextOwner { */ data class CgContext( override val classUnderTest: ClassId, - override val isSpringClass: Boolean = true, + override val isSpringClass: Boolean = false, val generateUtilClassFile: Boolean = false, override var currentExecutable: ExecutableId? = null, override val collectedExceptions: MutableSet = mutableSetOf(), From 4599f1ba6c30d6b3fa6f1e80ec506a4f5cc152e6 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 14 Feb 2023 19:31:56 +0300 Subject: [PATCH 5/5] Little review fixes --- .../codegen/tree/CgSimpleTestClassConstructor.kt | 9 ++------- .../framework/codegen/tree/CgTestClassConstructorBase.kt | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt index ecd92b05d0..879a7a67dd 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt @@ -49,12 +49,8 @@ open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstruc val testsGenerationReport = TestsGenerationReport() - override fun constructTestClassBody(testClassModel: SimpleTestClassModel): CgClassBody { - if (testClassModel !is SimpleTestClassModel) { - error("Test class model $testClassModel can't be constructed with ${this::class.simpleName}") - } - - return buildClassBody(currentTestClass) { + override fun constructTestClassBody(testClassModel: SimpleTestClassModel): CgClassBody = + buildClassBody(currentTestClass) { val notYetConstructedTestSets = testClassModel.methodTestSets.toMutableList() for (nestedClass in testClassModel.nestedClasses) { @@ -104,7 +100,6 @@ open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstruc } } } - } private fun constructTestSet(testSet: CgMethodTestSet): List>? { val regions = mutableListOf>() diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt index 2e63e30762..eecac53277 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgTestClassConstructorBase.kt @@ -19,7 +19,7 @@ abstract class CgTestClassConstructorBase(val context: CgCon protected open val testFrameworkManager: TestFrameworkManager = CgComponents.getTestFrameworkManagerBy(context) /** - * Constructs a file with the test class corresponding to [SimpleTestClassModel]. + * Constructs a file with the test class corresponding to [TestClassModel]. */ open fun construct(testClassModel: T): CgClassFile { return buildClassFile { @@ -29,7 +29,7 @@ abstract class CgTestClassConstructorBase(val context: CgCon } /** - * Constructs [CgClass] corresponding to [SimpleTestClassModel]. + * Constructs [CgClass] corresponding to [TestClassModel]. */ open fun constructTestClass(testClassModel: T): CgClass { return buildClass {