diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt index c96347f4c7..65cbf07251 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt @@ -27,6 +27,8 @@ import org.utbot.framework.plugin.api.util.objectClassId import org.utbot.framework.plugin.api.util.shortArrayClassId import org.utbot.framework.plugin.api.util.voidClassId import java.io.File +import org.utbot.framework.plugin.api.util.longClassId +import org.utbot.framework.plugin.api.util.voidWrapperClassId data class TestClassFile(val packageName: String, val imports: List, val testClass: String) @@ -410,6 +412,19 @@ object Junit5 : TestFramework("JUnit5") { simpleName = "TimeUnit" ) + val durationClassId = BuiltinClassId( + name = "Duration", + canonicalName = "java.time.Duration", + simpleName = "Duration" + ) + + val ofMillis = builtinStaticMethodId( + classId = durationClassId, + name = "ofMillis", + returnType = durationClassId, + arguments = arrayOf(longClassId) + ) + override val testAnnotationId = BuiltinClassId( name = "$JUNIT5_PACKAGE.Test", canonicalName = "$JUNIT5_PACKAGE.Test", @@ -447,6 +462,16 @@ object Junit5 : TestFramework("JUnit5") { ) ) + val assertTimeoutPreemptively = builtinStaticMethodId( + classId = assertionsClass, + name = "assertTimeoutPreemptively", + returnType = voidWrapperClassId, + arguments = arrayOf( + durationClassId, + executableClassId + ) + ) + val displayNameClassId = BuiltinClassId( name = "$JUNIT5_PACKAGE.DisplayName", canonicalName = "$JUNIT5_PACKAGE.DisplayName", diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt index b1ab03e5db..8e3510df91 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt @@ -361,11 +361,17 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c return } - when (exception) { - is TimeoutException -> { - methodType = TIMEOUT - writeWarningAboutTimeoutExceeding() + if (shouldTestPassWithTimeoutException(execution, exception)) { + writeWarningAboutTimeoutExceeding() + testFrameworkManager.expectTimeout(hangingTestsTimeout.timeoutMs) { + methodInvocationBlock() } + methodType = TIMEOUT + + return + } + + when (exception) { is ConcreteExecutionFailureException -> { methodType = CRASH writeWarningAboutCrash() @@ -388,6 +394,10 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c return exceptionRequiresAssert || exceptionIsExplicit } + private fun shouldTestPassWithTimeoutException(execution: UtExecution, exception: Throwable): Boolean { + return execution.result is UtTimeoutException || exception is TimeoutException + } + private fun writeWarningAboutTimeoutExceeding() { +CgMultilineComment( listOf( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt index 7b8ed610b9..6fde079657 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt @@ -155,6 +155,8 @@ internal abstract class TestFrameworkManager(val context: CgContext) // TestNg allows both approaches, we use similar to JUnit5 abstract fun expectException(exception: ClassId, block: () -> Unit) + open fun expectTimeout(timeoutMs: Long, block: () -> Unit) {} + open fun setTestExecutionTimeout(timeoutMs: Long) { val timeout = CgNamedAnnotationArgument( name = timeoutArgumentName, @@ -327,6 +329,14 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context) +assertions[assertThrows](exception.toExceptionClass(), lambda) } + override fun expectTimeout(timeoutMs : Long, block: () -> Unit) { + require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" } + val lambda = statementConstructor.lambda(testFramework.executableClassId) { block() } + importIfNeeded(testFramework.durationClassId) + val duration = CgMethodCall(null, testFramework.ofMillis, listOf(timeoutMs.resolve())) + +assertions[testFramework.assertTimeoutPreemptively](duration, lambda) + } + override fun addDisplayName(name: String) { require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" } collectedTestMethodAnnotations += statementConstructor.annotation(testFramework.displayNameClassId, name)