1+ package org.utbot.framework.codegen.domain.models
2+
3+ import org.utbot.framework.plugin.api.ClassId
4+ import org.utbot.framework.plugin.api.UtArrayModel
5+ import org.utbot.framework.plugin.api.UtAssembleModel
6+ import org.utbot.framework.plugin.api.UtClassRefModel
7+ import org.utbot.framework.plugin.api.UtCompositeModel
8+ import org.utbot.framework.plugin.api.UtDirectSetFieldModel
9+ import org.utbot.framework.plugin.api.UtEnumConstantModel
10+ import org.utbot.framework.plugin.api.UtExecutableCallModel
11+ import org.utbot.framework.plugin.api.UtLambdaModel
12+ import org.utbot.framework.plugin.api.UtModel
13+ import org.utbot.framework.plugin.api.UtNullModel
14+ import org.utbot.framework.plugin.api.UtPrimitiveModel
15+ import org.utbot.framework.plugin.api.UtVoidModel
16+ import org.utbot.framework.plugin.api.util.enclosingClass
17+
18+ class TestClassModelBuilder (
19+ private val isSpringClass : Boolean
20+ ) {
21+ fun createClassModel (classUnderTest : ClassId , testSets : List <CgMethodTestSet >): TestClassModel {
22+ // For each class stores list of methods declared in this class (methods from nested classes are excluded)
23+ val class2methodTestSets = testSets.groupBy { it.executableId.classId }
24+
25+ val classesWithMethodsUnderTest = testSets
26+ .map { it.executableId.classId }
27+ .distinct()
28+
29+ // For each class stores list of its "direct" nested classes
30+ val class2nestedClasses = mutableMapOf<ClassId , MutableSet <ClassId >>()
31+
32+ for (classId in classesWithMethodsUnderTest) {
33+ var currentClass = classId
34+ var enclosingClass = currentClass.enclosingClass
35+ // while we haven't reached the top of nested class hierarchy or the main class under test
36+ while (enclosingClass != null && currentClass != classUnderTest) {
37+ class2nestedClasses.getOrPut(enclosingClass) { mutableSetOf () } + = currentClass
38+ currentClass = enclosingClass
39+ enclosingClass = enclosingClass.enclosingClass
40+ }
41+ }
42+
43+ val baseModel = constructRecursively(classUnderTest, class2methodTestSets, class2nestedClasses)
44+
45+ return if (! isSpringClass) {
46+ baseModel
47+ } else {
48+ val mockedClasses = collectMockedClassIds(classUnderTest, testSets)
49+
50+ TestClassModel (
51+ baseModel.classUnderTest,
52+ baseModel.methodTestSets,
53+ baseModel.nestedClasses,
54+ classUnderTest,
55+ mockedClasses,
56+ )
57+ }
58+ }
59+
60+ private fun constructRecursively (
61+ clazz : ClassId ,
62+ class2methodTestSets : Map <ClassId , List <CgMethodTestSet >>,
63+ class2nestedClasses : Map <ClassId , Set <ClassId >>
64+ ): TestClassModel {
65+ val currentNestedClasses = class2nestedClasses.getOrDefault(clazz, listOf ())
66+ val currentMethodTestSets = class2methodTestSets.getOrDefault(clazz, listOf ())
67+ return TestClassModel (
68+ clazz,
69+ currentMethodTestSets,
70+ currentNestedClasses.map {
71+ constructRecursively(it, class2methodTestSets, class2nestedClasses)
72+ }
73+ )
74+ }
75+
76+ private fun collectMockedClassIds (
77+ classUnderTest : ClassId ,
78+ testSets : List <CgMethodTestSet >,
79+ ): Set <ClassId > {
80+ val allModelsInExecution = mutableListOf<UtModel >()
81+
82+ for (testSet in testSets) {
83+ for (execution in testSet.executions) {
84+ execution.stateBefore.thisInstance?.let { allModelsInExecution + = it }
85+ execution.stateAfter.thisInstance?.let { allModelsInExecution + = it }
86+ allModelsInExecution + = execution.stateBefore.parameters
87+ allModelsInExecution + = execution.stateAfter.parameters
88+ }
89+ }
90+
91+ val allConstructedModels = HashSet <UtModel >()
92+ allModelsInExecution.forEach { model -> collectRecursively(model, allConstructedModels) }
93+
94+ return allConstructedModels
95+ .filter { it.isMockComposite() || it.isMockAssemble() }
96+ .map { it.classId }
97+ .filter { it != classUnderTest }
98+ .toSet()
99+
100+ }
101+
102+ private fun collectRecursively (currentModel : UtModel , allModels : HashSet <UtModel >) {
103+ if (currentModel in allModels) {
104+ return
105+ }
106+
107+ allModels + = currentModel
108+
109+ when (currentModel) {
110+ is UtNullModel ,
111+ is UtPrimitiveModel ,
112+ is UtClassRefModel ,
113+ is UtVoidModel ,
114+ is UtEnumConstantModel -> {}
115+ is UtLambdaModel -> {
116+ currentModel.capturedValues.forEach { collectRecursively(it, allModels) }
117+ }
118+ is UtArrayModel -> {
119+ collectRecursively(currentModel.constModel, allModels)
120+ currentModel.stores.values.forEach { collectRecursively(it, allModels) }
121+ }
122+ is UtCompositeModel -> {
123+ currentModel.fields.values.forEach { collectRecursively(it, allModels) }
124+ currentModel.mocks.values.flatten().forEach { collectRecursively(it, allModels) }
125+ }
126+ is UtAssembleModel -> {
127+ if (currentModel.origin != null ) {
128+ collectRecursively(currentModel.origin!! , allModels)
129+ } else {
130+ currentModel.instantiationCall.instance?.let { collectRecursively(it, allModels) }
131+ currentModel.instantiationCall.params.forEach { collectRecursively(it, allModels) }
132+
133+ currentModel.modificationsChain.forEach { stmt ->
134+ stmt.instance?.let { collectRecursively(it, allModels) }
135+ when (stmt) {
136+ is UtExecutableCallModel -> stmt.params.forEach { collectRecursively(it, allModels) }
137+ is UtDirectSetFieldModel -> collectRecursively(stmt.fieldModel, allModels)
138+ }
139+ }
140+ }
141+ }
142+ // Python, JavaScript, Go models are not required in Spring
143+ else -> {}
144+ }
145+ }
146+
147+ private fun UtModel.isMockComposite (): Boolean = this is UtCompositeModel && this .isMock
148+
149+ private fun UtModel.isMockAssemble (): Boolean =
150+ this is UtAssembleModel && this .origin?.let { it.isMock } == true
151+ }
0 commit comments