Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fixes after review
  • Loading branch information
Markoutte committed Oct 11, 2022
commit 23dc52a53c0acd949c820d069994c132cc980be3
27 changes: 12 additions & 15 deletions utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ import org.utbot.framework.plugin.api.UtModel
/**
* Fuzzed Value stores information about concrete UtModel, reference to [ModelProvider]
* and reasons about why this value was generated.
*
* [summary] is a piece of useful information that clarify why this value has a concrete value.
*
* It supports a special character `%var%` that is used as a placeholder for parameter name.
*
* For example:
* 1. `%var% = 2` for a value that have value 2
* 2. `%var% >= 4` for a value that shouldn't be less than 4
* 3. `foo(%var%) returns true` for values that should be passed as a function parameter
* 4. `%var% has special characters` to describe content
*/
open class FuzzedValue(
val model: UtModel,
val createdBy: ModelProvider? = null,
) {

/**
* Summary is a piece of useful information that clarify why this value has a concrete value.
*
* It supports a special character `%var%` that is used as a placeholder for parameter name.
*
* For example:
* 1. `%var% = 2` for a value that have value 2
* 2. `%var% >= 4` for a value that shouldn't be less than 4
* 3. `foo(%var%) returns true` for values that should be passed as a function parameter
* 4. `%var% has special characters` to describe content
*/
var summary: String? = null
}
var summary: String? = null,
)
4 changes: 2 additions & 2 deletions utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.utbot.framework.plugin.api.util.voidClassId
import org.utbot.fuzzer.mutators.NumberRandomMutator
import org.utbot.fuzzer.mutators.RegexStringModelMutator
import org.utbot.fuzzer.mutators.StringRandomMutator
import org.utbot.fuzzer.objects.replaceToMock
import org.utbot.fuzzer.objects.replaceWithMock
import org.utbot.fuzzer.providers.ArrayModelProvider
import org.utbot.fuzzer.providers.CharToStringModelProvider
import org.utbot.fuzzer.providers.CollectionWithEmptyStatesModelProvider
Expand Down Expand Up @@ -118,7 +118,7 @@ fun fuzz(description: FuzzedMethodDescription, vararg modelProviders: ModelProvi
val values = List<MutableList<FuzzedValue>>(description.parameters.size) { mutableListOf() }
modelProviders.forEach { fuzzingProvider ->
fuzzingProvider.generate(description).forEach { (index, model) ->
val mock = replaceToMock(model.model, description.shouldMock)
val mock = replaceWithMock(model.model, description.shouldMock)
values[index].add(FuzzedValue(mock, model.createdBy).apply {
summary = model.summary
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it not a part of the constructor?

})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtCompositeModel
import org.utbot.framework.plugin.api.UtDirectSetFieldModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
Expand All @@ -28,43 +27,6 @@ fun ModelProvider.assembleModel(id: Int, constructorId: ConstructorId, params: L
}
}

fun replaceToMock(assembleModel: UtModel, shouldMock: (ClassId) -> Boolean): UtModel {
if (assembleModel !is UtAssembleModel) return assembleModel
if (shouldMock(assembleModel.classId)) {
return UtCompositeModel(assembleModel.id, assembleModel.classId, true).apply {
assembleModel.modificationsChain.forEach {
if (it is UtDirectSetFieldModel) {
fields[it.fieldId] = replaceToMock(it.fieldModel, shouldMock)
}
if (it is UtExecutableCallModel && it.executable is FuzzerMockableMethodId) {
(it.executable as FuzzerMockableMethodId).mock().forEach { (executionId, models) ->
mocks[executionId] = models.map { p -> replaceToMock(p, shouldMock) }
}
}
}
}
} else {
val models = assembleModel.modificationsChain.map { call ->
var mockedStatementModel: UtStatementModel? = null
if (call is UtDirectSetFieldModel) {
val mock = replaceToMock(call.fieldModel, shouldMock)
if (mock != call.fieldModel) {
mockedStatementModel = UtDirectSetFieldModel(call.instance, call.fieldId, mock)
}
} else if (call is UtExecutableCallModel) {
val params = call.params.map { m -> replaceToMock(m, shouldMock) }
if (params != call.params) {
mockedStatementModel = UtExecutableCallModel(call.instance, call.executable, params)
}
}
mockedStatementModel ?: call
}
return with(assembleModel) {
UtAssembleModel(id, classId, modelName, instantiationCall, origin) { models }
}
}
}

fun ClassId.create(
block: AssembleModelDsl.() -> Unit
): UtAssembleModel {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.utbot.fuzzer.objects

import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtCompositeModel
import org.utbot.framework.plugin.api.UtDirectSetFieldModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtStatementModel

/**
* Implements [MethodId] but also can supply a mock for this execution.
*
* Simplest example: setter and getter,
* when this methodId is a setter, getter can be used for a mock to supply correct value.
*/
internal class FuzzerMockableMethodId(
classId: ClassId,
name: String,
returnType: ClassId,
parameters: List<ClassId>,
val mock: () -> Map<ExecutableId, List<UtModel>> = { emptyMap() },
) : MethodId(classId, name, returnType, parameters) {

constructor(copyOf: MethodId, mock: () -> Map<ExecutableId, List<UtModel>> = { emptyMap() }) : this(
copyOf.classId, copyOf.name, copyOf.returnType, copyOf.parameters, mock
)

}

internal fun MethodId.toFuzzerMockable(block: suspend SequenceScope<Pair<MethodId, List<UtModel>>>.() -> Unit): FuzzerMockableMethodId {
return FuzzerMockableMethodId(this) {
sequence { block() }.toMap()
}
}

internal fun replaceWithMock(assembleModel: UtModel, shouldMock: (ClassId) -> Boolean): UtModel = when {
assembleModel !is UtAssembleModel -> assembleModel
shouldMock(assembleModel.classId) -> createMockModelFromFuzzerMockable(assembleModel, shouldMock)
else -> updateInnerModels(assembleModel, shouldMock)
}

private fun createMockModelFromFuzzerMockable(model: UtAssembleModel, shouldMock: (ClassId) -> Boolean): UtCompositeModel {
val mock = UtCompositeModel(model.id, model.classId, true)
for (mutator in model.modificationsChain) {
if (mutator is UtDirectSetFieldModel) {
mock.fields[mutator.fieldId] = replaceWithMock(mutator.fieldModel, shouldMock)
}
if (mutator is UtExecutableCallModel && mutator.executable is FuzzerMockableMethodId) {
(mutator.executable as FuzzerMockableMethodId).mock().forEach { (executionId, models) ->
mock.mocks[executionId] = models.map { p -> replaceWithMock(p, shouldMock) }
}
}
}
return mock
}

private fun updateInnerModels(model: UtAssembleModel, shouldMock: (ClassId) -> Boolean): UtAssembleModel {
val models = model.modificationsChain.map { call ->
var mockedStatementModel: UtStatementModel? = null
when (call) {
is UtDirectSetFieldModel -> {
val mock = replaceWithMock(call.fieldModel, shouldMock)
if (mock != call.fieldModel) {
mockedStatementModel = UtDirectSetFieldModel(call.instance, call.fieldId, mock)
}
}
is UtExecutableCallModel -> {
val params = call.params.map { m -> replaceWithMock(m, shouldMock) }
if (params != call.params) {
mockedStatementModel = UtExecutableCallModel(call.instance, call.executable, params)
}
}
}
mockedStatementModel ?: call
}
return with(model) {
UtAssembleModel(id, classId, modelName, instantiationCall, origin) { models }
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ class ObjectModelProvider(
mock = {
field.getter?.let { g ->
val getterMethodID = MethodId(
constructorId.classId,
g.name,
g.returnType.id,
emptyList()
classId = constructorId.classId,
name = g.name,
returnType = g.returnType.id,
parameters = emptyList()
)
mapOf(getterMethodID to listOf(value.model))
} ?: emptyMap()
Expand Down Expand Up @@ -158,16 +158,21 @@ class ObjectModelProvider(
return jClass.declaredFields.map { field ->
val setterAndGetter = jClass.findPublicSetterGetterIfHasPublicGetter(field, description)
FieldDescription(
field.name,
field.type.id,
isAccessible(field, description.packageName) && !isFinal(field.modifiers) && !isStatic(field.modifiers),
setterAndGetter?.first,
setterAndGetter?.second,
name = field.name,
classId = field.type.id,
canBeSetDirectly = isAccessible(field, description.packageName) && !isFinal(field.modifiers) && !isStatic(field.modifiers),
setter = setterAndGetter?.setter,
getter = setterAndGetter?.getter,
)
}
}

private fun Class<*>.findPublicSetterGetterIfHasPublicGetter(field: Field, description: FuzzedMethodDescription): Pair<Method, Method>? {
private class PublicSetterGetter(
val setter: Method,
val getter: Method,
)

private fun Class<*>.findPublicSetterGetterIfHasPublicGetter(field: Field, description: FuzzedMethodDescription): PublicSetterGetter? {
val postfixName = field.name.capitalize()
val setterName = "set$postfixName"
val getterName = "get$postfixName"
Expand All @@ -178,7 +183,7 @@ class ObjectModelProvider(
it.name == setterName &&
it.parameterCount == 1 &&
it.parameterTypes[0] == field.type
}?.let { it to getter }
}?.let { PublicSetterGetter(it, getter) }
} else {
null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.utbot.framework.plugin.api.util.voidClassId
import org.utbot.framework.plugin.api.util.withUtContext
import org.utbot.fuzzer.FuzzedMethodDescription
import org.utbot.fuzzer.objects.create
import org.utbot.fuzzer.objects.replaceToMock
import org.utbot.fuzzer.objects.replaceWithMock
import org.utbot.fuzzer.objects.toFuzzerMockable
import org.utbot.fuzzer.providers.ObjectModelProvider

Expand All @@ -25,7 +25,7 @@ class MockOfObjectModelProviderTest {
val description = FuzzedMethodDescription("test", voidClassId, listOf(Some::class.id))
val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator)
val results = provider.generate(description).map { it.value.model }.map {
replaceToMock(it) { m -> description.shouldMock(m) }
replaceWithMock(it) { m -> description.shouldMock(m) }
}.toList()
assertEquals(2, results.size)
results.forEach { model ->
Expand All @@ -42,7 +42,7 @@ class MockOfObjectModelProviderTest {
}
val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator)
val results = provider.generate(description).map { it.value.model }.map {
replaceToMock(it) { m -> description.shouldMock(m) }
replaceWithMock(it) { m -> description.shouldMock(m) }
}.toList()
assertEquals(2, results.size)
results.forEach { model ->
Expand All @@ -58,7 +58,7 @@ class MockOfObjectModelProviderTest {
}
val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator, recursionDepthLeft = 2)
val results = provider.generate(description).map { it.value.model }.map {
replaceToMock(it) { m -> description.shouldMock(m) }
replaceWithMock(it) { m -> description.shouldMock(m) }
}.toList()
assertEquals(2, results.size)
results.forEach { model ->
Expand All @@ -80,7 +80,7 @@ class MockOfObjectModelProviderTest {
using empty constructor
call instance field("some") with UtNullModel(Nothing::class.id)
}
val replacedModel = replaceToMock(customModel) { true }
val replacedModel = replaceWithMock(customModel) { true }
assertInstanceOf(UtCompositeModel::class.java, replacedModel)
replacedModel as UtCompositeModel
assertEquals(0, replacedModel.mocks.size)
Expand All @@ -99,7 +99,7 @@ class MockOfObjectModelProviderTest {
yield(MethodId(classId, "another", doubleWrapperClassId, emptyList()) to listOf(UtPrimitiveModel(2.0)))
} with values(UtNullModel(Nothing::class.id))
}
val replacedModel = replaceToMock(customModel) { true }
val replacedModel = replaceWithMock(customModel) { true }
assertInstanceOf(UtCompositeModel::class.java, replacedModel)
replacedModel as UtCompositeModel
assertEquals(0, replacedModel.fields.size)
Expand Down