Movatterモバイル変換


[0]ホーム

URL:


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

Commitace9742

Browse files
authored
Improve mock type inference in fuzzer (#2536)
1 parent2379473 commitace9742

File tree

7 files changed

+100
-23
lines changed

7 files changed

+100
-23
lines changed

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ commonsIoVersion=2.8.0
6060
kotlinLoggingVersion=1.8.3
6161
ktorVersion=1.4.1
6262
cliktVersion=3.2.0
63-
guavaVersion=30.0-jre
63+
guavaVersion=32.1.2-jre
6464
apacheCommonsExecVersion=1.2
6565
apacheCommonsTextVersion=1.9
6666
rgxgenVersion=1.3

‎utbot-framework/src/main/kotlin/org/utbot/framework/util/SizeUtils.kt‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import org.utbot.framework.plugin.api.UtLambdaModel
1414
importorg.utbot.framework.plugin.api.UtModel
1515
importorg.utbot.framework.plugin.api.UtNullModel
1616
importorg.utbot.framework.plugin.api.UtPrimitiveModel
17+
importorg.utbot.framework.plugin.api.UtReferenceModel
1718
importorg.utbot.framework.plugin.api.UtStatementModel
1819
importorg.utbot.framework.plugin.api.UtVoidModel
1920

@@ -27,30 +28,35 @@ fun EnvironmentModels.calculateSize(): Int {
2728

2829
/**
2930
* We assume that "size" for "common" models is 1, 0 for [UtVoidModel] (as they do not return anything) and
30-
* [UtPrimitiveModel] and [UtNullModel] (we use them as literals in codegen), summarising for all statements for [UtAssembleModel] and
31-
* summarising for all fields and mocks for [UtCompositeModel]. As [UtCompositeModel] could be recursive, we need to
32-
* store it in [used]. Moreover, if we already calculate size for [this], it means that we will use already created
33-
* variable by this model and do not need to create it again, so size should be equal to 0.
31+
* [UtPrimitiveModel] and 2 for [UtNullModel] (we use them as literals in codegen), summarising for
32+
* all statements for [UtAssembleModel] and summarising for all fields and mocks for [UtCompositeModel].
33+
*
34+
* As [UtReferenceModel] could be recursive, we need to store it in [used]. Moreover, if we have already
35+
* calculated the size for [this] model and [this] is [UtReferenceModel], then in codegen we would have already
36+
* created variable for [this] model and do not need to create it again, so size should be equal to 0.
3437
*/
35-
privatefun UtModel.calculateSize(used:MutableSet<UtModel> = mutableSetOf()):Int {
38+
privatefun UtModel.calculateSize(used:MutableSet<UtReferenceModel> = mutableSetOf()):Int {
3639
if (thisin used)return0
3740

38-
used+=this
41+
if (thisisUtReferenceModel)
42+
used+=this
3943

4044
returnwhen (this) {
41-
isUtNullModel,isUtPrimitiveModel,UtVoidModel->0
45+
// `null` is assigned size of `2` to encourage use of empty mocks which have size of `1` over `null`s
46+
isUtNullModel->2
47+
isUtPrimitiveModel,UtVoidModel->0
4248
isUtClassRefModel,isUtEnumConstantModel,isUtArrayModel,isUtCustomModel->1
4349
isUtAssembleModel-> {
4450
1+ instantiationCall.calculateSize(used)+ modificationsChain.sumOf { it.calculateSize(used) }
4551
}
46-
isUtCompositeModel->1+ fields.values.sumOf { it.calculateSize(used) }
52+
isUtCompositeModel->1+(fields.values+ mocks.values.flatten()).sumOf { it.calculateSize(used) }
4753
isUtLambdaModel->1+ capturedValues.sumOf { it.calculateSize(used) }
4854
// PythonModel, JsUtModel, UtSpringContextModel may be here
4955
else->0
5056
}
5157
}
5258

53-
privatefun UtStatementModel.calculateSize(used:MutableSet<UtModel> = mutableSetOf()):Int=
59+
privatefun UtStatementModel.calculateSize(used:MutableSet<UtReferenceModel> = mutableSetOf()):Int=
5460
when (this) {
5561
isUtExecutableCallModel->1+ params.sumOf { it.calculateSize(used) }+ (instance?.calculateSize(used)?:0)
5662
isUtDirectSetFieldModel->1+ fieldModel.calculateSize(used)+ instance.calculateSize(used)

‎utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/InstrumentationContextAwareValueConstructor.kt‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import org.utbot.instrumentation.instrumentation.execution.mock.MethodMockContro
5252
importorg.utbot.instrumentation.instrumentation.execution.mock.MockController
5353
importorg.utbot.instrumentation.process.runSandbox
5454
importjava.lang.reflect.Modifier
55+
importjava.lang.reflect.TypeVariable
5556
importjava.security.AccessController
5657
importjava.security.PrivilegedAction
5758
importjava.util.*
@@ -280,22 +281,25 @@ class InstrumentationContextAwareValueConstructor(
280281

281282
privateval dynamicMockModelToDepth= mutableMapOf<UtCompositeModel,Int>()
282283

283-
privatefungenerateNewAnswerModel(executableId:ExecutableId,depth:Int)=
284-
executableId.returnType.defaultValueModel().takeUnless { it.isNull() }?:when {
284+
privatefungenerateNewAnswerModel(methodId:MethodId,depth:Int)=
285+
methodId.returnType.defaultValueModel().takeUnless { it.isNull() }?:when {
286+
// use `null` to avoid false positive `ClassCastException`
287+
methodId.method.genericReturnTypeisTypeVariable<*>->UtNullModel(methodId.returnType)
288+
285289
// mockito can't mock `String` and `Class`
286-
executableId.returnType== stringClassId->UtNullModel(stringClassId)
287-
executableId.returnType== classClassId->UtClassRefModel(
290+
methodId.returnType== stringClassId->UtNullModel(stringClassId)
291+
methodId.returnType== classClassId->UtClassRefModel(
288292
id= idGenerator.createId(),
289293
classId= classClassId,
290294
value= classClassId,
291295
)
292-
depth>MAX_DYNAMIC_MOCK_DEPTH->UtNullModel(executableId.classId)
296+
depth>MAX_DYNAMIC_MOCK_DEPTH->UtNullModel(methodId.classId)
293297

294298
else->UtCompositeModel(
295299
id= idGenerator.createId(),
296300
// TODO mockito can't mock sealed interfaces,
297301
// we have to mock their implementations or use null
298-
classId=executableId.returnType,
302+
classId=methodId.returnType,
299303
isMock=true,
300304
canHaveRedundantOrMissingMocks=true,
301305
).also { dynamicMockModelToDepth[it]= depth+1 }

‎utbot-java-fuzzing/build.gradle.kts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
val sootVersion:String by rootProject
22
val kotlinLoggingVersion:String by rootProject
33
val rgxgenVersion:String by rootProject
4+
val guavaVersion:String by rootProject
45

56
dependencies {
67
implementation(project(":utbot-framework-api"))
@@ -12,4 +13,5 @@ dependencies {
1213
}
1314
implementation(group="io.github.microutils", name="kotlin-logging", version= kotlinLoggingVersion)
1415
implementation(group="com.github.curious-odd-man", name="rgxgen", version= rgxgenVersion)
16+
implementation(group="com.google.guava", name="guava", version= guavaVersion)
1517
}

‎utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class AbstractsObjectValueProvider(
177177
overridefungenerate(description:FuzzedDescription,type:FuzzedType)= sequence<Seed<FuzzedType,FuzzedValue>> {
178178
val t=try {
179179
Scene.v().getRefType(type.classId.name).sootClass
180-
}catch (ignore:NoClassDefFoundError) {
180+
}catch (ignore:Throwable) {
181181
logger.error(ignore) {"Soot may be not initialized" }
182182
return@sequence
183183
}

‎utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
packageorg.utbot.fuzzing.spring.unit
22

3+
importcom.google.common.reflect.TypeResolver
34
importmu.KotlinLogging
45
importorg.utbot.framework.plugin.api.ClassId
56
importorg.utbot.framework.plugin.api.MethodId
@@ -17,6 +18,9 @@ import org.utbot.fuzzing.Routine
1718
importorg.utbot.fuzzing.Scope
1819
importorg.utbot.fuzzing.ScopeProperty
1920
importorg.utbot.fuzzing.Seed
21+
importorg.utbot.fuzzing.spring.utils.jType
22+
importorg.utbot.fuzzing.spring.utils.toTypeParametrizedByTypeVariables
23+
importorg.utbot.fuzzing.spring.utils.typeToken
2024
importorg.utbot.fuzzing.toFuzzerType
2125

2226
val methodsToMockProperty=ScopeProperty<Set<MethodId>>(
@@ -28,6 +32,7 @@ class MockValueProvider(private val idGenerator: IdGenerator<Int>) : JavaValuePr
2832
companionobject {
2933
privateval logger=KotlinLogging.logger {}
3034
privateval loggedMockedMethods= mutableSetOf<MethodId>()
35+
privateval loggedUnresolvedMethods= mutableSetOf<MethodId>()
3136
}
3237

3338
privateval methodsToMock= mutableSetOf<MethodId>()
@@ -44,12 +49,26 @@ class MockValueProvider(private val idGenerator: IdGenerator<Int>) : JavaValuePr
4449
construct=Routine.Create(types= emptyList()) { emptyMockFuzzedValue(type.classId) },
4550
empty=Routine.Empty { emptyMockFuzzedValue(type.classId) },
4651
modify= (description.scope?.getProperty(methodsToMockProperty)?.asSequence()?: emptySequence()).map { methodId->
47-
if (loggedMockedMethods.add(methodId))
48-
logger.info {"Actually mocked$methodId for the first time" }
49-
// TODO accept `List<returnType>` instead of singular `returnType`
50-
Routine.Call(types=listOf(
51-
toFuzzerType(methodId.method.genericReturnType, description.typeCache)
52-
)) { instance, (value)->
52+
val methodDeclaringClass= methodId.classId.jClass
53+
54+
val returnType=try {
55+
TypeResolver().where(
56+
methodDeclaringClass.toTypeParametrizedByTypeVariables(),
57+
@Suppress("UNCHECKED_CAST")
58+
type.jType.typeToken.getSupertype(methodDeclaringClassasClass<inAny>).type
59+
).resolveType(methodId.method.genericReturnType)
60+
}catch (e:Exception) {
61+
if (loggedUnresolvedMethods.add(methodId))
62+
logger.error(e) {"Failed to resolve return type for$methodId, using unresolved generic type" }
63+
64+
methodId.method.genericReturnType
65+
}
66+
67+
// TODO accept `List<resolvedReturnType>` instead of singular `resolvedReturnType`
68+
Routine.Call(types=listOf(toFuzzerType(returnType, description.typeCache))) { instance, (value)->
69+
if (loggedMockedMethods.add(methodId))
70+
logger.info {"Actually mocked$methodId for the first time" }
71+
5372
(instance.modelasUtCompositeModel).mocks[methodId]=listOf(value.model)
5473
}
5574
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
packageorg.utbot.fuzzing.spring.utils
2+
3+
importcom.google.common.reflect.TypeToken
4+
importorg.utbot.framework.plugin.api.util.isArray
5+
importorg.utbot.framework.plugin.api.util.jClass
6+
importorg.utbot.fuzzer.FuzzedType
7+
importjava.lang.reflect.GenericArrayType
8+
importjava.lang.reflect.ParameterizedType
9+
importjava.lang.reflect.Type
10+
11+
valType.typeToken:TypeToken<*> get()=TypeToken.of(this)
12+
13+
valFuzzedType.jType:Type get()= toType(cache=mutableMapOf())
14+
15+
privatefun FuzzedType.toType(cache:MutableMap<FuzzedType,Type>):Type= cache.getOrPut(this) {
16+
when {
17+
generics.isEmpty()-> classId.jClass
18+
classId.isArray&& generics.size==1->GenericArrayType { generics.single().toType(cache) }
19+
else->object:ParameterizedType {
20+
overridefungetActualTypeArguments():Array<Type>=
21+
generics.map { it.toType(cache) }.toTypedArray()
22+
23+
overridefungetRawType():Type=
24+
classId.jClass
25+
26+
overridefungetOwnerType():Type?=null
27+
}
28+
}
29+
}
30+
31+
/**
32+
* Returns fully parameterized type, e.g. for `Map` class
33+
* `Map<K, V>` type is returned, where `K` and `V` are type variables.
34+
*/
35+
funClass<*>.toTypeParametrizedByTypeVariables():Type=
36+
if (typeParameters.isEmpty())this
37+
elseobject:ParameterizedType {
38+
overridefungetActualTypeArguments():Array<Type>=
39+
typeParameters.toList().toTypedArray()
40+
41+
overridefungetRawType():Type=
42+
this@toTypeParametrizedByTypeVariables
43+
44+
overridefungetOwnerType():Type?=
45+
declaringClass?.toTypeParametrizedByTypeVariables()
46+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp