GeezerVison is showing github.com — Other class is not mocked as required #747 by Markoutte · Pull Request #1033 · UnitTestBot/UTBotJava
Other class is not mocked as required #747
#1033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement . We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Uh oh!
There was an error while loading. Please reload this page.
Show file tree
Hide file tree
Changes from all commits
Commits
File filter
Filter by extension
.kt
(8)
All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Hide whitespace
Diff view
Hide whitespace
There are no files selected for viewing
Original file line number
Diff line number
Diff line change
Expand Up
@@ -158,7 +158,7 @@ class UtBotSymbolicEngine(
private val methodUnderTest: ExecutableId,
classpath: String,
dependencyPaths: String,
mockStrategy: MockStrategy = NO_MOCKS,
val mockStrategy: MockStrategy = NO_MOCKS,
chosenClassesToMockAlways: Set<ClassId>,
private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis
) : UtContextInitializer() {
Expand Down
Expand Up
@@ -429,6 +429,7 @@ class UtBotSymbolicEngine(
val names = graph.body.method.tags.filterIsInstance<ParamNamesTag>().firstOrNull()?.names
parameterNameMap = { index -> names?.getOrNull(index) }
fuzzerType = { try { toFuzzerType(methodUnderTest.executable.genericParameterTypes[it]) } catch (_: Throwable) { null } }
shouldMock = { mockStrategy.eligibleToMock(it, classUnderTest) }
}
val coveredInstructionTracker = Trie(Instruction::id)
val coveredInstructionValues = linkedMapOf<Trie.Node<Instruction>, List<FuzzedValue>>()
Expand Down
Original file line number
Diff line number
Diff line change
Expand Up
@@ -52,6 +52,11 @@ class FuzzedMethodDescription(
*/
var fuzzerType: (Int) -> FuzzedType? = { null }
/**
* Returns true if class should be mocked.
*/
var shouldMock: (ClassId) -> Boolean = { false }
/**
* Map class id to indices of this class in parameters list.
*/
Expand Down
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,
)
Original file line number
Diff line number
Diff line change
Expand Up
@@ -7,6 +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.replaceWithMock
import org.utbot.fuzzer.providers.ArrayModelProvider
import org.utbot.fuzzer.providers.CharToStringModelProvider
import org.utbot.fuzzer.providers.CollectionWithEmptyStatesModelProvider
Expand Down
Expand Up
@@ -117,7 +118,10 @@ 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) ->
values[index].add(model)
val mock = replaceWithMock(model.model, description.shouldMock)
values[index].add(FuzzedValue(mock, model.createdBy).apply {
summary = model.summary
Comment thread
There was a problem hiding this comment.
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?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
})
}
}
description.parameters.forEachIndexed { index, classId ->
Expand Down
Original file line number
Diff line number
Diff line change
Expand Up
@@ -3,8 +3,10 @@ package org.utbot.fuzzer.objects
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.ConstructorId
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.UtDirectSetFieldModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtStatementModel
Expand Down
Expand Up
@@ -38,6 +40,7 @@ class AssembleModelDsl internal constructor(
val call = KeyWord.Call
val constructor = KeyWord.Constructor(classId)
val method = KeyWord.Method(classId)
val field = KeyWord.Field(classId)
var id: () -> Int? = { null }
var name: (Int?) -> String = { "<dsl generated model>" }
Expand All
@@ -53,10 +56,15 @@ class AssembleModelDsl internal constructor(
infix fun <T : ExecutableId> KeyWord.Call.instance(executableId: T) = CallDsl(executableId, false)
infix fun <T : FieldId> KeyWord.Call.instance(field: T) = FieldDsl(field, false)
infix fun <T : ExecutableId> KeyWord.Using.static(executableId: T) = UsingDsl(executableId)
infix fun <T : ExecutableId> KeyWord.Call.static(executableId: T) = CallDsl(executableId, true)
infix fun <T : FieldId> KeyWord.Call.static(field: T) = FieldDsl(field, true)
@Suppress("UNUSED_PARAMETER")
infix fun KeyWord.Using.empty(ignored: KeyWord.Constructor) {
initialization = { UtExecutableCallModel(null, ConstructorId(classId, emptyList()), emptyList()) }
}
Expand All
@@ -73,6 +81,10 @@ class AssembleModelDsl internal constructor(
modChain += { UtExecutableCallModel(it, executableId, models.toList()) }
}
infix fun FieldDsl.with(model: UtModel) {
modChain += { UtDirectSetFieldModel(it, fieldId, model) }
}
internal fun build(): UtAssembleModel {
val objectId = id()
return UtAssembleModel(
Expand Down
Expand Up
@@ -102,8 +114,14 @@ class AssembleModelDsl internal constructor(
return MethodId(classId, name, returns, params)
}
}
class Field(val classId: ClassId) : KeyWord() {
operator fun invoke(name: String): FieldId {
return FieldId(classId, name)
}
}
}
class UsingDsl(val executableId: ExecutableId)
class CallDsl(val executableId: ExecutableId, val isStatic: Boolean)
class FieldDsl(val fieldId: FieldId, val isStatic: Boolean)
}
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 }
}
}
Original file line number
Diff line number
Diff line change
Expand Up
@@ -27,6 +27,7 @@ import org.utbot.fuzzer.FuzzedMethodDescription
import org.utbot.fuzzer.FuzzedType
import org.utbot.fuzzer.FuzzedValue
import org.utbot.fuzzer.IdentityPreservingIdGenerator
import org.utbot.fuzzer.objects.FuzzerMockableMethodId
import org.utbot.fuzzer.objects.assembleModel
/**
Expand Down
Expand Up
@@ -101,11 +102,22 @@ class ObjectModelProvider(
)
field.setter != null -> UtExecutableCallModel(
fuzzedModel.model,
MethodId (
FuzzerMockableMethodId (
constructorId.classId,
field.setter.name,
field.setter.returnType.id,
listOf(field.classId)
listOf(field.classId),
mock = {
field.getter?.let { g ->
val getterMethodID = MethodId(
classId = constructorId.classId,
name = g.name,
returnType = g.returnType.id,
parameters = emptyList()
)
mapOf(getterMethodID to listOf(value.model))
} ?: emptyMap()
}
),
listOf(value.model)
)
Expand Down
Expand Up
@@ -144,16 +156,23 @@ class ObjectModelProvider(
private fun findSuitableFields(classId: ClassId, description: FuzzedMethodDescription): List<FieldDescription> {
val jClass = classId.jClass
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),
jClass.findPublicSetterIfHasPublicGetter(field, description)
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<*>.findPublicSetterIfHasPublicGetter(field: Field, description: FuzzedMethodDescription): 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
@@ -164,7 +183,7 @@ class ObjectModelProvider(
it.name == setterName &&
it.parameterCount == 1 &&
it.parameterTypes[0] == field.type
}
}?.let { PublicSetterGetter(it, getter) }
} else {
null
}
Expand All
@@ -184,6 +203,7 @@ class ObjectModelProvider(
val classId: ClassId,
val canBeSetDirectly: Boolean,
val setter: Method?,
val getter: Method?
)
}
}
Loading
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.