Skip to content

An attempt to avoid UtMethod in codegen #602

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 5 commits into from
Aug 1, 2022
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 @@ -98,6 +98,22 @@ data class UtMethodTestSet(
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
)

data class CgMethodTestSet private constructor(
val executableId: ExecutableId,
val executions: List<UtExecution> = emptyList(),
val jimpleBody: JimpleBody? = null,
val errors: Map<String, Int> = emptyMap(),
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
) {
constructor(from: UtMethodTestSet) : this(
from.method.callable.executableId,
from.executions,
from.jimpleBody,
from.errors,
from.clustersInfo
)
}

data class Step(
val stmt: Stmt,
val depth: Int,
Expand Down
27 changes: 21 additions & 6 deletions utbot-framework/src/main/kotlin/org/utbot/engine/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import kotlin.reflect.jvm.javaMethod
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentHashMapOf
import org.utbot.engine.pc.UtSolverStatusUNDEFINED
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.util.executableId
import soot.ArrayType
import soot.PrimType
import soot.RefLikeType
Expand Down Expand Up @@ -326,15 +328,28 @@ val <R> UtMethod<R>.signature: String
return "${methodName}()"
}

val ExecutableId.displayName: String
get() {
val executableName = this.name
val parameters = this.parameters.joinToString(separator = ", ") { it.canonicalName }
return "$executableName($parameters)"
}

val Constructor<*>.displayName: String
get() = executableId.displayName

val Method.displayName: String
get() = executableId.displayName

val <R> UtMethod<R>.displayName: String
get() {
val methodName = this.callable.name
val javaMethod = this.javaMethod ?: this.javaConstructor
if (javaMethod != null) {
val parameters = javaMethod.parameters.joinToString(separator = ", ") { "${it.type.canonicalName}" }
return "${methodName}($parameters)"
val executableId = this.javaMethod?.executableId ?: this.javaConstructor?.executableId
return if (executableId != null) {
executableId.displayName
} else {
val methodName = this.callable.name
return "${methodName}()"
}
return "${methodName}()"
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor
import org.utbot.framework.codegen.model.constructor.tree.TestsGenerationReport
import org.utbot.framework.codegen.model.tree.CgTestClassFile
import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer
import org.utbot.framework.plugin.api.CgMethodTestSet
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MockFramework
import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtMethodTestSet
import org.utbot.framework.plugin.api.util.id

class CodeGenerator(
private val classUnderTest: Class<*>,
params: MutableMap<UtMethod<*>, List<String>> = mutableMapOf(),
paramNames: MutableMap<ExecutableId, List<String>> = mutableMapOf(),
testFramework: TestFramework = TestFramework.defaultItem,
mockFramework: MockFramework? = MockFramework.defaultItem,
staticsMocking: StaticsMocking = StaticsMocking.defaultItem,
Expand All @@ -35,7 +36,7 @@ class CodeGenerator(
) {
private var context: CgContext = CgContext(
classUnderTest = classUnderTest.id,
paramNames = params,
paramNames = paramNames,
testFramework = testFramework,
mockFramework = mockFramework ?: MockFramework.MOCKITO,
codegenLanguage = codegenLanguage,
Expand All @@ -57,13 +58,20 @@ class CodeGenerator(
fun generateAsStringWithTestReport(
testSets: Collection<UtMethodTestSet>,
testClassCustomName: String? = null,
): TestsCodeWithTestReport =
withCustomContext(testClassCustomName) {
context.withClassScope {
val testClassFile = CgTestClassConstructor(context).construct(testSets)
TestsCodeWithTestReport(renderClassFile(testClassFile), testClassFile.testsGenerationReport)
}
}
): TestsCodeWithTestReport {
val cgTestSets = testSets.map { CgMethodTestSet(it) }.toList()
return generateAsStringWithTestReport(cgTestSets, testClassCustomName)
}

fun generateAsStringWithTestReport(
cgTestSets: List<CgMethodTestSet>,
testClassCustomName: String? = null,
): TestsCodeWithTestReport = withCustomContext(testClassCustomName) {
context.withClassScope {
val testClassFile = CgTestClassConstructor(context).construct(cgTestSets)
TestsCodeWithTestReport(renderClassFile(testClassFile), testClassFile.testsGenerationReport)
}
}

/**
* Wrapper function that configures context as needed for utbot-online:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.MockFramework
import org.utbot.framework.plugin.api.UtExecution
import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtReferenceModel
import org.utbot.framework.plugin.api.UtMethodTestSet
import java.util.IdentityHashMap
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.PersistentMap
Expand All @@ -55,7 +53,7 @@ import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.persistentSetOf
import org.utbot.framework.codegen.model.constructor.builtin.streamsDeepEqualsMethodId
import org.utbot.framework.codegen.model.tree.CgParameterKind
import org.utbot.framework.plugin.api.util.executableId
import org.utbot.framework.plugin.api.CgMethodTestSet
import org.utbot.framework.plugin.api.util.id
import org.utbot.framework.plugin.api.util.isCheckedException
import org.utbot.framework.plugin.api.util.isSubtypeOf
Expand Down Expand Up @@ -121,7 +119,7 @@ internal interface CgContextOwner {
val prevStaticFieldValues: MutableMap<FieldId, CgVariable>

// names of parameters of methods under test
val paramNames: Map<UtMethod<*>, List<String>>
val paramNames: Map<ExecutableId, List<String>>

// UtExecution we currently generate a test method for.
// It is null when no test method is being generated at the moment.
Expand Down Expand Up @@ -176,7 +174,7 @@ internal interface CgContextOwner {
// map from a set of tests for a method to another map
// which connects code generation error message
// with the number of times it occurred
val codeGenerationErrors: MutableMap<UtMethodTestSet, MutableMap<String, Int>>
val codeGenerationErrors: MutableMap<CgMethodTestSet, MutableMap<String, Int>>

// package for generated test class
val testClassPackageName: String
Expand Down Expand Up @@ -233,8 +231,8 @@ internal interface CgContextOwner {
currentBlock = currentBlock.add(it)
}

fun updateCurrentExecutable(method: UtMethod<*>) {
currentExecutable = method.callable.executableId
fun updateCurrentExecutable(executableId: ExecutableId) {
currentExecutable = executableId
}

fun addExceptionIfNeeded(exception: ClassId) {
Expand Down Expand Up @@ -399,7 +397,7 @@ internal data class CgContext(
override val testMethods: MutableList<CgTestMethod> = mutableListOf(),
override val existingMethodNames: MutableSet<String> = mutableSetOf(),
override val prevStaticFieldValues: MutableMap<FieldId, CgVariable> = mutableMapOf(),
override val paramNames: Map<UtMethod<*>, List<String>>,
override val paramNames: Map<ExecutableId, List<String>>,
override var currentExecution: UtExecution? = null,
override val testFramework: TestFramework,
override val mockFramework: MockFramework,
Expand All @@ -415,7 +413,7 @@ internal data class CgContext(
override var declaredExecutableRefs: PersistentMap<ExecutableId, CgVariable> = persistentMapOf(),
override var thisInstance: CgValue? = null,
override val methodArguments: MutableList<CgValue> = mutableListOf(),
override val codeGenerationErrors: MutableMap<UtMethodTestSet, MutableMap<String, Int>> = mutableMapOf(),
override val codeGenerationErrors: MutableMap<CgMethodTestSet, MutableMap<String, Int>> = mutableMapOf(),
override val testClassPackageName: String = classUnderTest.packageName,
override var shouldOptimizeImports: Boolean = false,
override var testClassCustomName: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import org.utbot.framework.codegen.model.constructor.util.infiniteInts
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.ConstructorId
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.util.executableId
import org.utbot.framework.plugin.api.util.isArray

/**
Expand Down Expand Up @@ -45,7 +44,7 @@ internal interface CgNameGenerator {
/**
* Generate a new test method name.
*/
fun testMethodNameFor(method: UtMethod<*>, customName: String? = null): String
fun testMethodNameFor(executableId: ExecutableId, customName: String? = null): String

/**
* Generates a new parameterized test method name by data provider method name.
Expand All @@ -55,12 +54,12 @@ internal interface CgNameGenerator {
/**
* Generates a new data for parameterized test provider method name
*/
fun dataProviderMethodNameFor(method: UtMethod<*>): String
fun dataProviderMethodNameFor(executableId: ExecutableId): String

/**
* Generate a new error method name
*/
fun errorMethodNameFor(method: UtMethod<*>): String
fun errorMethodNameFor(executableId: ExecutableId): String
}

/**
Expand All @@ -86,10 +85,10 @@ internal class CgNameGeneratorImpl(private val context: CgContext)
return variableName(baseName.decapitalize(), isMock)
}

override fun testMethodNameFor(method: UtMethod<*>, customName: String?): String {
val executableName = when (val id = method.callable.executableId) {
is ConstructorId -> id.classId.prettifiedName // TODO: maybe we need some suffix e.g. "Ctor"?
is MethodId -> id.name
override fun testMethodNameFor(executableId: ExecutableId, customName: String?): String {
val executableName = when (executableId) {
is ConstructorId -> executableId.classId.prettifiedName // TODO: maybe we need some suffix e.g. "Ctor"?
is MethodId -> executableId.name
}
// no index suffix allowed only when there's a vacant custom name
val name = if (customName != null && customName !in existingMethodNames) {
Expand All @@ -107,17 +106,17 @@ internal class CgNameGeneratorImpl(private val context: CgContext)
override fun parameterizedTestMethodName(dataProviderMethodName: String) =
dataProviderMethodName.replace(dataProviderMethodPrefix, "parameterizedTestsFor")

override fun dataProviderMethodNameFor(method: UtMethod<*>): String {
val indexedName = nextIndexedMethodName(method.callable.name.capitalize(), skipOne = true)
override fun dataProviderMethodNameFor(executableId: ExecutableId): String {
val indexedName = nextIndexedMethodName(executableId.name.capitalize(), skipOne = true)

existingMethodNames += indexedName
return "$dataProviderMethodPrefix$indexedName"
}

override fun errorMethodNameFor(method: UtMethod<*>): String {
val executableName = when (val id = method.callable.executableId) {
is ConstructorId -> id.classId.prettifiedName
is MethodId -> id.name
override fun errorMethodNameFor(executableId: ExecutableId): String {
val executableName = when (executableId) {
is ConstructorId -> executableId.classId.prettifiedName
is MethodId -> executableId.name
}
val newName = when (val base = "test${executableName.capitalize()}_errors") {
!in existingMethodNames -> base
Expand Down
Loading