Skip to content

Commit faa6506

Browse files
committed
Improve exception rendering in parametrized tests
1 parent f5132f7 commit faa6506

File tree

6 files changed

+72
-35
lines changed

6 files changed

+72
-35
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ internal interface CgContextOwner {
171171
// a variable representing an actual result of the method under test call
172172
var actual: CgVariable
173173

174+
//a variable representing an expected error in parametrized tests
175+
var expectedErrorVariable: CgVariable
176+
177+
// a variable representing if test method contains reflective call or not
178+
// and should we catch exceptions like InvocationTargetException or not so on
179+
var containsReflectiveCall: Boolean
180+
174181
// map from a set of tests for a method to another map
175182
// which connects code generation error message
176183
// with the number of times it occurred
@@ -420,10 +427,12 @@ internal data class CgContext(
420427
override val runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour =
421428
RuntimeExceptionTestsBehaviour.defaultItem,
422429
override val hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(),
423-
override val enableTestsTimeout: Boolean = true
430+
override val enableTestsTimeout: Boolean = true,
431+
override var containsReflectiveCall: Boolean = false,
424432
) : CgContextOwner {
425433
override lateinit var statesCache: EnvironmentFieldStateCache
426434
override lateinit var actual: CgVariable
435+
override lateinit var expectedErrorVariable: CgVariable
427436

428437
override val currentTestClass: ClassId by lazy {
429438
val packagePrefix = if (testClassPackageName.isNotEmpty()) "$testClassPackageName." else ""

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
359359
}
360360

361361
private fun MethodId.callWithReflection(caller: CgExpression?, args: List<CgExpression>): CgMethodCall {
362+
containsReflectiveCall = true
362363
val method = declaredExecutableRefs[this]
363364
?: toExecutableVariable(args).also {
364365
declaredExecutableRefs = declaredExecutableRefs.put(this, it)
@@ -372,6 +373,7 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
372373
}
373374

374375
private fun ConstructorId.callWithReflection(args: List<CgExpression>): CgExecutableCall {
376+
containsReflectiveCall = true
375377
val constructor = declaredExecutableRefs[this]
376378
?: this.toExecutableVariable(args).also {
377379
declaredExecutableRefs = declaredExecutableRefs.put(this, it)

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

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.utbot.framework.codegen.model.tree.CgExecutableCall
4141
import org.utbot.framework.codegen.model.tree.CgExpression
4242
import org.utbot.framework.codegen.model.tree.CgFieldAccess
4343
import org.utbot.framework.codegen.model.tree.CgGetJavaClass
44+
import org.utbot.framework.codegen.model.tree.CgIsInstance
4445
import org.utbot.framework.codegen.model.tree.CgLiteral
4546
import org.utbot.framework.codegen.model.tree.CgMethod
4647
import org.utbot.framework.codegen.model.tree.CgMethodCall
@@ -1195,20 +1196,6 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
11951196
val testName = nameGenerator.parameterizedTestMethodName(dataProviderMethodName)
11961197
withNameScope {
11971198
val testParameterDeclarations = createParameterDeclarations(testSet, genericExecution)
1198-
val mainBody = {
1199-
substituteStaticFields(statics, isParametrized = true)
1200-
// build this instance
1201-
thisInstance = genericExecution.stateBefore.thisInstance?.let { currentMethodParameters[CgParameterKind.ThisInstance] }
1202-
1203-
// build arguments for method under test and parameterized test
1204-
for (index in genericExecution.stateBefore.parameters.indices) {
1205-
methodArguments += currentMethodParameters[CgParameterKind.Argument(index)]!!
1206-
}
1207-
1208-
//record result and generate result assertions
1209-
recordActualResult()
1210-
generateAssertionsForParameterizedTest()
1211-
}
12121199

12131200
methodType = PARAMETRIZED
12141201
testMethod(
@@ -1219,20 +1206,36 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12191206
dataProviderMethodName
12201207
) {
12211208
rememberInitialStaticFields(statics)
1209+
substituteStaticFields(statics, isParametrized = true)
1210+
1211+
// build this instance
1212+
thisInstance = genericExecution.stateBefore.thisInstance?.let { currentMethodParameters[CgParameterKind.ThisInstance] }
1213+
1214+
// build arguments for method under test and parameterized test
1215+
for (index in genericExecution.stateBefore.parameters.indices) {
1216+
methodArguments += currentMethodParameters[CgParameterKind.Argument(index)]!!
1217+
}
12221218

12231219
if (containsFailureExecution(testSet) || statics.isNotEmpty()) {
12241220
var currentTryBlock = tryBlock {
1225-
mainBody()
1221+
recordActualResult()
1222+
generateAssertionsForParameterizedTest()
12261223
}
12271224

12281225
if (containsFailureExecution(testSet)) {
1229-
currentTryBlock = currentTryBlock.catch(Throwable::class.java.id) { e ->
1230-
val pseudoExceptionVarName = when (codegenLanguage) {
1231-
CodegenLanguage.JAVA -> "${expectedErrorVarName}.isInstance(${e.name.decapitalize()})"
1232-
CodegenLanguage.KOTLIN -> "${expectedErrorVarName}!!.isInstance(${e.name.decapitalize()})"
1226+
currentTryBlock =
1227+
if (containsReflectiveCall) {
1228+
currentTryBlock.catch(InvocationTargetException::class.java.id) { exception ->
1229+
testFrameworkManager.assertBoolean(
1230+
CgIsInstance(expectedErrorVariable, exception[getTargetException]())
1231+
)
1232+
}
1233+
} else {
1234+
currentTryBlock.catch(Throwable::class.java.id) { throwable ->
1235+
testFrameworkManager.assertBoolean(
1236+
CgIsInstance(expectedErrorVariable, throwable)
1237+
)
12331238
}
1234-
1235-
testFrameworkManager.assertBoolean(CgVariable(pseudoExceptionVarName, booleanClassId))
12361239
}
12371240
}
12381241

@@ -1243,7 +1246,8 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12431246
}
12441247
+currentTryBlock
12451248
} else {
1246-
mainBody()
1249+
recordActualResult()
1250+
generateAssertionsForParameterizedTest()
12471251
}
12481252
}
12491253
}
@@ -1329,20 +1333,19 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
13291333
val containsFailureExecution = containsFailureExecution(testSet)
13301334
if (containsFailureExecution) {
13311335
val classClassId = Class::class.id
1332-
val expectedException = CgParameterDeclaration(
1333-
parameter = declareParameter(
1334-
type = BuiltinClassId(
1335-
name = classClassId.name,
1336-
simpleName = classClassId.simpleName,
1337-
canonicalName = classClassId.canonicalName,
1338-
packageName = classClassId.packageName,
1339-
typeParameters = TypeParameters(listOf(Throwable::class.java.id))
1340-
),
1341-
name = nameGenerator.variableName(expectedErrorVarName)
1336+
expectedErrorVariable = declareParameter(
1337+
type = BuiltinClassId(
1338+
name = classClassId.name,
1339+
simpleName = classClassId.simpleName,
1340+
canonicalName = classClassId.canonicalName,
1341+
packageName = classClassId.packageName,
1342+
typeParameters = TypeParameters(listOf(Throwable::class.java.id))
13421343
),
1343-
// exceptions are always reference type
1344-
isReferenceType = true
1344+
name = nameGenerator.variableName(expectedErrorVarName)
13451345
)
1346+
1347+
// exceptions are always reference type
1348+
val expectedException = CgParameterDeclaration(parameter = expectedErrorVariable, isReferenceType = true)
13461349
this += expectedException
13471350
currentMethodParameters[CgParameterKind.ExpectedException] = expectedException.parameter
13481351
}
@@ -1466,6 +1469,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
14661469
thisInstance = null
14671470
methodArguments.clear()
14681471
currentExecution = null
1472+
containsReflectiveCall = false
14691473
mockFrameworkManager.clearExecutionResources()
14701474
currentMethodParameters.clear()
14711475
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ interface CgElement {
7575
is CgDeclaration -> visit(element)
7676
is CgAssignment -> visit(element)
7777
is CgTypeCast -> visit(element)
78+
is CgIsInstance -> visit(element)
7879
is CgThisInstance -> visit(element)
7980
is CgNotNullAssertion -> visit(element)
8081
is CgVariable -> visit(element)
@@ -537,6 +538,13 @@ class CgTypeCast(
537538
override val type: ClassId = targetType
538539
}
539540

541+
class CgIsInstance(
542+
val thisExpr: CgExpression,
543+
val typeExpr: CgExpression,
544+
) : CgExpression {
545+
override val type: ClassId = booleanClassId
546+
}
547+
540548
// Value
541549

542550
// TODO in general CgLiteral is not CgReferenceExpression because it can hold primitive values

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import org.utbot.framework.codegen.model.tree.CgGreaterThan
3939
import org.utbot.framework.codegen.model.tree.CgIfStatement
4040
import org.utbot.framework.codegen.model.tree.CgIncrement
4141
import org.utbot.framework.codegen.model.tree.CgInnerBlock
42+
import org.utbot.framework.codegen.model.tree.CgIsInstance
4243
import org.utbot.framework.codegen.model.tree.CgLessThan
4344
import org.utbot.framework.codegen.model.tree.CgLiteral
4445
import org.utbot.framework.codegen.model.tree.CgLogicalAnd
@@ -422,6 +423,15 @@ internal abstract class CgAbstractRenderer(val context: CgContext, val printer:
422423
print("${element.variable.name}--")
423424
}
424425

426+
// isInstance check
427+
428+
override fun visit(element: CgIsInstance) {
429+
element.thisExpr.accept(this)
430+
print(".isInstance(")
431+
element.typeExpr.accept(this)
432+
print(")")
433+
}
434+
425435
// Try-catch
426436

427437
override fun visit(element: CgTryCatch) {

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgVisitor.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import org.utbot.framework.codegen.model.tree.CgGreaterThan
4242
import org.utbot.framework.codegen.model.tree.CgIfStatement
4343
import org.utbot.framework.codegen.model.tree.CgIncrement
4444
import org.utbot.framework.codegen.model.tree.CgInnerBlock
45+
import org.utbot.framework.codegen.model.tree.CgIsInstance
4546
import org.utbot.framework.codegen.model.tree.CgLessThan
4647
import org.utbot.framework.codegen.model.tree.CgLiteral
4748
import org.utbot.framework.codegen.model.tree.CgLogicalAnd
@@ -180,6 +181,9 @@ interface CgVisitor<R> {
180181
// Type cast
181182
fun visit(element: CgTypeCast): R
182183

184+
// isInstance check
185+
fun visit(element: CgIsInstance): R
186+
183187
// This instance
184188
fun visit(element: CgThisInstance): R
185189

0 commit comments

Comments
 (0)