Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f9c9534

Browse files
Call entityManager.flush() on every entityManager usage and dynamically remove failing UtStatementCallModels (#2550)
* Introduce deep `UtModel` mapper * Add `flush` after every `entityManager` usage * Move setting up Spring specific RD responses to `SpringUtExecutionInstrumentation` * Remove unused `getBean` rd call * Dynamically remove failing `UtStatementModel`s * Comment out unsafe class loading of `javax.servlet.http.Cookie` (until #2542 is fixed) * Avoid `mockMvc.perform((RequestBuilder) null)` tests * Address comments from #2550 * Clarify that we discard `mockMvc.perform((RequestBuilder) null)` test
1 parent 1931f26 commit f9c9534

File tree

27 files changed

+592
-315
lines changed

27 files changed

+592
-315
lines changed

‎utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ import java.io.File
5555
import kotlin.contracts.ExperimentalContracts
5656
import kotlin.contracts.contract
5757
import org.utbot.common.isAbstract
58+
import org.utbot.framework.plugin.api.mapper.UtModelMapper
59+
import org.utbot.framework.plugin.api.mapper.map
60+
import org.utbot.framework.plugin.api.mapper.mapPreservingType
5861
import org.utbot.framework.plugin.api.util.SpringModelUtils
5962
import org.utbot.framework.process.OpenModulesContainer
6063
import soot.SootMethod
@@ -767,15 +770,15 @@ abstract class UtCustomModel(
767770
modelName: String = id.toString(),
768771
override val origin: UtCompositeModel? = null,
769772
) : UtModelWithCompositeOrigin(id, classId, modelName, origin) {
770-
abstract val dependencies:Collection<UtModel>
773+
abstract funshallowMap(mapper:UtModelMapper): UtCustomModel
771774
}
772775

773776
object UtSpringContextModel : UtCustomModel(
774777
id = null,
775778
classId = SpringModelUtils.applicationContextClassId,
776779
modelName = "applicationContext"
777780
) {
778-
override val dependencies:Collection<UtModel> get() = emptySet()
781+
override funshallowMap(mapper:UtModelMapper) = this
779782

780783
// NOTE that overriding equals is required just because without it
781784
// we will lose equality for objects after deserialization
@@ -789,7 +792,7 @@ class UtSpringEntityManagerModel : UtCustomModel(
789792
classId = SpringModelUtils.entityManagerClassIds.first(),
790793
modelName = "entityManager"
791794
) {
792-
override val dependencies:Collection<UtModel> get() = emptySet()
795+
override funshallowMap(mapper:UtModelMapper) = this
793796

794797
// NOTE that overriding equals is required just because without it
795798
// we will lose equality for objects after deserialization
@@ -820,7 +823,10 @@ data class UtSpringMockMvcResultActionsModel(
820823
id = id,
821824
modelName = "mockMvcResultActions@$id"
822825
) {
823-
override val dependencies: Collection<UtModel> get() = emptySet()
826+
override fun shallowMap(mapper: UtModelMapper) = copy(
827+
origin = origin?.mapPreservingType<UtCompositeModel>(mapper),
828+
model = model?.map(mapper)
829+
)
824830
}
825831

826832
/**
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package org.utbot.framework.plugin.api.mapper
2+
3+
import org.utbot.framework.plugin.api.UtArrayModel
4+
import org.utbot.framework.plugin.api.UtAssembleModel
5+
import org.utbot.framework.plugin.api.UtClassRefModel
6+
import org.utbot.framework.plugin.api.UtCompositeModel
7+
import org.utbot.framework.plugin.api.UtCustomModel
8+
import org.utbot.framework.plugin.api.UtEnumConstantModel
9+
import org.utbot.framework.plugin.api.UtLambdaModel
10+
import org.utbot.framework.plugin.api.UtModel
11+
import org.utbot.framework.plugin.api.UtNullModel
12+
import org.utbot.framework.plugin.api.UtPrimitiveModel
13+
import org.utbot.framework.plugin.api.UtReferenceModel
14+
import org.utbot.framework.plugin.api.UtVoidModel
15+
16+
/**
17+
* Performs deep mapping of [UtModel]s.
18+
*
19+
* NOTE:
20+
* - [shallowMapper] is invoked on models **before** mapping their sub models.
21+
* - [shallowMapper] is responsible for caching own results (it may be called repeatedly on same models).
22+
*/
23+
class UtModelDeepMapper private constructor(
24+
private val shallowMapper: UtModelMapper
25+
) : UtModelMapper {
26+
constructor(shallowMapper: (UtModel) -> UtModel) : this(UtModelSafeCastingCachingShallowMapper(shallowMapper))
27+
28+
/**
29+
* Keys are models that have been shallowly mapped by [shallowMapper].
30+
* Values are models that have been deeply mapped by this [UtModelDeepMapper].
31+
* Models are only associated with models of the same type (i.e. the cache type is actually `MutableMap<T, T>`)
32+
*/
33+
private val cache = mutableMapOf<UtModel, UtModel>()
34+
35+
private val allInputtedModels get() = cache.keys
36+
private val allOutputtedModels get() = cache.values
37+
38+
override fun <T : UtModel> map(model: T, clazz: Class<T>): T =
39+
clazz.cast(mapNestedModels(shallowMapper.map(model, clazz)))
40+
41+
/**
42+
* Maps models contained inside [model], but not the [model] itself.
43+
*/
44+
private fun mapNestedModels(model: UtModel): UtModel = cache.getOrPut(model) {
45+
when (model) {
46+
is UtNullModel,
47+
is UtPrimitiveModel,
48+
is UtEnumConstantModel,
49+
is UtClassRefModel,
50+
is UtVoidModel -> model
51+
is UtArrayModel -> mapNestedModels(model)
52+
is UtCompositeModel -> mapNestedModels(model)
53+
is UtLambdaModel -> mapNestedModels(model)
54+
is UtAssembleModel -> mapNestedModels(model)
55+
is UtCustomModel -> mapNestedModels(model)
56+
57+
// PythonModel, JsUtModel may be here
58+
else -> throw UnsupportedOperationException("UtModel $this cannot be mapped")
59+
}
60+
}
61+
62+
private fun mapNestedModels(model: UtArrayModel): UtReferenceModel {
63+
val mappedModel = UtArrayModel(
64+
id = model.id,
65+
classId = model.classId,
66+
length = model.length,
67+
constModel = model.constModel,
68+
stores = model.stores,
69+
)
70+
cache[model] = mappedModel
71+
72+
mappedModel.constModel = model.constModel.map(this)
73+
mappedModel.stores.putAll(model.stores.mapModelValues(this))
74+
75+
return mappedModel
76+
}
77+
78+
private fun mapNestedModels(model: UtCompositeModel): UtCompositeModel {
79+
val mappedModel = UtCompositeModel(
80+
id = model.id,
81+
classId = model.classId,
82+
isMock = model.isMock,
83+
)
84+
cache[model] = mappedModel
85+
86+
mappedModel.fields.putAll(model.fields.mapModelValues(this))
87+
mappedModel.mocks.putAll(model.mocks.mapValuesTo(mutableMapOf()) { it.value.mapModels(this@UtModelDeepMapper) })
88+
89+
return mappedModel
90+
}
91+
92+
private fun mapNestedModels(model: UtLambdaModel): UtReferenceModel = UtLambdaModel(
93+
id = model.id,
94+
samType = model.samType,
95+
declaringClass = model.declaringClass,
96+
lambdaName = model.lambdaName,
97+
capturedValues = model.capturedValues.mapModels(this@UtModelDeepMapper).toMutableList()
98+
)
99+
100+
private fun mapNestedModels(model: UtAssembleModel): UtReferenceModel = UtAssembleModel(
101+
id = model.id,
102+
classId = model.classId,
103+
modelName = model.modelName,
104+
instantiationCall = model.instantiationCall.mapModels(this),
105+
modificationsChainProvider = {
106+
cache[model] = this@UtAssembleModel
107+
model.modificationsChain.map { it.mapModels(this@UtModelDeepMapper) }
108+
},
109+
origin = model.origin?.mapPreservingType<UtCompositeModel>(this)
110+
)
111+
112+
private fun mapNestedModels(model: UtCustomModel): UtReferenceModel =
113+
model.shallowMap(this)
114+
115+
companion object {
116+
/**
117+
* Creates identity deep mapper, runs [block] on it, and returns the set of all models that
118+
* were mapped (i.e. deeply collects all models reachable from models passed to `collector`).
119+
*/
120+
fun collectAllModels(block: (collector: UtModelDeepMapper) -> Unit): Set<UtModel> =
121+
UtModelDeepMapper(UtModelNoopMapper).also(block).allInputtedModels
122+
}
123+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.utbot.framework.plugin.api.mapper
2+
3+
import org.utbot.framework.plugin.api.UtCompositeModel
4+
import org.utbot.framework.plugin.api.UtModel
5+
import org.utbot.framework.plugin.api.UtModelWithCompositeOrigin
6+
7+
interface UtModelMapper {
8+
/**
9+
* Performs depending on the implementation deep or shallow mapping of the [model].
10+
*
11+
* In some cases (e.g. when mapping [UtModelWithCompositeOrigin.origin]) you may want to get result
12+
* of some specific type (e.g. [UtCompositeModel]), only then you should specify specific value for [clazz].
13+
*
14+
* NOTE: if you are fine with result model and [model] having different types, then you should
15+
* use `UtModel::class.java` as a value for [clazz] or just use [UtModel.map].
16+
*/
17+
fun <T : UtModel> map(model: T, clazz: Class<T>): T
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.utbot.framework.plugin.api.mapper
2+
3+
import org.utbot.framework.plugin.api.UtModel
4+
5+
object UtModelNoopMapper : UtModelMapper {
6+
override fun <T : UtModel> map(model: T, clazz: Class<T>): T = model
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.utbot.framework.plugin.api.mapper
2+
3+
import org.utbot.framework.plugin.api.UtModel
4+
5+
class UtModelSafeCastingCachingShallowMapper(
6+
val mapper: (UtModel) -> UtModel
7+
) : UtModelMapper {
8+
private val cache = mutableMapOf<UtModel, UtModel>()
9+
10+
override fun <T : UtModel> map(model: T, clazz: Class<T>): T {
11+
val mapped = cache.getOrPut(model) { mapper(model) }
12+
return if (clazz.isInstance(mapped)) clazz.cast(mapped)
13+
else model
14+
}
15+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.utbot.framework.plugin.api.mapper
2+
3+
import org.utbot.framework.plugin.api.EnvironmentModels
4+
import org.utbot.framework.plugin.api.UtDirectGetFieldModel
5+
import org.utbot.framework.plugin.api.UtDirectSetFieldModel
6+
import org.utbot.framework.plugin.api.UtExecutableCallModel
7+
import org.utbot.framework.plugin.api.UtExecution
8+
import org.utbot.framework.plugin.api.UtInstrumentation
9+
import org.utbot.framework.plugin.api.UtModel
10+
import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation
11+
import org.utbot.framework.plugin.api.UtReferenceModel
12+
import org.utbot.framework.plugin.api.UtStatementCallModel
13+
import org.utbot.framework.plugin.api.UtStatementModel
14+
import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation
15+
16+
inline fun <reified T : UtModel> T.mapPreservingType(mapper: UtModelMapper): T =
17+
mapper.map(this, T::class.java)
18+
19+
fun UtModel.map(mapper: UtModelMapper) = mapPreservingType<UtModel>(mapper)
20+
21+
fun List<UtModel>.mapModels(mapper: UtModelMapper): List<UtModel> =
22+
map { model -> model.map(mapper) }
23+
24+
fun <K> Map<K, UtModel>.mapModelValues(mapper: UtModelMapper): Map<K, UtModel> =
25+
mapValues { (_, model) -> model.map(mapper) }
26+
27+
fun UtStatementModel.mapModels(mapper: UtModelMapper): UtStatementModel =
28+
when(this) {
29+
is UtStatementCallModel -> mapModels(mapper)
30+
is UtDirectSetFieldModel -> UtDirectSetFieldModel(
31+
instance = instance.mapPreservingType<UtReferenceModel>(mapper),
32+
fieldId = fieldId,
33+
fieldModel = fieldModel.map(mapper)
34+
)
35+
}
36+
37+
fun UtStatementCallModel.mapModels(mapper: UtModelMapper): UtStatementCallModel =
38+
when(this) {
39+
is UtDirectGetFieldModel -> UtDirectGetFieldModel(
40+
instance = instance.mapPreservingType<UtReferenceModel>(mapper),
41+
fieldAccess = fieldAccess,
42+
)
43+
is UtExecutableCallModel -> UtExecutableCallModel(
44+
instance = instance?.mapPreservingType<UtReferenceModel>(mapper),
45+
executable = executable,
46+
params = params.mapModels(mapper)
47+
)
48+
}
49+
50+
fun EnvironmentModels.mapModels(mapper: UtModelMapper) = EnvironmentModels(
51+
thisInstance = thisInstance?.map(mapper),
52+
statics = statics.mapModelValues(mapper),
53+
parameters = parameters.mapModels(mapper),
54+
executableToCall = executableToCall,
55+
)
56+
57+
fun UtInstrumentation.mapModels(mapper: UtModelMapper) = when (this) {
58+
is UtNewInstanceInstrumentation -> copy(instances = instances.mapModels(mapper))
59+
is UtStaticMethodInstrumentation -> copy(values = values.mapModels(mapper))
60+
}
61+
62+
fun UtExecution.mapStateBeforeModels(mapper: UtModelMapper) = copy(
63+
stateBefore = stateBefore.mapModels(mapper)
64+
)

‎utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt‎

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ object SpringModelUtils {
6969
)
7070
}
7171

72+
val flushMethodIdOrNull: MethodId?
73+
get() {
74+
return MethodId(
75+
classId = entityManagerClassIds.firstOrNull() ?: return null,
76+
name = "flush",
77+
returnType = voidClassId,
78+
parameters = listOf(),
79+
bypassesSandbox = true // TODO may be we can use some alternative sandbox that has more permissions
80+
)
81+
}
82+
7283
val detachMethodIdOrNull: MethodId?
7384
get() {
7485
return MethodId(
@@ -182,12 +193,13 @@ object SpringModelUtils {
182193
parameters = listOf(httpHeaderClassId)
183194
)
184195

185-
private val mockHttpServletCookieMethodId = MethodId(
186-
classId = mockHttpServletRequestBuilderClassId,
187-
name = "cookie",
188-
returnType = mockHttpServletRequestBuilderClassId,
189-
parameters = listOf(getArrayClassIdByElementClassId(cookieClassId))
190-
)
196+
// // TODO uncomment when #2542 is fixed
197+
// private val mockHttpServletCookieMethodId = MethodId(
198+
// classId = mockHttpServletRequestBuilderClassId,
199+
// name = "cookie",
200+
// returnType = mockHttpServletRequestBuilderClassId,
201+
// parameters = listOf(getArrayClassIdByElementClassId(cookieClassId))
202+
// )
191203

192204
private val mockHttpServletContentTypeMethodId = MethodId(
193205
classId = mockHttpServletRequestBuilderClassId,
@@ -376,9 +388,10 @@ object SpringModelUtils {
376388
val headersContentModel = createHeadersContentModel(methodId, arguments, idGenerator)
377389
requestBuilderModel = addHeadersToRequestBuilderModel(headersContentModel, requestBuilderModel, idGenerator)
378390

379-
val cookieValuesModel = createCookieValuesModel(methodId, arguments, idGenerator)
380-
requestBuilderModel =
381-
addCookiesToRequestBuilderModel(cookieValuesModel, requestBuilderModel, idGenerator)
391+
// // TODO uncomment when #2542 is fixed
392+
// val cookieValuesModel = createCookieValuesModel(methodId, arguments, idGenerator)
393+
// requestBuilderModel =
394+
// addCookiesToRequestBuilderModel(cookieValuesModel, requestBuilderModel, idGenerator)
382395

383396
val requestAttributes = collectArgumentsWithAnnotationModels(methodId, requestAttributesClassId, arguments)
384397
requestBuilderModel =
@@ -455,28 +468,29 @@ object SpringModelUtils {
455468
return requestBuilderModel
456469
}
457470

458-
private fun addCookiesToRequestBuilderModel(
459-
cookieValuesModel: UtArrayModel,
460-
requestBuilderModel: UtAssembleModel,
461-
idGenerator: () -> Int
462-
): UtAssembleModel {
463-
@Suppress("NAME_SHADOWING")
464-
var requestBuilderModel = requestBuilderModel
465-
466-
if(cookieValuesModel.length > 0) {
467-
requestBuilderModel = UtAssembleModel(
468-
id = idGenerator(),
469-
classId = mockHttpServletRequestBuilderClassId,
470-
modelName = "requestBuilder",
471-
instantiationCall = UtExecutableCallModel(
472-
instance = requestBuilderModel,
473-
executable = mockHttpServletCookieMethodId,
474-
params = listOf(cookieValuesModel)
475-
)
476-
)
477-
}
478-
return requestBuilderModel
479-
}
471+
// // TODO uncomment when #2542 is fixed
472+
// private fun addCookiesToRequestBuilderModel(
473+
// cookieValuesModel: UtArrayModel,
474+
// requestBuilderModel: UtAssembleModel,
475+
// idGenerator: () -> Int
476+
// ): UtAssembleModel {
477+
// @Suppress("NAME_SHADOWING")
478+
// var requestBuilderModel = requestBuilderModel
479+
//
480+
// if(cookieValuesModel.length > 0) {
481+
// requestBuilderModel = UtAssembleModel(
482+
// id = idGenerator(),
483+
// classId = mockHttpServletRequestBuilderClassId,
484+
// modelName = "requestBuilder",
485+
// instantiationCall = UtExecutableCallModel(
486+
// instance = requestBuilderModel,
487+
// executable = mockHttpServletCookieMethodId,
488+
// params = listOf(cookieValuesModel)
489+
// )
490+
// )
491+
// }
492+
// return requestBuilderModel
493+
// }
480494

481495
private fun addHeadersToRequestBuilderModel(
482496
headersContentModel: UtAssembleModel,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,6 @@ data class CgMethodTestSet(
135135
return substituteExecutions(symbolicExecutionsWithoutMocking)
136136
}
137137

138-
privatefun substituteExecutions(newExecutions: List<UtExecution>): CgMethodTestSet =
138+
fun substituteExecutions(newExecutions: List<UtExecution>): CgMethodTestSet =
139139
copy().apply { executions = newExecutions }
140140
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /