Skip to content

Commit

Permalink
Introduce UtilMethodProviderPlaceholder (#2717)
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyaMuravjov authored and EgorkaKulikov committed Dec 14, 2023
1 parent a7ce884 commit 5961d80
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 59 deletions.
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 @@ -1369,19 +1445,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) },
)

0 comments on commit 5961d80

Please sign in to comment.