Skip to content

Introduce UtilMethodProviderPlaceholder #2717

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import kotlin.contracts.contract
import org.utbot.common.isAbstract
import org.utbot.framework.plugin.api.mapper.UtModelMapper
import org.utbot.framework.plugin.api.mapper.map
import org.utbot.framework.plugin.api.mapper.mapModelIfExists
import org.utbot.framework.plugin.api.mapper.mapModels
import org.utbot.framework.plugin.api.mapper.mapPreservingType
import org.utbot.framework.plugin.api.util.SpringModelUtils
import org.utbot.framework.process.OpenModulesContainer
Expand All @@ -73,6 +75,11 @@ data class UtMethodTestSet(
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
)

fun UtMethodTestSet.mapModels(mapper: UtModelMapper): UtMethodTestSet =
copy(executions = executions.map { it.mapModels(mapper) })

fun Collection<UtMethodTestSet>.mapModels(mapper: UtModelMapper) = map { it.mapModels(mapper) }

data class Step(
val stmt: Stmt,
val depth: Int,
Expand Down Expand Up @@ -145,11 +152,70 @@ abstract class UtExecution(
displayName: String? = this.displayName,
): UtExecution

open fun mapModels(mapper: UtModelMapper) = copy(
stateBefore = stateBefore.mapModels(mapper),
stateAfter = stateAfter.mapModels(mapper),
result = result.mapModelIfExists(mapper)
)

val executableToCall get() = stateBefore.executableToCall
}

interface UtExecutionWithInstrumentation {
val instrumentation: List<UtInstrumentation>
abstract class UtExecutionWithInstrumentation(
stateBefore: EnvironmentModels,
stateAfter: EnvironmentModels,
result: UtExecutionResult,
coverage: Coverage? = null,
summary: List<DocStatement>? = null,
testMethodName: String? = null,
displayName: String? = null,
val instrumentation: List<UtInstrumentation>,
) : UtExecution(
stateBefore = stateBefore,
stateAfter = stateAfter,
result = result,
coverage = coverage,
summary = summary,
testMethodName = testMethodName,
displayName = displayName,
) {
abstract fun copy(
stateBefore: EnvironmentModels = this.stateBefore,
stateAfter: EnvironmentModels = this.stateAfter,
result: UtExecutionResult = this.result,
coverage: Coverage? = this.coverage,
summary: List<DocStatement>? = this.summary,
testMethodName: String? = this.testMethodName,
displayName: String? = this.displayName,
instrumentation: List<UtInstrumentation> = this.instrumentation,
): UtExecution

override fun copy(
stateBefore: EnvironmentModels,
stateAfter: EnvironmentModels,
result: UtExecutionResult,
coverage: Coverage?,
summary: List<DocStatement>?,
testMethodName: String?,
displayName: String?,
): UtExecution = copy(
stateBefore = stateBefore,
stateAfter = stateAfter,
result = result,
instrumentation = instrumentation,
coverage = coverage,
summary = summary,
testMethodName = testMethodName,
displayName = displayName,
)

override fun mapModels(mapper: UtModelMapper): UtExecution =
copy(
stateBefore = stateBefore.mapModels(mapper),
stateAfter = stateAfter.mapModels(mapper),
result = result.mapModelIfExists(mapper),
instrumentation = instrumentation.map { it.mapModels(mapper) },
)
}

/**
Expand All @@ -167,15 +233,24 @@ class UtSymbolicExecution(
stateBefore: EnvironmentModels,
stateAfter: EnvironmentModels,
result: UtExecutionResult,
override val instrumentation: List<UtInstrumentation>,
instrumentation: List<UtInstrumentation>,
val path: MutableList<Step>,
val fullPath: List<Step>,
coverage: Coverage? = null,
summary: List<DocStatement>? = null,
testMethodName: String? = null,
displayName: String? = null,
/** Convenient view of the full symbolic path */ val symbolicSteps: List<SymbolicStep> = listOf(),
) : UtExecution(stateBefore, stateAfter, result, coverage, summary, testMethodName, displayName), UtExecutionWithInstrumentation {
) : UtExecutionWithInstrumentation(
stateBefore,
stateAfter,
result,
coverage,
summary,
testMethodName,
displayName,
instrumentation
) {
/**
* By design the 'before' and 'after' states contain info about the same fields.
* It means that it is not possible for a field to be present at 'before' and to be absent at 'after'.
Expand All @@ -193,7 +268,8 @@ class UtSymbolicExecution(
coverage: Coverage?,
summary: List<DocStatement>?,
testMethodName: String?,
displayName: String?
displayName: String?,
instrumentation: List<UtInstrumentation>,
): UtExecution = UtSymbolicExecution(
stateBefore = stateBefore,
stateAfter = stateAfter,
Expand Down Expand Up @@ -1356,19 +1432,49 @@ class BuiltinMethodId(
name: String,
returnType: ClassId,
parameters: List<ClassId>,
bypassesSandbox: Boolean = false,
// by default we assume that the builtin method is non-static and public
isStatic: Boolean = false,
isPublic: Boolean = true,
isProtected: Boolean = false,
isPrivate: Boolean = false
bypassesSandbox: Boolean,
override val modifiers: Int,
) : MethodId(classId, name, returnType, parameters, bypassesSandbox) {
override val modifiers: Int = ModifierFactory {
static = isStatic
public = isPublic
private = isPrivate
protected = isProtected
}
constructor(
classId: ClassId,
name: String,
returnType: ClassId,
parameters: List<ClassId>,
bypassesSandbox: Boolean = false,
// by default, we assume that the builtin method is non-static and public
isStatic: Boolean = false,
isPublic: Boolean = true,
isProtected: Boolean = false,
isPrivate: Boolean = false
) : this(
classId = classId,
name = name,
returnType = returnType,
parameters = parameters,
bypassesSandbox = bypassesSandbox,
modifiers = ModifierFactory {
static = isStatic
public = isPublic
private = isPrivate
protected = isProtected
}
)

fun copy(
classId: ClassId = this.classId,
name: String = this.name,
returnType: ClassId = this.returnType,
parameters: List<ClassId> = this.parameters,
bypassesSandbox: Boolean = this.bypassesSandbox,
modifiers: Int = this.modifiers,
) = BuiltinMethodId(
classId = classId,
name = name,
returnType = returnType,
parameters = parameters,
bypassesSandbox = bypassesSandbox,
modifiers = modifiers,
)
}

class BuiltinConstructorId(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.utbot.framework.codegen.domain.builtin

import org.utbot.framework.plugin.api.BuiltinMethodId
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtStatementCallModel
import org.utbot.framework.plugin.api.UtStatementModel

/**
* Can be used in `UtModel`s to denote class containing util methods,
* before actual [ClassId] containing these methods has been determined.
*
* At the very start of the code generation, [utilClassIdPlaceholder] is
* replaced with actual [ClassId] containing util methods.
*/
val utilClassIdPlaceholder = utJavaUtilsClassId
object UtilMethodProviderPlaceholder : UtilMethodProvider(utilClassIdPlaceholder)

fun UtModel.shallowlyFixUtilClassIds(actualUtilClassId: ClassId) = when (this) {
is UtAssembleModel -> UtAssembleModel(
id = id,
classId = classId,
modelName = modelName,
instantiationCall = instantiationCall.shallowlyFixUtilClassId(actualUtilClassId),
origin = origin,
modificationsChainProvider = { modificationsChain.map { it.shallowlyFixUtilClassId(actualUtilClassId) } }
)
else -> this
}

private fun UtStatementModel.shallowlyFixUtilClassId(actualUtilClassId: ClassId) =
when (this) {
is UtExecutableCallModel -> shallowlyFixUtilClassId(actualUtilClassId)
else -> this
}

private fun UtStatementCallModel.shallowlyFixUtilClassId(actualUtilClassId: ClassId) =
when (this) {
is UtExecutableCallModel -> {
val executable = executable
if (executable.classId == utilClassIdPlaceholder && executable is BuiltinMethodId) {
copy(executable = executable.copy(classId = actualUtilClassId))
} else {
this
}
}
else -> this
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.utbot.framework.codegen.generator

import mu.KotlinLogging
import org.utbot.framework.codegen.domain.builtin.shallowlyFixUtilClassIds
import org.utbot.framework.codegen.domain.context.CgContext
import org.utbot.framework.codegen.domain.models.CgClassFile
import org.utbot.framework.codegen.domain.models.CgMethodTestSet
import org.utbot.framework.codegen.renderer.CgAbstractRenderer
import org.utbot.framework.plugin.api.UtMethodTestSet
import org.utbot.framework.plugin.api.mapModels
import org.utbot.framework.plugin.api.mapper.UtModelDeepMapper
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

Expand Down Expand Up @@ -42,6 +45,11 @@ abstract class AbstractCodeGenerator(params: CodeGeneratorParams) {
testSets: Collection<UtMethodTestSet>,
testClassCustomName: String? = null,
): CodeGeneratorResult {
@Suppress("NAME_SHADOWING")
val testSets = testSets.mapModels(UtModelDeepMapper { model ->
model.shallowlyFixUtilClassIds(actualUtilClassId = context.utilsClassId)
})

val cgTestSets = testSets.map { CgMethodTestSet(it) }.toList()
return withCustomContext(testClassCustomName) {
context.withTestClassFileScope {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ class UtFuzzedExecution(
displayName: String? = null,
val fuzzingValues: List<FuzzedValue>? = null,
val fuzzedMethodDescription: FuzzedMethodDescription? = null,
override val instrumentation: List<UtInstrumentation> = emptyList(),
) : UtExecution(stateBefore, stateAfter, result, coverage, summary, testMethodName, displayName), UtExecutionWithInstrumentation {
instrumentation: List<UtInstrumentation> = emptyList(),
) : UtExecutionWithInstrumentation(
stateBefore,
stateAfter,
result,
coverage,
summary,
testMethodName,
displayName,
instrumentation
) {
/**
* By design the 'before' and 'after' states contain info about the same fields.
* It means that it is not possible for a field to be present at 'before' and to be absent at 'after'.
Expand All @@ -39,7 +48,8 @@ class UtFuzzedExecution(
coverage: Coverage?,
summary: List<DocStatement>?,
testMethodName: String?,
displayName: String?
displayName: String?,
instrumentation: List<UtInstrumentation>,
): UtExecution {
return UtFuzzedExecution(
stateBefore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import org.utbot.framework.plugin.api.UtExecution
import org.utbot.framework.plugin.api.UtExecutionResult
import org.utbot.framework.plugin.api.UtExecutionWithInstrumentation
import org.utbot.framework.plugin.api.UtInstrumentation
import org.utbot.framework.plugin.api.mapper.UtModelMapper
import org.utbot.framework.plugin.api.mapper.mapModelIfExists
import org.utbot.framework.plugin.api.mapper.mapModels

class UtUsvmExecution(
stateBefore: EnvironmentModels,
Expand All @@ -19,24 +16,26 @@ class UtUsvmExecution(
summary: List<DocStatement>? = emptyList(),
testMethodName: String? = null,
displayName: String? = null,
override val instrumentation: List<UtInstrumentation>
) : UtExecution(
instrumentation: List<UtInstrumentation>
) : UtExecutionWithInstrumentation(
stateBefore,
stateAfter,
result,
coverage,
summary,
testMethodName,
displayName
), UtExecutionWithInstrumentation {
displayName,
instrumentation,
) {
override fun copy(
stateBefore: EnvironmentModels,
stateAfter: EnvironmentModels,
result: UtExecutionResult,
coverage: Coverage?,
summary: List<DocStatement>?,
testMethodName: String?,
displayName: String?
displayName: String?,
instrumentation: List<UtInstrumentation>,
): UtExecution = UtUsvmExecution(
stateBefore,
stateAfter,
Expand All @@ -47,35 +46,4 @@ class UtUsvmExecution(
displayName,
instrumentation,
)

fun copy(
stateBefore: EnvironmentModels = this.stateBefore,
stateAfter: EnvironmentModels = this.stateAfter,
result: UtExecutionResult = this.result,
coverage: Coverage? = this.coverage,
summary: List<DocStatement>? = this.summary,
testMethodName: String? = this.testMethodName,
displayName: String? = this.displayName,
instrumentation: List<UtInstrumentation> = this.instrumentation,
) = UtUsvmExecution(
stateBefore,
stateAfter,
result,
coverage,
summary,
testMethodName,
displayName,
instrumentation,
)
}

fun UtUsvmExecution.mapModels(mapper: UtModelMapper) = copy(
stateBefore = stateBefore.mapModels(mapper),
stateAfter = stateAfter.mapModels(mapper),
result = result.mapModelIfExists(mapper),
coverage = this.coverage,
summary = this.summary,
testMethodName = this.testMethodName,
displayName = this.displayName,
instrumentation = instrumentation.map { it.mapModels(mapper) },
)