Skip to content

Commit e7830e6

Browse files
committed
New treating of Overflows
1 parent 295ede5 commit e7830e6

File tree

13 files changed

+97
-12
lines changed

13 files changed

+97
-12
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.utbot.engine
2+
3+
/**
4+
* Represents an error that may be detected or not
5+
* during analysis in accordance with custom settings.
6+
*
7+
* Usually execution may be continued somehow after such error,
8+
* but the result may be different from basic expectations.
9+
*/
10+
sealed class ArtificialError(message: String): Error(message)
11+
12+
/**
13+
* Represents overflow detection errors in symbolic engine,
14+
* if a mode to detect them is turned on.
15+
*
16+
* See [TraversalContext.intOverflowCheck] for more details.
17+
*/
18+
class OverflowDetectionError(message: String): ArtificialError(message)

utbot-framework/src/main/kotlin/org/utbot/engine/DataClasses.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ fun explicitThrown(exception: Throwable, addr: UtAddrExpression, inNestedMethod:
6363
/**
6464
* Implicitly thrown exception. There are no difference if it happens in nested call or not.
6565
*/
66-
fun implicitThrown(exception: Throwable, addr: UtAddrExpression, inNestedMethod: Boolean) =
67-
SymbolicFailure(symbolic(exception, addr), exception, explicit = false, inNestedMethod = inNestedMethod)
66+
fun implicitThrown(throwable: Throwable, addr: UtAddrExpression, inNestedMethod: Boolean) =
67+
SymbolicFailure(symbolic(throwable, addr), throwable, explicit = false, inNestedMethod = inNestedMethod)
6868

69-
private fun symbolic(exception: Throwable, addr: UtAddrExpression) =
70-
objectValue(Scene.v().getRefType(exception.javaClass.canonicalName), addr, ThrowableWrapper(exception))
69+
private fun symbolic(throwable: Throwable, addr: UtAddrExpression) =
70+
objectValue(Scene.v().getRefType(throwable.javaClass.canonicalName), addr, ThrowableWrapper(throwable))
7171

7272
private fun extractConcrete(symbolic: SymbolicValue) =
7373
(symbolic.asWrapperOrNull as? ThrowableWrapper)?.throwable

utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,9 @@ class Resolver(
390390
return if (explicit) {
391391
UtExplicitlyThrownException(exception, inNestedMethod)
392392
} else {
393-
when {
394-
// TODO SAT-1561
395-
exception is ArithmeticException && exception.message?.contains("overflow") == true -> UtOverflowFailure(exception)
396-
exception is AccessControlException -> UtSandboxFailure(exception)
393+
when (exception) {
394+
is OverflowDetectionError -> UtOverflowFailure(exception)
395+
is AccessControlException -> UtSandboxFailure(exception)
397396
else -> UtImplicitlyThrownException(exception, inNestedMethod)
398397
}
399398
}

utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,10 @@ class Traverser(
23002300
exception: SymbolicFailure,
23012301
conditions: Set<UtBoolExpression>
23022302
): Boolean {
2303+
if (exception.concrete is ArtificialError) {
2304+
return false
2305+
}
2306+
23032307
val classId = exception.fold(
23042308
{ it.javaClass.id },
23052309
{ (exception.symbolic as ObjectValue).type.id }
@@ -3406,7 +3410,7 @@ class Traverser(
34063410
}
34073411

34083412
if (overflow != null) {
3409-
implicitlyThrowException(ArithmeticException("${left.type} ${op.symbol} overflow"), setOf(overflow))
3413+
implicitlyThrowException(OverflowDetectionError("${left.type} ${op.symbol} overflow"), setOf(overflow))
34103414
queuedSymbolicStateUpdates += mkNot(overflow).asHardConstraint()
34113415
}
34123416
}
@@ -3482,13 +3486,13 @@ class Traverser(
34823486
}
34833487

34843488
private fun TraversalContext.implicitlyThrowException(
3485-
exception: Exception,
3489+
throwable: Throwable,
34863490
conditions: Set<UtBoolExpression>,
34873491
softConditions: Set<UtBoolExpression> = emptySet()
34883492
) {
34893493
if (environment.state.executionStack.last().doesntThrow) return
34903494

3491-
val symException = implicitThrown(exception, findNewAddr(), environment.state.isInNestedMethod())
3495+
val symException = implicitThrown(throwable, findNewAddr(), environment.state.isInNestedMethod())
34923496
if (!traverseCatchBlock(environment.state.stmt, symException, conditions)) {
34933497
environment.state.expectUndefined()
34943498
val nextState = createExceptionStateQueued(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/Domain.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ abstract class TestFramework(
178178
abstract val mainPackage: String
179179
abstract val assertionsClass: ClassId
180180
abstract val arraysAssertionsClass: ClassId
181+
abstract val kotlinFailureAssertionsClass: ClassId
181182
abstract val testAnnotation: String
182183
abstract val testAnnotationId: ClassId
183184
abstract val testAnnotationFqn: String
@@ -226,11 +227,19 @@ abstract class TestFramework(
226227

227228
val assertNotEquals by lazy { assertionId("assertNotEquals", objectClassId, objectClassId) }
228229

230+
val fail by lazy { assertionId("fail", objectClassId) }
231+
232+
val kotlinFail by lazy { kotlinFailAssertionId("fail", objectClassId) }
233+
229234
protected open fun assertionId(name: String, vararg params: ClassId): MethodId =
230235
builtinStaticMethodId(assertionsClass, name, voidClassId, *params)
236+
231237
private fun arrayAssertionId(name: String, vararg params: ClassId): MethodId =
232238
builtinStaticMethodId(arraysAssertionsClass, name, voidClassId, *params)
233239

240+
private fun kotlinFailAssertionId(name: String, vararg params: ClassId): MethodId =
241+
builtinStaticMethodId(kotlinFailureAssertionsClass, name, voidClassId, *params)
242+
234243
abstract fun getRunTestsCommand(
235244
executionInvoke: String,
236245
classPath: String,
@@ -272,6 +281,8 @@ object TestNg : TestFramework(id = "TestNG",displayName = "TestNG") {
272281
simpleName = "ArrayAsserts"
273282
)
274283

284+
override val kotlinFailureAssertionsClass = assertionsClass
285+
275286
override val assertBooleanArrayEquals by lazy { assertionId("assertEquals", booleanArrayClassId, booleanArrayClassId) }
276287

277288
val throwingRunnableClassId = BuiltinClassId(
@@ -389,6 +400,7 @@ object Junit4 : TestFramework(id = "JUnit4",displayName = "JUnit 4") {
389400
simpleName = "Assert"
390401
)
391402
override val arraysAssertionsClass = assertionsClass
403+
override val kotlinFailureAssertionsClass = assertionsClass
392404

393405
val ignoreAnnotationClassId = with("$JUNIT4_PACKAGE.Ignore") {
394406
BuiltinClassId(
@@ -485,6 +497,11 @@ object Junit5 : TestFramework(id = "JUnit5", displayName = "JUnit 5") {
485497

486498
override val arraysAssertionsClass = assertionsClass
487499

500+
override val kotlinFailureAssertionsClass = BuiltinClassId(
501+
canonicalName = "org.junit.jupiter.api",
502+
simpleName = "Assertions"
503+
)
504+
488505
val assertThrows = builtinStaticMethodId(
489506
classId = assertionsClass,
490507
name = "assertThrows",

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/CgElement.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ enum class CgTestMethodType(val displayName: String, val isThrowing: Boolean) {
309309
PASSED_EXCEPTION(displayName = "Thrown exceptions marked as passed", isThrowing = true),
310310
FAILING(displayName = "Failing tests (with exceptions)", isThrowing = true),
311311
TIMEOUT(displayName = "Failing tests (with timeout)", isThrowing = true),
312+
ARTIFICIAL(displayName = "Failing tests (with custom exception)", isThrowing = true),
312313
CRASH(displayName = "Possibly crashing tests", isThrowing = true),
313314
PARAMETRIZED(displayName = "Parametrized tests", isThrowing = false);
314315

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/reports/TestsGenerationReport.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ data class TestsGenerationReport(
1616
var successfulExecutions: MethodGeneratedTests = mutableMapOf(),
1717
var timeoutExecutions: MethodGeneratedTests = mutableMapOf(),
1818
var failedExecutions: MethodGeneratedTests = mutableMapOf(),
19+
var artificiallyFailedExecutions: MethodGeneratedTests = mutableMapOf(),
1920
var crashExecutions: MethodGeneratedTests = mutableMapOf(),
2021
var errors: MutableMap<ExecutableId, ErrorsCount> = mutableMapOf()
2122
) {
@@ -59,6 +60,7 @@ data class TestsGenerationReport(
5960
when (it.type) {
6061
CgTestMethodType.SUCCESSFUL, CgTestMethodType.PASSED_EXCEPTION -> updateExecutions(it, successfulExecutions)
6162
CgTestMethodType.FAILING -> updateExecutions(it, failedExecutions)
63+
CgTestMethodType.ARTIFICIAL -> updateExecutions(it, artificiallyFailedExecutions)
6264
CgTestMethodType.TIMEOUT -> updateExecutions(it, timeoutExecutions)
6365
CgTestMethodType.CRASH -> updateExecutions(it, crashExecutions)
6466
CgTestMethodType.PARAMETRIZED -> {

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/TestFrameworkManager.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ abstract class TestFrameworkManager(val context: CgContext)
6666
val assertTrue = context.testFramework.assertTrue
6767
val assertFalse = context.testFramework.assertFalse
6868

69+
val fail = context.testFramework.fail
70+
val kotlinFail = context.testFramework.kotlinFail
71+
6972
val assertArrayEquals = context.testFramework.assertArrayEquals
7073
val assertBooleanArrayEquals = context.testFramework.assertBooleanArrayEquals
7174
val assertByteArrayEquals = context.testFramework.assertByteArrayEquals
@@ -173,6 +176,13 @@ abstract class TestFrameworkManager(val context: CgContext)
173176

174177
fun assertBoolean(actual: CgExpression) = assertBoolean(expected = true, actual)
175178

179+
fun fail(actual: CgExpression) {
180+
when (codegenLanguage) {
181+
CodegenLanguage.JAVA -> +assertions[fail](actual)
182+
CodegenLanguage.KOTLIN -> +assertions[kotlinFail](actual)
183+
}
184+
}
185+
176186
// Exception expectation differs between test frameworks
177187
// JUnit4 requires to add a specific argument to the test method annotation
178188
// JUnit5 requires using method assertThrows()

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import org.utbot.common.PathUtil
44
import org.utbot.common.WorkaroundReason
55
import org.utbot.common.isStatic
66
import org.utbot.common.workaround
7+
import org.utbot.engine.ArtificialError
8+
import org.utbot.engine.OverflowDetectionError
79
import org.utbot.framework.assemble.assemble
810
import org.utbot.framework.codegen.domain.ForceStaticMocking
911
import org.utbot.framework.codegen.domain.ParametrizedTestSource
@@ -141,6 +143,7 @@ import org.utbot.framework.codegen.tree.CgTestClassConstructor.CgComponents.getS
141143
import org.utbot.framework.codegen.tree.CgTestClassConstructor.CgComponents.getTestFrameworkManagerBy
142144
import org.utbot.framework.codegen.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy
143145
import org.utbot.framework.plugin.api.UtExecutionResult
146+
import org.utbot.framework.plugin.api.UtOverflowFailure
144147
import org.utbot.framework.plugin.api.UtStreamConsumingFailure
145148
import org.utbot.framework.plugin.api.util.allSuperTypes
146149
import org.utbot.framework.plugin.api.util.baseStreamClassId
@@ -350,6 +353,12 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte
350353
}
351354
else -> error("Unexpected crash suite for failing execution with $expectedException exception")
352355
}
356+
ARTIFICIAL -> {
357+
methodInvocationBlock()
358+
359+
val failureMessage = prepareArtificialFailureMessage(executionResult)
360+
testFrameworkManager.fail(failureMessage)
361+
}
353362
FAILING -> {
354363
writeWarningAboutFailureTest(expectedException)
355364
methodInvocationBlock()
@@ -358,6 +367,25 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte
358367
}
359368
}
360369

370+
//TODO: ISSUE-1546 introduce some kind of language-specific string interpolation in Codegen
371+
private fun prepareArtificialFailureMessage(executionResult: UtExecutionResult): CgVariable {
372+
when (executionResult) {
373+
is UtOverflowFailure -> {
374+
val preparedMethodArguments = methodArguments.joinToString(separator = ", ") {
375+
when (it) {
376+
is CgVariable -> it.name
377+
is CgLiteral -> it.value.toString()
378+
else -> it.toString()
379+
}
380+
}
381+
382+
val failureMessage = "\"Overflow detected in \'${currentExecutable!!.name}\' call with arguments $preparedMethodArguments \""
383+
return CgVariable(failureMessage, stringClassId)
384+
}
385+
else -> error("$executionResult is not supported in artificial errors")
386+
}
387+
}
388+
361389
private fun constructExceptionProducingBlock(
362390
exceptionFromAnalysis: Throwable,
363391
executionResult: UtExecutionResult
@@ -405,6 +433,7 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte
405433
if (exception is AccessControlException) return false
406434
// tests with timeout or crash should be processed differently
407435
if (exception is TimeoutException || exception is ConcreteExecutionFailureException) return false
436+
if (exception is OverflowDetectionError) return false
408437
if (UtSettings.treatAssertAsErrorSuite && exception is AssertionError) return false
409438

410439
val exceptionRequiresAssert = exception !is RuntimeException || runtimeExceptionTestsBehaviour == PASS
@@ -1796,6 +1825,7 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte
17961825
shouldTestPassWithException(currentExecution, exception) -> PASSED_EXCEPTION
17971826
shouldTestPassWithTimeoutException(currentExecution, exception) -> TIMEOUT
17981827
else -> when (exception) {
1828+
is ArtificialError -> ARTIFICIAL
17991829
is ConcreteExecutionFailureException -> CRASH
18001830
is AccessControlException -> CRASH // exception from sandbox
18011831
else -> FAILING

utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.utbot.framework.plugin.api.UtVoidModel
2929
* * Regression suite
3030
* * Error suite (invocations in which implicitly thrown unchecked exceptions reached to the top)
3131
* * Crash suite (invocations in which the instrumented process crashed or unexpected exception in our code occurred)
32+
* * Artificial error suite (invocations in which some custom exception like overflow detection occurred)
3233
* * Timeout suite
3334
*
3435
* We want to minimize tests independently in each of these suites.

utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ private val classesToLoad = arrayOf(
197197
org.utbot.engine.overrides.stream.IntStream::class,
198198
org.utbot.engine.overrides.stream.LongStream::class,
199199
org.utbot.engine.overrides.stream.DoubleStream::class,
200+
org.utbot.engine.OverflowDetectionError::class,
200201
).map { it.java }.toTypedArray()
201202

202203
private const val UTBOT_PACKAGE_PREFIX = "org.utbot"

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class EngineProcess private constructor(val project: Project, private val classN
9595
private fun suspendValue(): String = if (UtSettings.suspendEngineProcessExecutionInDebugMode) "y" else "n"
9696

9797
private val debugArgument: String?
98-
get() = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue()},quiet=y,address=${UtSettings.engineProcessDebugPort}"
98+
get() = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=${suspendValue()},quiet=y,address=${UtSettings.engineProcessDebugPort}"
9999
.takeIf { UtSettings.runEngineProcessWithDebug }
100100

101101
private val javaExecutablePathString: Path

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/PythonDomain.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ object Pytest : TestFramework(displayName = "pytest", id = "pytest") {
1515
override val mainPackage: String = "pytest"
1616
override val assertionsClass: ClassId = pythonNoneClassId
1717
override val arraysAssertionsClass: ClassId = assertionsClass
18+
override val kotlinFailureAssertionsClass: ClassId = assertionsClass
1819
override val testAnnotation: String
1920
get() = TODO("Not yet implemented")
2021
override val testAnnotationId: ClassId = BuiltinClassId(
@@ -51,6 +52,7 @@ object Unittest : TestFramework(displayName = "Unittest", id = "Unittest") {
5152
override val mainPackage: String = "unittest"
5253
override val assertionsClass: ClassId = PythonClassId("self")
5354
override val arraysAssertionsClass: ClassId = assertionsClass
55+
override val kotlinFailureAssertionsClass: ClassId = assertionsClass
5456
override val testAnnotation: String = ""
5557
override val testAnnotationId: ClassId = BuiltinClassId(
5658
canonicalName = "Unittest",

0 commit comments

Comments
 (0)