Skip to content

Commit 1d0680a

Browse files
committed
Add support for rendering class fields with annotations
1 parent c4c26f3 commit 1d0680a

File tree

11 files changed

+131
-10
lines changed

11 files changed

+131
-10
lines changed

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

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,14 @@ abstract class TestFramework(
191191
abstract val nestedClassesShouldBeStatic: Boolean
192192
abstract val argListClassId: ClassId
193193

194+
abstract val beforeEachAnnotation: String
195+
abstract val beforeEachAnnotationId: ClassId
196+
abstract val beforeEachAnnotationFqn: String
197+
198+
abstract val afterEachAnnotation: String
199+
abstract val afterEachAnnotationId: ClassId
200+
abstract val afterEachAnnotationFqn: String
201+
194202
open val testSuperClass: ClassId? = null
195203

196204
open val assertEquals by lazy { assertionId("assertEquals", objectClassId, objectClassId) }
@@ -269,6 +277,11 @@ object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
269277
override val methodSourceAnnotation: String = "@$mainPackage.DataProvider"
270278
override val methodSourceAnnotationFqn: String = "@$mainPackage.DataProvider"
271279

280+
override val beforeEachAnnotation: String = "@$mainPackage.BeforeMethod"
281+
override val beforeEachAnnotationFqn: String = "$mainPackage.BeforeMethod"
282+
override val afterEachAnnotation: String = "@$mainPackage.AfterMethod"
283+
override val afterEachAnnotationFqn: String = "$mainPackage.AfterMethod"
284+
272285
internal const val testXmlName: String = "testng.xml"
273286

274287
override val assertionsClass: ClassId = BuiltinClassId(
@@ -321,6 +334,18 @@ object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
321334
override val argListClassId: ClassId
322335
get() = Array<Array<Any?>?>::class.id
323336

337+
override val beforeEachAnnotationId: ClassId =
338+
BuiltinClassId(
339+
canonicalName = "$mainPackage.annotations.BeforeMethod",
340+
simpleName = "BeforeMethod"
341+
)
342+
343+
override val afterEachAnnotationId: ClassId =
344+
BuiltinClassId(
345+
canonicalName = "$mainPackage.annotations.AfterMethod",
346+
simpleName = "AfterMethod"
347+
)
348+
324349
@OptIn(ExperimentalStdlibApi::class)
325350
override fun getRunTestsCommand(
326351
executionInvoke: String,
@@ -382,6 +407,12 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
382407
override val methodSourceAnnotationFqn
383408
get() = parametrizedTestsNotSupportedError
384409

410+
override val beforeEachAnnotation: String = "@$mainPackage.Before"
411+
override val beforeEachAnnotationFqn: String = "$mainPackage.Before"
412+
413+
override val afterEachAnnotation: String = "@$mainPackage.After"
414+
override val afterEachAnnotationFqn: String = "$mainPackage.After"
415+
385416
override val testAnnotationId = BuiltinClassId(
386417
canonicalName = "$JUNIT4_PACKAGE.Test",
387418
simpleName = "Test"
@@ -414,6 +445,19 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
414445
override val argListClassId: ClassId
415446
get() = parametrizedTestsNotSupportedError
416447

448+
override val beforeEachAnnotationId: ClassId =
449+
BuiltinClassId(
450+
canonicalName = "$JUNIT4_PACKAGE.Before",
451+
simpleName = "Before"
452+
)
453+
454+
override val afterEachAnnotationId: ClassId =
455+
BuiltinClassId(
456+
canonicalName = "$JUNIT4_PACKAGE.After",
457+
simpleName = "After"
458+
)
459+
460+
417461
@OptIn(ExperimentalStdlibApi::class)
418462
override fun getRunTestsCommand(
419463
executionInvoke: String,
@@ -431,12 +475,16 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
431475

432476
object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit 5") {
433477
override val mainPackage: String = JUNIT5_PACKAGE
434-
override val testAnnotation = "@$mainPackage.Test"
478+
override val testAnnotation: String = "@$mainPackage.Test"
435479
override val testAnnotationFqn: String = "$mainPackage.Test"
436-
override val parameterizedTestAnnotation = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest"
480+
override val parameterizedTestAnnotation: String = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest"
437481
override val parameterizedTestAnnotationFqn: String = "$JUNIT5_PARAMETERIZED_PACKAGE.ParameterizedTest"
438482
override val methodSourceAnnotation: String = "$JUNIT5_PARAMETERIZED_PACKAGE.provider.MethodSource"
439483
override val methodSourceAnnotationFqn: String = "$JUNIT5_PARAMETERIZED_PACKAGE.provider.MethodSource"
484+
override val beforeEachAnnotation: String = "@$mainPackage.BeforeEach"
485+
override val beforeEachAnnotationFqn: String = "$mainPackage.BeforeEach"
486+
override val afterEachAnnotation: String = "@$mainPackage.AfterEach"
487+
override val afterEachAnnotationFqn: String = "$mainPackage.AfterEach"
440488

441489
val executableClassId = BuiltinClassId(
442490
canonicalName = "$JUNIT5_PACKAGE.function.Executable",
@@ -543,6 +591,18 @@ object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit 5") {
543591
)
544592
}
545593

594+
override val beforeEachAnnotationId: ClassId =
595+
BuiltinClassId(
596+
canonicalName = "$JUNIT5_PACKAGE.BeforeEach",
597+
simpleName = "BeforeEach"
598+
)
599+
600+
override val afterEachAnnotationId: ClassId =
601+
BuiltinClassId(
602+
canonicalName = "$JUNIT5_PACKAGE.AfterEach",
603+
simpleName = "AfterEach"
604+
)
605+
546606
private const val junitVersion = "1.9.0" // TODO read it from gradle.properties
547607
private const val platformJarName: String = "junit-platform-console-standalone-$junitVersion.jar"
548608

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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ interface CgElement {
8181
is CgBreakStatement -> visit(element)
8282
is CgContinueStatement -> visit(element)
8383
is CgDeclaration -> visit(element)
84+
is CgFieldDeclaration -> visit(element)
8485
is CgAssignment -> visit(element)
8586
is CgTypeCast -> visit(element)
8687
is CgIsInstance -> visit(element)
@@ -152,11 +153,17 @@ class CgClass(
152153
*/
153154
class CgClassBody(
154155
val classId: ClassId,
156+
val fields: List<CgElement>,
155157
val methodRegions: List<CgMethodsCluster>,
156158
val staticDeclarationRegions: List<CgStaticsRegion>,
157159
val nestedClassRegions: List<CgNestedClassesRegion<*>>
158160
) : CgElement
159161

162+
class CgFieldDeclaration(
163+
val annotation: CgAnnotation,
164+
val declaration: CgDeclaration
165+
) : CgElement
166+
160167
/**
161168
* A class representing the IntelliJ IDEA's regions.
162169
* A region is a part of code between the special starting and ending comments.

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import org.utbot.framework.codegen.domain.models.CgStatementExecutableCall
7373
import org.utbot.framework.codegen.domain.models.CgStaticFieldAccess
7474
import org.utbot.framework.codegen.domain.models.CgStaticRunnable
7575
import org.utbot.framework.codegen.domain.models.CgStaticsRegion
76+
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
7677
import org.utbot.framework.codegen.domain.models.CgTestMethod
7778
import org.utbot.framework.codegen.domain.models.CgTestMethodCluster
7879
import org.utbot.framework.codegen.domain.models.CgThisInstance
@@ -562,6 +563,14 @@ abstract class CgAbstractRenderer(
562563
println(statementEnding)
563564
}
564565

566+
// Class field declaration
567+
568+
override fun visit(element: CgFieldDeclaration) {
569+
element.annotation.accept(this)
570+
renderVisibility(element.declaration.variableType)
571+
element.declaration.accept(this)
572+
}
573+
565574
// Variable assignment
566575

567576
override fun visit(element: CgAssignment) {
@@ -878,7 +887,7 @@ abstract class CgAbstractRenderer(
878887
}
879888
}
880889

881-
protected abstract fun renderClassVisibility(classId: ClassId)
890+
protected abstract fun renderVisibility(classId: ClassId)
882891

883892
protected abstract fun renderClassModality(aClass: CgClass)
884893

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
6969
annotation.accept(this)
7070
}
7171

72-
renderClassVisibility(element.id)
72+
renderVisibility(element.id)
7373
renderClassModality(element)
7474
if (element.isStatic) {
7575
print("static ")
@@ -91,6 +91,11 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
9191
}
9292

9393
override fun visit(element: CgClassBody) {
94+
// render test class fields, e.g. Spring stuff
95+
for (region in element.fields) {
96+
region.accept(this)
97+
}
98+
9499
// render regions for test methods and utils
95100
val allRegions = element.methodRegions + element.nestedClassRegions + element.staticDeclarationRegions
96101
for ((i, region) in allRegions.withIndex()) {
@@ -376,7 +381,7 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C
376381

377382
override fun escapeNamePossibleKeywordImpl(s: String): String = s
378383

379-
override fun renderClassVisibility(classId: ClassId) {
384+
override fun renderVisibility(classId: ClassId) {
380385
when {
381386
classId.isPublic -> print("public ")
382387
classId.isProtected -> print("protected ")

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import org.utbot.framework.codegen.domain.models.CgFormattedString
4242
import org.utbot.framework.codegen.domain.models.CgLiteral
4343
import org.utbot.framework.codegen.domain.models.CgTestMethod
4444
import org.utbot.framework.codegen.domain.models.CgTypeCast
45-
import org.utbot.framework.codegen.domain.models.CgValue
4645
import org.utbot.framework.codegen.domain.models.CgVariable
4746
import org.utbot.framework.codegen.util.nullLiteral
4847
import org.utbot.framework.plugin.api.BuiltinClassId
@@ -84,7 +83,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter =
8483
annotation.accept(this)
8584
}
8685

87-
renderClassVisibility(element.id)
86+
renderVisibility(element.id)
8887
renderClassModality(element)
8988
if (!element.isStatic && element.isNested) {
9089
print("inner ")
@@ -571,7 +570,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter =
571570
override fun escapeNamePossibleKeywordImpl(s: String): String =
572571
if (isLanguageKeyword(s, context.cgLanguageAssistant)) "`$s`" else s
573572

574-
override fun renderClassVisibility(classId: ClassId) {
573+
override fun renderVisibility(classId: ClassId) {
575574
when {
576575
// Kotlin classes are public by default
577576
classId.isPublic -> Unit

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import org.utbot.framework.codegen.domain.models.CgClassBody
7878
import org.utbot.framework.codegen.domain.models.CgDocRegularLineStmt
7979
import org.utbot.framework.codegen.domain.models.CgFormattedString
8080
import org.utbot.framework.codegen.domain.models.CgNestedClassesRegion
81+
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
8182
import org.utbot.framework.codegen.domain.models.CgTestMethod
8283
import org.utbot.framework.codegen.domain.models.CgTestMethodCluster
8384
import org.utbot.framework.codegen.domain.models.CgThisInstance
@@ -183,6 +184,9 @@ interface CgVisitor<R> {
183184
// Variable declaration
184185
fun visit(element: CgDeclaration): R
185186

187+
// Field declaration
188+
fun visit(element: CgFieldDeclaration): R
189+
186190
// Variable assignment
187191
fun visit(element: CgAssignment): R
188192

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/Builders.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.utbot.framework.codegen.domain.models.CgElement
1313
import org.utbot.framework.codegen.domain.models.CgErrorTestMethod
1414
import org.utbot.framework.codegen.domain.models.CgExceptionHandler
1515
import org.utbot.framework.codegen.domain.models.CgExpression
16+
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
1617
import org.utbot.framework.codegen.domain.models.CgForEachLoop
1718
import org.utbot.framework.codegen.domain.models.CgForLoop
1819
import org.utbot.framework.codegen.domain.models.CgLoop
@@ -63,11 +64,12 @@ class CgClassBuilder : CgBuilder<CgClass> {
6364
fun buildClass(init: CgClassBuilder.() -> Unit) = CgClassBuilder().apply(init).build()
6465

6566
class CgClassBodyBuilder(val classId: ClassId) : CgBuilder<CgClassBody> {
67+
val fields: MutableList<CgFieldDeclaration> = mutableListOf()
6668
val methodRegions: MutableList<CgMethodsCluster> = mutableListOf()
6769
val staticDeclarationRegions: MutableList<CgStaticsRegion> = mutableListOf()
6870
val nestedClassRegions: MutableList<CgNestedClassesRegion<*>> = mutableListOf()
6971

70-
override fun build() = CgClassBody(classId, methodRegions, staticDeclarationRegions, nestedClassRegions)
72+
override fun build() = CgClassBody(classId, fields, methodRegions, staticDeclarationRegions, nestedClassRegions)
7173
}
7274

7375
fun buildClassBody(classId: ClassId, init: CgClassBodyBuilder.() -> Unit) = CgClassBodyBuilder(classId).apply(init).build()

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSimpleTestClassConstructor.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package org.utbot.framework.codegen.tree
22

3+
import com.jetbrains.rd.util.firstOrNull
34
import org.utbot.framework.UtSettings
45
import org.utbot.framework.codegen.domain.Junit4
56
import org.utbot.framework.codegen.domain.Junit5
67
import org.utbot.framework.codegen.domain.ParametrizedTestSource
78
import org.utbot.framework.codegen.domain.TestNg
89
import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider
10+
import org.utbot.framework.codegen.domain.builtin.mockClassId
911
import org.utbot.framework.codegen.domain.context.CgContext
1012
import org.utbot.framework.codegen.domain.models.CgAuxiliaryClass
1113
import org.utbot.framework.codegen.domain.models.CgClassBody
14+
import org.utbot.framework.codegen.domain.models.CgDeclaration
15+
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
1216
import org.utbot.framework.codegen.domain.models.CgMethod
1317
import org.utbot.framework.codegen.domain.models.CgMethodTestSet
1418
import org.utbot.framework.codegen.domain.models.CgMethodsCluster
@@ -29,6 +33,7 @@ import org.utbot.framework.codegen.tree.CgComponents.clearContextRelatedStorage
2933
import org.utbot.framework.codegen.tree.CgComponents.getMethodConstructorBy
3034
import org.utbot.framework.plugin.api.ClassId
3135
import org.utbot.framework.plugin.api.MethodId
36+
import org.utbot.framework.plugin.api.UtCompositeModel
3237
import org.utbot.framework.plugin.api.UtExecutionSuccess
3338
import org.utbot.framework.plugin.api.UtMethodTestSet
3439
import org.utbot.framework.plugin.api.UtSymbolicExecution
@@ -72,6 +77,20 @@ open class CgSimpleTestClassConstructor(context: CgContext): CgTestClassConstruc
7277
}
7378
}
7479

80+
// Don't forget to delete these lines and some imports
81+
// BEGIN
82+
// A sample field collection. Use max method from IntExamplesTest
83+
val tmpFields = (notYetConstructedTestSets[0].executions[0].stateAfter.thisInstance as UtCompositeModel).fields.firstOrNull()
84+
val annotation = CgComponents
85+
.getStatementConstructorBy(context)
86+
.annotation(mockClassId)
87+
val declaration = CgDeclaration(tmpFields!!.value.classId, tmpFields.key.name, null)
88+
89+
// This is the way
90+
// It may be a separate REGION containing fields for each test method, not just a list of Cg little things...
91+
fields += CgFieldDeclaration(annotation, declaration)
92+
// END
93+
7594
for (testSet in notYetConstructedTestSets) {
7695
updateCurrentExecutable(testSet.executableId)
7796
val currentMethodUnderTestRegions = constructTestSet(testSet) ?: continue

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ internal class CgPythonRenderer(
415415
}
416416

417417
override fun escapeNamePossibleKeywordImpl(s: String): String = s
418-
override fun renderClassVisibility(classId: ClassId) {
418+
override fun renderVisibility(classId: ClassId) {
419419
throw UnsupportedOperationException()
420420
}
421421

utbot-sample/src/main/java/org/utbot/examples/primitives/IntExamples.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
import java.util.List;
55

66
public class IntExamples {
7+
// Don't forget to delete these lines
8+
// BEGIN
9+
public Object kekField1;
10+
public Object kekField2 = 1;
11+
// END
12+
713
public static boolean isInteger(String value) {
814
try {
915
return (Integer.valueOf(value) != null);

0 commit comments

Comments
 (0)