GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

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.

Sign up for GitHub

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

Merged
Markoutte merged 3 commits into main from pelevin/747_Other_class_is_not_mocked_as_required
Oct 11, 2022

Uh oh!

There was an error while loading. Please reload this page.

Merged

Other class is not mocked as required #747 #1033

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
3 commits
Select commit Hold shift + click to select a range
14f4b94
Other class is not mocked as required #747
Markoutte Sep 27, 2022
0299e13
Fix tests
Markoutte Oct 4, 2022
23dc52a
Fixes after review
Markoutte Oct 11, 2022
File filter
Filter by extension

Clear filters
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
Diff view

There are no files selected for viewing

3 changes: 2 additions & 1 deletion 3 utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt
Show comments
View file
Open in desktop
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
5 changes: 5 additions & 0 deletions 5 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedMethodDescription.kt
Show comments
View file
Open in desktop
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
27 changes: 12 additions & 15 deletions 27 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt
Show comments
View file
Open in desktop
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,
)
6 changes: 5 additions & 1 deletion 6 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt
Show comments
View file
Open in desktop
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

@CaelmBleidd CaelmBleidd Oct 5, 2022

Copy link
Copy Markdown
Member

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.

All reactions
})
}
}
description.parameters.forEachIndexed { index, classId ->
Expand Down
18 changes: 18 additions & 0 deletions 18 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt
Show comments
View file
Open in desktop
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)
}
82 changes: 82 additions & 0 deletions 82 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/FuzzerMockUtils.kt
Show comments
View file
Open in desktop
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 }
}
}
36 changes: 28 additions & 8 deletions 36 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt
Show comments
View file
Open in desktop
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.