Skip to content

Commit aa70070

Browse files
committed
Generate separated parametrized tests for test sets with different result type
1 parent 45e687e commit aa70070

File tree

4 files changed

+84
-29
lines changed

4 files changed

+84
-29
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.utbot.framework.plugin.api.util.isPrimitive
2929
import org.utbot.framework.plugin.api.util.jClass
3030
import org.utbot.framework.plugin.api.util.longClassId
3131
import org.utbot.framework.plugin.api.util.method
32+
import org.utbot.framework.plugin.api.util.objectClassId
3233
import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull
3334
import org.utbot.framework.plugin.api.util.shortClassId
3435
import org.utbot.framework.plugin.api.util.toReferenceTypeBytecodeSignature
@@ -100,20 +101,63 @@ data class UtMethodTestSet(
100101

101102
data class CgMethodTestSet private constructor(
102103
val executableId: ExecutableId,
103-
val executions: List<UtExecution> = emptyList(),
104104
val jimpleBody: JimpleBody? = null,
105105
val errors: Map<String, Int> = emptyMap(),
106-
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
106+
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>>,
107107
) {
108+
var executions: List<UtExecution> = emptyList()
109+
private set
110+
108111
constructor(from: UtMethodTestSet) : this(
109112
from.method.callable.executableId,
110-
from.executions,
111113
from.jimpleBody,
112114
from.errors,
113115
from.clustersInfo
114-
)
116+
) {
117+
executions = from.executions
118+
}
119+
120+
/**
121+
* Splits [CgMethodTestSet] into separate test sets having
122+
* unique result model [ClassId] in each subset.
123+
*/
124+
fun splitExecutionsByResult() : List<CgMethodTestSet> {
125+
val successfulExecutions = executions.filter { it.result is UtExecutionSuccess }
126+
val executionsByResult: Map<ClassId, List<UtExecution>> =
127+
if (successfulExecutions.any()) {
128+
successfulExecutions.groupBy { (it.result as UtExecutionSuccess).model.classId }
129+
} else {
130+
mapOf(objectClassId to executions)
131+
}
132+
133+
return executionsByResult.map{ (_, executions) -> substituteExecutions(executions) }
134+
}
135+
136+
/**
137+
* Finds a [ClassId] of all result models in executions.
138+
*
139+
* Tries to find an unique result type in testSets or
140+
* gets executable return type.
141+
*/
142+
fun resultType(): ClassId {
143+
val successfulExecutions = executions.filter { it.result is UtExecutionSuccess }
144+
return if (successfulExecutions.any()) {
145+
successfulExecutions
146+
.map { (it.result as UtExecutionSuccess).model.classId }
147+
.distinct()
148+
.singleOrNull()
149+
?: executableId.returnType
150+
} else {
151+
executableId.returnType
152+
}
153+
}
154+
155+
private fun substituteExecutions(newExecutions: List<UtExecution>): CgMethodTestSet =
156+
this.copy().apply { executions = newExecutions }
157+
115158
}
116159

160+
117161
data class Step(
118162
val stmt: Stmt,
119163
val depth: Int,

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,9 +1265,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12651265
currentMethodParameters[CgParameterKind.Argument(index)] = argument.parameter
12661266
}
12671267

1268-
val method = currentExecutable!!
1269-
val expectedResultClassId = wrapTypeIfRequired(method.returnType)
1270-
1268+
val expectedResultClassId = wrapTypeIfRequired(testSet.resultType())
12711269
if (expectedResultClassId != voidClassId) {
12721270
val wrappedType = wrapIfPrimitive(expectedResultClassId)
12731271
//We are required to wrap the type of expected result if it is primitive

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ internal class CgTestClassConstructor(val context: CgContext) :
8383
return null
8484
}
8585

86-
val (methodUnderTest, executions, _, _, clustersInfo) = testSet
86+
val (methodUnderTest, _, _, clustersInfo) = testSet
8787
val regions = mutableListOf<CgRegion<CgMethod>>()
8888
val requiredFields = mutableListOf<CgParameterDeclaration>()
8989

@@ -94,7 +94,7 @@ internal class CgTestClassConstructor(val context: CgContext) :
9494
emptyLineIfNeeded()
9595
for (i in executionIndices) {
9696
runCatching {
97-
currentTestCaseTestMethods += methodConstructor.createTestMethod(methodUnderTest, executions[i])
97+
currentTestCaseTestMethods += methodConstructor.createTestMethod(methodUnderTest, testSet.executions[i])
9898
}.onFailure { e -> processFailure(testSet, e) }
9999
}
100100
val clusterHeader = clusterSummary?.header
@@ -107,22 +107,9 @@ internal class CgTestClassConstructor(val context: CgContext) :
107107
}
108108
}
109109
ParametrizedTestSource.PARAMETRIZE -> {
110-
runCatching {
111-
val dataProviderMethodName = nameGenerator.dataProviderMethodNameFor(testSet.executableId)
112-
113-
val parameterizedTestMethod =
114-
methodConstructor.createParameterizedTestMethod(testSet, dataProviderMethodName)
115-
116-
requiredFields += parameterizedTestMethod.requiredFields
117-
118-
cgDataProviderMethods +=
119-
methodConstructor.createParameterizedTestDataProvider(testSet, dataProviderMethodName)
120-
121-
regions += CgSimpleRegion(
122-
"Parameterized test for method ${methodUnderTest.displayName}",
123-
listOf(parameterizedTestMethod),
124-
)
125-
}.onFailure { error -> processFailure(testSet, error) }
110+
for (currentTestSet in testSet.splitExecutionsByResult()) {
111+
createParametrizedTestAndDataProvider(currentTestSet, requiredFields, regions, methodUnderTest)
112+
}
126113
}
127114
}
128115

@@ -141,6 +128,30 @@ internal class CgTestClassConstructor(val context: CgContext) :
141128
.merge(failure.description, 1, Int::plus)
142129
}
143130

131+
private fun createParametrizedTestAndDataProvider(
132+
testSet: CgMethodTestSet,
133+
requiredFields: MutableList<CgParameterDeclaration>,
134+
regions: MutableList<CgRegion<CgMethod>>,
135+
methodUnderTest: ExecutableId,
136+
) {
137+
runCatching {
138+
val dataProviderMethodName = nameGenerator.dataProviderMethodNameFor(testSet.executableId)
139+
140+
val parameterizedTestMethod =
141+
methodConstructor.createParameterizedTestMethod(testSet, dataProviderMethodName)
142+
143+
requiredFields += parameterizedTestMethod.requiredFields
144+
145+
cgDataProviderMethods +=
146+
methodConstructor.createParameterizedTestDataProvider(testSet, dataProviderMethodName)
147+
148+
regions += CgSimpleRegion(
149+
"Parameterized test for method ${methodUnderTest.displayName}",
150+
listOf(parameterizedTestMethod),
151+
)
152+
}.onFailure { error -> processFailure(testSet, error) }
153+
}
154+
144155
// TODO: collect imports of util methods
145156
private fun createUtilMethods(): List<CgUtilMethod> {
146157
val utilMethods = mutableListOf<CgUtilMethod>()

utbot-framework/src/test/kotlin/org/utbot/framework/codegen/TestCodeGeneratorPipeline.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,12 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
129129
"Errors regions has been generated: $errorText"
130130
}
131131

132-
require(generatedMethodsCount == expectedNumberOfGeneratedMethods) {
133-
"Something went wrong during the code generation for ${classUnderTest.simpleName}. " +
134-
"Expected to generate $expectedNumberOfGeneratedMethods test methods, " +
135-
"but got only $generatedMethodsCount"
132+
if (parametrizedTestSource != ParametrizedTestSource.PARAMETRIZE) {
133+
require(generatedMethodsCount == expectedNumberOfGeneratedMethods) {
134+
"Something went wrong during the code generation for ${classUnderTest.simpleName}. " +
135+
"Expected to generate $expectedNumberOfGeneratedMethods test methods, " +
136+
"but got only $generatedMethodsCount"
137+
}
136138
}
137139
}.onFailure {
138140
val classes = listOf(classPipeline).retrieveClasses()

0 commit comments

Comments
 (0)