Skip to content

Commit 6f70c52

Browse files
sofurihafeEgorkaKulikov
authored andcommitted
Add support for class fields rendering with annotations
1 parent bfc2de9 commit 6f70c52

16 files changed

Lines changed: 246 additions & 65 deletions

File tree

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/MockitoBuiltins.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ internal val mockitoClassId = BuiltinClassId(
2020
simpleName = "Mockito",
2121
)
2222

23+
internal val mockClassId = BuiltinClassId(
24+
canonicalName = "org.mockito.Mock",
25+
simpleName = "Mock",
26+
)
27+
28+
internal val injectMocksClassId = BuiltinClassId(
29+
canonicalName = "org.mockito.InjectMocks",
30+
simpleName = "InjectMocks",
31+
)
32+
2333
internal val ongoingStubbingClassId = BuiltinClassId(
2434
canonicalName = "org.mockito.stubbing.OngoingStubbing",
2535
simpleName = "OngoingStubbing",

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.utbot.framework.codegen.renderer.CgRendererContext
77
import org.utbot.framework.codegen.renderer.CgVisitor
88
import org.utbot.framework.codegen.renderer.auxiliaryClassTextById
99
import org.utbot.framework.codegen.renderer.utilMethodTextById
10+
import org.utbot.framework.codegen.tree.VisibilityModifier
1011
import org.utbot.framework.plugin.api.BuiltinClassId
1112
import org.utbot.framework.plugin.api.ClassId
1213
import org.utbot.framework.plugin.api.ConstructorId
@@ -82,6 +83,7 @@ interface CgElement {
8283
is CgBreakStatement -> visit(element)
8384
is CgContinueStatement -> visit(element)
8485
is CgDeclaration -> visit(element)
86+
is CgFieldDeclaration -> visit(element)
8587
is CgAssignment -> visit(element)
8688
is CgTypeCast -> visit(element)
8789
is CgIsInstance -> visit(element)
@@ -134,6 +136,7 @@ class CgClass(
134136
val body: CgClassBody,
135137
val isStatic: Boolean,
136138
val isNested: Boolean,
139+
val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
137140
): CgElement {
138141
val packageName
139142
get() = id.packageName
@@ -156,8 +159,21 @@ class CgClassBody(
156159
val methodRegions: List<CgMethodsCluster>,
157160
val staticDeclarationRegions: List<CgStaticsRegion>,
158161
val nestedClassRegions: List<CgNestedClassesRegion<*>>,
159-
//TODO: use [CgFieldDeclaration] after PR-1788 merge
160-
val fields: List<CgDeclaration> = emptyList(),
162+
val fields: Set<CgFieldDeclaration> = emptySet(),
163+
) : CgElement
164+
165+
/**
166+
* Field of a class.
167+
* @property ownerClassId [ClassId] of the field owner class.
168+
* @property declaration declaration itself.
169+
* @property annotation optional annotation.
170+
* @property visibility field visibility.
171+
*/
172+
class CgFieldDeclaration(
173+
val ownerClassId: ClassId,
174+
val declaration: CgDeclaration,
175+
val annotation: CgAnnotation? = null,
176+
val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
161177
) : CgElement
162178

163179
/**
@@ -272,6 +288,7 @@ sealed class CgMethod(open val isStatic: Boolean) : CgElement {
272288
abstract val annotations: List<CgAnnotation>
273289
abstract val documentation: CgDocumentationComment
274290
abstract val requiredFields: List<CgParameterDeclaration>
291+
abstract val visibility: VisibilityModifier
275292
}
276293

277294
class CgTestMethod(
@@ -281,6 +298,7 @@ class CgTestMethod(
281298
override val statements: List<CgStatement>,
282299
override val exceptions: Set<ClassId>,
283300
override val annotations: List<CgAnnotation>,
301+
override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
284302
val type: CgTestMethodType,
285303
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()),
286304
override val requiredFields: List<CgParameterDeclaration> = emptyList(),
@@ -291,6 +309,7 @@ class CgFrameworkUtilMethod(
291309
override val statements: List<CgStatement>,
292310
override val exceptions: Set<ClassId>,
293311
override val annotations: List<CgAnnotation>,
312+
override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
294313
) : CgMethod(isStatic = false) {
295314
override val returnType: ClassId = voidClassId
296315
override val parameters: List<CgParameterDeclaration> = emptyList()
@@ -301,7 +320,8 @@ class CgFrameworkUtilMethod(
301320
class CgErrorTestMethod(
302321
override val name: String,
303322
override val statements: List<CgStatement>,
304-
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
323+
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList()),
324+
override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
305325
) : CgMethod(isStatic = false) {
306326
override val exceptions: Set<ClassId> = emptySet()
307327
override val returnType: ClassId = voidClassId
@@ -316,6 +336,7 @@ class CgParameterizedTestDataProviderMethod(
316336
override val returnType: ClassId,
317337
override val annotations: List<CgAnnotation>,
318338
override val exceptions: Set<ClassId>,
339+
override val visibility: VisibilityModifier = VisibilityModifier.PUBLIC,
319340
) : CgMethod(isStatic = true) {
320341
override val parameters: List<CgParameterDeclaration> = emptyList()
321342
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.framework.codegen.domain.models
22

33
import org.utbot.framework.plugin.api.ClassId
4+
import org.utbot.framework.plugin.api.UtModel
45

56
/**
67
* Stores method test sets in a structure that replicates structure of their methods in [classUnderTest].
@@ -13,7 +14,7 @@ abstract class TestClassModel(
1314
val nestedClasses: List<SimpleTestClassModel>,
1415
)
1516

16-
open class SimpleTestClassModel(
17+
class SimpleTestClassModel(
1718
classUnderTest: ClassId,
1819
methodTestSets: List<CgMethodTestSet>,
1920
nestedClasses: List<SimpleTestClassModel> = listOf(),
@@ -29,7 +30,7 @@ class SpringTestClassModel(
2930
classUnderTest: ClassId,
3031
methodTestSets: List<CgMethodTestSet>,
3132
nestedClasses: List<SimpleTestClassModel>,
32-
val injectingMocksClass: ClassId? = null,
33-
val mockedClasses: Set<ClassId> = setOf(),
33+
val injectedMockModels: Map<ClassId, Set<UtModel>> = mapOf(),
34+
val mockedModels: Map<ClassId, Set<UtModel>> = mapOf(),
3435
): TestClassModel(classUnderTest, methodTestSets, nestedClasses)
3536

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,40 @@ import org.utbot.framework.plugin.api.UtModel
1616
import org.utbot.framework.plugin.api.UtNullModel
1717
import org.utbot.framework.plugin.api.UtPrimitiveModel
1818
import org.utbot.framework.plugin.api.UtVoidModel
19+
import org.utbot.framework.plugin.api.isMockModel
1920

2021
class SpringTestClassModelBuilder: TestClassModelBuilder() {
2122

2223
override fun createTestClassModel(classUnderTest: ClassId, testSets: List<CgMethodTestSet>): SpringTestClassModel {
2324
val baseModel = SimpleTestClassModelBuilder().createTestClassModel(classUnderTest, testSets)
24-
val mockedClasses = collectMockedClassIds(classUnderTest, testSets)
25+
val (injectedModels, mockedModels) = collectInjectedAndMockedModels(testSets)
2526

2627
return SpringTestClassModel(
2728
baseModel.classUnderTest,
2829
baseModel.methodTestSets,
2930
baseModel.nestedClasses,
30-
classUnderTest,
31-
mockedClasses,
31+
injectedModels,
32+
mockedModels,
3233
)
3334
}
3435

35-
private fun collectMockedClassIds(
36-
classUnderTest: ClassId,
36+
private fun collectInjectedAndMockedModels(
3737
testSets: List<CgMethodTestSet>,
38-
): Set<ClassId> {
38+
): Pair<Map<ClassId, Set<UtModel>>, Map<ClassId, Set<UtModel>>> {
39+
val thisInstances = mutableSetOf<UtModel>()
3940
val allModelsInExecution = mutableListOf<UtModel>()
4041

4142
for (testSet in testSets) {
4243
for (execution in testSet.executions) {
43-
execution.stateBefore.thisInstance?.let { allModelsInExecution += it }
44-
execution.stateAfter.thisInstance?.let { allModelsInExecution += it }
44+
execution.stateBefore.thisInstance?.let {
45+
allModelsInExecution += it
46+
thisInstances += it
47+
}
48+
49+
execution.stateAfter.thisInstance?.let {
50+
allModelsInExecution += it
51+
thisInstances += it
52+
}
4553

4654
allModelsInExecution += execution.stateBefore.parameters
4755
allModelsInExecution += execution.stateAfter.parameters
@@ -53,21 +61,22 @@ class SpringTestClassModelBuilder: TestClassModelBuilder() {
5361
val allConstructedModels = mutableSetOf<UtModel>()
5462
allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) }
5563

56-
return allConstructedModels
57-
.filter { it.isMockComposite() || it.isMockAssemble() }
58-
.map { it.classId }
59-
.filter { it != classUnderTest }
60-
.toSet()
64+
val mockedModels =
65+
allConstructedModels
66+
.filterTo(mutableSetOf()) { it.isMockModel() && it !in thisInstances }
67+
68+
return thisInstances.groupByClassId() to mockedModels.groupByClassId()
69+
}
6170

71+
private fun Set<UtModel>.groupByClassId(): Map<ClassId, Set<UtModel>> {
72+
return this.groupBy { it.classId }.mapValues { it.value.toSet() }
6273
}
6374

6475
private fun collectRecursively(currentModel: UtModel, allModels: MutableSet<UtModel>) {
65-
if (currentModel in allModels) {
76+
if (!allModels.add(currentModel)) {
6677
return
6778
}
6879

69-
allModels += currentModel
70-
7180
when (currentModel) {
7281
is UtNullModel,
7382
is UtPrimitiveModel,
@@ -104,9 +113,4 @@ class SpringTestClassModelBuilder: TestClassModelBuilder() {
104113
//Python, JavaScript, Go models are not required in Spring
105114
}
106115
}
107-
108-
private fun UtModel.isMockComposite(): Boolean = this is UtCompositeModel && this.isMock
109-
110-
//TODO: Having an assemble model often means that we do not use its origin, so is this composite mock redundant?
111-
private fun UtModel.isMockAssemble(): Boolean = this is UtAssembleModel && this.origin?.isMock == true
112116
}

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgAbstractRenderer.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.utbot.framework.codegen.domain.models.CgExecutableCall
4141
import org.utbot.framework.codegen.domain.models.CgMethodsCluster
4242
import org.utbot.framework.codegen.domain.models.CgExpression
4343
import org.utbot.framework.codegen.domain.models.CgFieldAccess
44+
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
4445
import org.utbot.framework.codegen.domain.models.CgForEachLoop
4546
import org.utbot.framework.codegen.domain.models.CgForLoop
4647
import org.utbot.framework.codegen.domain.models.CgFrameworkUtilMethod
@@ -83,6 +84,7 @@ import org.utbot.framework.codegen.domain.models.CgTryCatch
8384
import org.utbot.framework.codegen.domain.models.CgUtilMethod
8485
import org.utbot.framework.codegen.domain.models.CgVariable
8586
import org.utbot.framework.codegen.domain.models.CgWhileLoop
87+
import org.utbot.framework.codegen.tree.VisibilityModifier
8688
import org.utbot.framework.codegen.tree.ututils.UtilClassKind
8789
import org.utbot.framework.plugin.api.ClassId
8890
import org.utbot.framework.plugin.api.CodegenLanguage
@@ -574,6 +576,14 @@ abstract class CgAbstractRenderer(
574576
println(statementEnding)
575577
}
576578

579+
// Class field declaration
580+
581+
override fun visit(element: CgFieldDeclaration) {
582+
element.annotation?.accept(this)
583+
renderVisibility(element.visibility)
584+
element.declaration.accept(this)
585+
}
586+
577587
// Variable assignment
578588

579589
override fun visit(element: CgAssignment) {
@@ -891,7 +901,7 @@ abstract class CgAbstractRenderer(
891901
}
892902
}
893903

894-
protected abstract fun renderClassVisibility(classId: ClassId)
904+
protected abstract fun renderVisibility(modifier: VisibilityModifier)
895905

896906
protected abstract fun renderClassModality(aClass: CgClass)
897907

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/renderer/CgJavaRenderer.kt

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@ import org.utbot.framework.codegen.domain.models.CgLiteral
3838
import org.utbot.framework.codegen.domain.models.CgTestMethod
3939
import org.utbot.framework.codegen.domain.models.CgTypeCast
4040
import org.utbot.framework.codegen.domain.models.CgVariable
41+
import org.utbot.framework.codegen.tree.VisibilityModifier
4142
import org.utbot.framework.codegen.util.nullLiteral
4243
import org.utbot.framework.plugin.api.ClassId
4344
import org.utbot.framework.plugin.api.TypeParameters
4445
import org.utbot.framework.plugin.api.util.isFinal
45-
import org.utbot.framework.plugin.api.util.isPrivate
46-
import org.utbot.framework.plugin.api.util.isProtected
47-
import org.utbot.framework.plugin.api.util.isPublic
4846
import org.utbot.framework.plugin.api.util.wrapperByPrimitive
4947

5048
internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = CgPrinterImpl()) :
@@ -70,7 +68,7 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
7068
annotation.accept(this)
7169
}
7270

73-
renderClassVisibility(element.id)
71+
renderVisibility(element.visibility)
7472
renderClassModality(element)
7573
if (element.isStatic) {
7674
print("static ")
@@ -92,6 +90,12 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
9290
}
9391

9492
override fun visit(element: CgClassBody) {
93+
// render class fields
94+
for (field in element.fields) {
95+
field.accept(this)
96+
println()
97+
}
98+
9599
// render regions for test methods and utils
96100
val allRegions = element.methodRegions + element.nestedClassRegions + element.staticDeclarationRegions
97101
for ((i, region) in allRegions.withIndex()) {
@@ -230,8 +234,9 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
230234
}
231235

232236
override fun renderMethodSignature(element: CgTestMethod) {
237+
renderVisibility(element.visibility)
233238
// test methods always have void return type
234-
print("public void ")
239+
print("void ")
235240
print(element.name)
236241

237242
print("(")
@@ -243,21 +248,25 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
243248
}
244249

245250
override fun renderMethodSignature(element: CgErrorTestMethod) {
251+
renderVisibility(element.visibility)
246252
// error test methods always have void return type
247-
println("public void ${element.name}()")
253+
println("void ${element.name}()")
248254
}
249255

250256
override fun renderMethodSignature(element: CgParameterizedTestDataProviderMethod) {
251257
//we do not have a good string representation for two-dimensional array, so this strange if-else is required
252258
val returnType =
253259
if (element.returnType.simpleName == "Object[][]") "java.lang.Object[][]" else "${element.returnType}"
254-
print("public static $returnType ${element.name}()")
260+
261+
renderVisibility(element.visibility)
262+
print("static $returnType ${element.name}()")
255263
renderExceptions(element)
256264
}
257265

258266
override fun renderMethodSignature(element: CgFrameworkUtilMethod) {
267+
renderVisibility(element.visibility)
259268
// framework util methods always have void return type
260-
print("public void ")
269+
print("void ")
261270
print(element.name)
262271
print("()")
263272

@@ -388,11 +397,14 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
388397

389398
override fun escapeNamePossibleKeywordImpl(s: String): String = s
390399

391-
override fun renderClassVisibility(classId: ClassId) {
392-
when {
393-
classId.isPublic -> print("public ")
394-
classId.isProtected -> print("protected ")
395-
classId.isPrivate -> print("private ")
400+
override fun renderVisibility(modifier: VisibilityModifier) {
401+
when (modifier) {
402+
VisibilityModifier.PUBLIC -> print("public ")
403+
VisibilityModifier.PRIVATE -> print("private ")
404+
VisibilityModifier.PROTECTED -> print("protected ")
405+
VisibilityModifier.INTERNAL -> print("internal ")
406+
VisibilityModifier.PACKAGEPRIVATE -> Unit
407+
else -> error("Java: unexpected visibility modifier -- $modifier")
396408
}
397409
}
398410

0 commit comments

Comments
 (0)