1
1
package org.utbot.framework.codegen.model.constructor.tree
2
2
3
3
import org.utbot.common.PathUtil
4
+ import org.utbot.common.WorkaroundReason
4
5
import org.utbot.common.isStatic
6
+ import org.utbot.common.workaround
5
7
import org.utbot.framework.assemble.assemble
6
8
import org.utbot.framework.codegen.ForceStaticMocking
7
9
import org.utbot.framework.codegen.ParametrizedTestSource
@@ -146,7 +148,8 @@ import java.lang.reflect.InvocationTargetException
146
148
import java.security.AccessControlException
147
149
import java.lang.reflect.ParameterizedType
148
150
import org.utbot.framework.UtSettings
149
- import org.utbot.framework.plugin.api.UtStreamConsumingException
151
+ import org.utbot.framework.plugin.api.UtExecutionResult
152
+ import org.utbot.framework.plugin.api.UtStreamConsumingFailure
150
153
import org.utbot.framework.plugin.api.util.allSuperTypes
151
154
import org.utbot.framework.plugin.api.util.baseStreamClassId
152
155
import org.utbot.framework.plugin.api.util.doubleStreamClassId
@@ -183,6 +186,12 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
183
186
184
187
private val fieldsOfExecutionResults = mutableMapOf<Pair <FieldId , Int >, MutableList <UtModel >>()
185
188
189
+ /* *
190
+ * Contains whether [UtStreamConsumingFailure] is in [CgMethodTestSet] for parametrized tests.
191
+ * See [WorkaroundReason.CONSUME_DIRTY_STREAMS].
192
+ */
193
+ private var containsStreamConsumingFailureForParametrizedTests: Boolean = false
194
+
186
195
private fun setupInstrumentation () {
187
196
if (currentExecution is UtSymbolicExecution ) {
188
197
val execution = currentExecution as UtSymbolicExecution
@@ -300,28 +309,30 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
300
309
emptyLineIfNeeded()
301
310
val method = currentExecutable as MethodId
302
311
val currentExecution = currentExecution!!
312
+ val executionResult = currentExecution.result
313
+
303
314
// build assertions
304
- currentExecution.result
305
- .onSuccess { result ->
315
+ executionResult
316
+ .onSuccess { resultModel ->
306
317
methodType = SUCCESSFUL
307
318
308
- // TODO possible engine bug - void method return type and result not UtVoidModel
309
- if (result .isUnit() || method.returnType == voidClassId) {
319
+ // TODO possible engine bug - void method return type and result model not UtVoidModel
320
+ if (resultModel .isUnit() || method.returnType == voidClassId) {
310
321
+ thisInstance[method](* methodArguments.toTypedArray())
311
322
} else {
312
- resultModel = result
313
- val expected = variableConstructor.getOrCreateVariable(result , " expected" )
323
+ this . resultModel = resultModel
324
+ val expected = variableConstructor.getOrCreateVariable(resultModel , " expected" )
314
325
assertEquality(expected, actual)
315
326
}
316
327
}
317
- .onFailure { exception -> processExecutionFailure(exception) }
328
+ .onFailure { exception -> processExecutionFailure(exception, executionResult ) }
318
329
}
319
330
else -> {} // TODO: check this specific case
320
331
}
321
332
}
322
333
323
- private fun processExecutionFailure (exceptionFromAnalysis : Throwable ) {
324
- val (methodInvocationBlock, expectedException) = constructExceptionProducingBlock(exceptionFromAnalysis)
334
+ private fun processExecutionFailure (exceptionFromAnalysis : Throwable , executionResult : UtExecutionResult ) {
335
+ val (methodInvocationBlock, expectedException) = constructExceptionProducingBlock(exceptionFromAnalysis, executionResult )
325
336
326
337
when (methodType) {
327
338
SUCCESSFUL -> error(" Unexpected successful without exception method type for execution with exception $expectedException " )
@@ -355,9 +366,12 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
355
366
}
356
367
}
357
368
358
- private fun constructExceptionProducingBlock (exceptionFromAnalysis : Throwable ): Pair <() -> Unit , Throwable> {
359
- if (exceptionFromAnalysis is UtStreamConsumingException ) {
360
- return constructStreamConsumingBlock() to exceptionFromAnalysis.innerExceptionOrAny
369
+ private fun constructExceptionProducingBlock (
370
+ exceptionFromAnalysis : Throwable ,
371
+ executionResult : UtExecutionResult
372
+ ): Pair <() -> Unit , Throwable> {
373
+ if (executionResult is UtStreamConsumingFailure ) {
374
+ return constructStreamConsumingBlock() to executionResult.rootCauseException
361
375
}
362
376
363
377
return {
@@ -461,22 +475,32 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
461
475
is ConstructorId -> generateConstructorCall(currentExecutable!! , currentExecution!! )
462
476
is MethodId -> {
463
477
val method = currentExecutable as MethodId
464
- currentExecution!! .result
465
- .onSuccess { result ->
466
- if (result.isUnit()) {
478
+ val executionResult = currentExecution!! .result
479
+
480
+ executionResult
481
+ .onSuccess { resultModel ->
482
+ if (resultModel.isUnit()) {
467
483
+ thisInstance[method](* methodArguments.toTypedArray())
468
484
} else {
469
485
// "generic" expected variable is represented with a wrapper if
470
486
// actual result is primitive to support cases with exceptions.
471
- resultModel = if (result is UtPrimitiveModel ) assemble(result ) else result
487
+ this . resultModel = if (resultModel is UtPrimitiveModel ) assemble(resultModel ) else resultModel
472
488
473
489
val expectedVariable = currentMethodParameters[CgParameterKind .ExpectedResult ]!!
474
490
val expectedExpression = CgNotNullAssertion (expectedVariable)
475
491
476
492
assertEquality(expectedExpression, actual)
477
493
}
478
494
}
479
- .onFailure { thisInstance[method](* methodArguments.toTypedArray()).intercepted() }
495
+ .onFailure {
496
+ workaround(WorkaroundReason .CONSUME_DIRTY_STREAMS ) {
497
+ if (containsStreamConsumingFailureForParametrizedTests) {
498
+ constructStreamConsumingBlock().invoke()
499
+ } else {
500
+ thisInstance[method](* methodArguments.toTypedArray()).intercepted()
501
+ }
502
+ }
503
+ }
480
504
}
481
505
else -> {} // TODO: check this specific case
482
506
}
@@ -1208,7 +1232,9 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1208
1232
// we cannot generate any assertions for constructor testing
1209
1233
// but we need to generate a constructor call
1210
1234
val constructorCall = currentExecutableId as ConstructorId
1211
- currentExecution.result
1235
+ val executionResult = currentExecution.result
1236
+
1237
+ executionResult
1212
1238
.onSuccess {
1213
1239
methodType = SUCCESSFUL
1214
1240
@@ -1220,7 +1246,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1220
1246
constructorCall(* methodArguments.toTypedArray())
1221
1247
}
1222
1248
}
1223
- .onFailure { exception -> processExecutionFailure(exception) }
1249
+ .onFailure { exception -> processExecutionFailure(exception, executionResult ) }
1224
1250
}
1225
1251
1226
1252
/* *
@@ -1241,7 +1267,15 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1241
1267
actual.type.isPrimitive -> generateDeepEqualsAssertion(expected, actual)
1242
1268
else -> ifStatement(
1243
1269
CgEqualTo (expected, nullLiteral()),
1244
- trueBranch = { + testFrameworkManager.assertions[testFramework.assertNull](actual).toStatement() },
1270
+ trueBranch = {
1271
+ workaround(WorkaroundReason .CONSUME_DIRTY_STREAMS ) {
1272
+ if (containsStreamConsumingFailureForParametrizedTests) {
1273
+ constructStreamConsumingBlock().invoke()
1274
+ } else {
1275
+ + testFrameworkManager.assertions[testFramework.assertNull](actual).toStatement()
1276
+ }
1277
+ }
1278
+ },
1245
1279
falseBranch = {
1246
1280
+ testFrameworkManager.assertions[testFrameworkManager.assertNotNull](actual).toStatement()
1247
1281
generateDeepEqualsAssertion(expected, actual)
@@ -1270,21 +1304,23 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1270
1304
}
1271
1305
1272
1306
private fun recordActualResult () {
1273
- currentExecution!! .result.onSuccess { result ->
1307
+ val executionResult = currentExecution!! .result
1308
+
1309
+ executionResult.onSuccess { resultModel ->
1274
1310
when (val executable = currentExecutable) {
1275
1311
is ConstructorId -> {
1276
1312
// there is nothing to generate for constructors
1277
1313
return
1278
1314
}
1279
1315
is BuiltinMethodId -> error(" Unexpected BuiltinMethodId $currentExecutable while generating actual result" )
1280
1316
is MethodId -> {
1281
- // TODO possible engine bug - void method return type and result not UtVoidModel
1282
- if (result .isUnit() || executable.returnType == voidClassId) return
1317
+ // TODO possible engine bug - void method return type and result model not UtVoidModel
1318
+ if (resultModel .isUnit() || executable.returnType == voidClassId) return
1283
1319
1284
1320
emptyLineIfNeeded()
1285
1321
1286
1322
actual = newVar(
1287
- CgClassId (result .classId, isNullable = result is UtNullModel ),
1323
+ CgClassId (resultModel .classId, isNullable = resultModel is UtNullModel ),
1288
1324
" actual"
1289
1325
) {
1290
1326
thisInstance[executable](* methodArguments.toTypedArray())
@@ -1293,13 +1329,13 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1293
1329
else -> {} // TODO: check this specific case
1294
1330
}
1295
1331
}.onFailure {
1296
- processActualInvocationFailure(it )
1332
+ processActualInvocationFailure(executionResult )
1297
1333
}
1298
1334
}
1299
1335
1300
- private fun processActualInvocationFailure (e : Throwable ) {
1301
- when (e ) {
1302
- is UtStreamConsumingException -> processStreamConsumingException(e.innerExceptionOrAny )
1336
+ private fun processActualInvocationFailure (executionResult : UtExecutionResult ) {
1337
+ when (executionResult ) {
1338
+ is UtStreamConsumingFailure -> processStreamConsumingException(executionResult.rootCauseException )
1303
1339
else -> {} // Do nothing for now
1304
1340
}
1305
1341
}
@@ -1423,6 +1459,12 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
1423
1459
// may be a heuristic to select a model with minimal number of internal nulls should be used
1424
1460
val genericExecution = chooseGenericExecution(testSet.executions)
1425
1461
1462
+ workaround(WorkaroundReason .CONSUME_DIRTY_STREAMS ) {
1463
+ containsStreamConsumingFailureForParametrizedTests = testSet.executions.any {
1464
+ it.result is UtStreamConsumingFailure
1465
+ }
1466
+ }
1467
+
1426
1468
val statics = genericExecution.stateBefore.statics
1427
1469
1428
1470
return withTestMethodScope(genericExecution) {
0 commit comments