diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 6b5c7480f3..7fe8da9a2c 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -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 @@ -73,6 +75,11 @@ data class UtMethodTestSet( val clustersInfo: List> = listOf(null to executions.indices) ) +fun UtMethodTestSet.mapModels(mapper: UtModelMapper): UtMethodTestSet = + copy(executions = executions.map { it.mapModels(mapper) }) + +fun Collection.mapModels(mapper: UtModelMapper) = map { it.mapModels(mapper) } + data class Step( val stmt: Stmt, val depth: Int, @@ -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 +abstract class UtExecutionWithInstrumentation( + stateBefore: EnvironmentModels, + stateAfter: EnvironmentModels, + result: UtExecutionResult, + coverage: Coverage? = null, + summary: List? = null, + testMethodName: String? = null, + displayName: String? = null, + val instrumentation: List, +) : 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? = this.summary, + testMethodName: String? = this.testMethodName, + displayName: String? = this.displayName, + instrumentation: List = this.instrumentation, + ): UtExecution + + override fun copy( + stateBefore: EnvironmentModels, + stateAfter: EnvironmentModels, + result: UtExecutionResult, + coverage: Coverage?, + summary: List?, + 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) }, + ) } /** @@ -167,7 +233,7 @@ class UtSymbolicExecution( stateBefore: EnvironmentModels, stateAfter: EnvironmentModels, result: UtExecutionResult, - override val instrumentation: List, + instrumentation: List, val path: MutableList, val fullPath: List, coverage: Coverage? = null, @@ -175,7 +241,16 @@ class UtSymbolicExecution( testMethodName: String? = null, displayName: String? = null, /** Convenient view of the full symbolic path */ val symbolicSteps: List = 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'. @@ -193,7 +268,8 @@ class UtSymbolicExecution( coverage: Coverage?, summary: List?, testMethodName: String?, - displayName: String? + displayName: String?, + instrumentation: List, ): UtExecution = UtSymbolicExecution( stateBefore = stateBefore, stateAfter = stateAfter, @@ -1356,19 +1432,49 @@ class BuiltinMethodId( name: String, returnType: ClassId, parameters: List, - 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, + 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 = 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( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/UtilMethodProviderPlaceholder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/UtilMethodProviderPlaceholder.kt new file mode 100644 index 0000000000..4e8d58c39f --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/UtilMethodProviderPlaceholder.kt @@ -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 + } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt index a7a05831f5..44f61a7dea 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/generator/AbstractCodeGenerator.kt @@ -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 @@ -42,6 +45,11 @@ abstract class AbstractCodeGenerator(params: CodeGeneratorParams) { testSets: Collection, 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 { diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt index 806f3126ec..f1958db378 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt @@ -22,8 +22,17 @@ class UtFuzzedExecution( displayName: String? = null, val fuzzingValues: List? = null, val fuzzedMethodDescription: FuzzedMethodDescription? = null, - override val instrumentation: List = emptyList(), -) : UtExecution(stateBefore, stateAfter, result, coverage, summary, testMethodName, displayName), UtExecutionWithInstrumentation { + instrumentation: List = 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'. @@ -39,7 +48,8 @@ class UtFuzzedExecution( coverage: Coverage?, summary: List?, testMethodName: String?, - displayName: String? + displayName: String?, + instrumentation: List, ): UtExecution { return UtFuzzedExecution( stateBefore, diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/converter/UtUsvmExecution.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/converter/UtUsvmExecution.kt index 2bed13737b..f4f199d5c8 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/converter/UtUsvmExecution.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/converter/UtUsvmExecution.kt @@ -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, @@ -19,16 +16,17 @@ class UtUsvmExecution( summary: List? = emptyList(), testMethodName: String? = null, displayName: String? = null, - override val instrumentation: List -) : UtExecution( + instrumentation: List +) : UtExecutionWithInstrumentation( stateBefore, stateAfter, result, coverage, summary, testMethodName, - displayName -), UtExecutionWithInstrumentation { + displayName, + instrumentation, +) { override fun copy( stateBefore: EnvironmentModels, stateAfter: EnvironmentModels, @@ -36,7 +34,8 @@ class UtUsvmExecution( coverage: Coverage?, summary: List?, testMethodName: String?, - displayName: String? + displayName: String?, + instrumentation: List, ): UtExecution = UtUsvmExecution( stateBefore, stateAfter, @@ -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? = this.summary, - testMethodName: String? = this.testMethodName, - displayName: String? = this.displayName, - instrumentation: List = 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) }, -) \ No newline at end of file