From c4ec50ecf934b8f75237a8e59d04cf9ec125cf30 Mon Sep 17 00:00:00 2001 From: Rustam Sadykov Date: Thu, 19 Jan 2023 21:51:10 +0100 Subject: [PATCH 1/2] add specification --- .../framework/plugin/api/UtExecutionResult.kt | 4 ++ .../org/utbot/engine/UtBotSymbolicEngine.kt | 29 +++++++++-- .../org/utbot/external/api/UtBotJavaApi.kt | 4 +- .../util/UtConcreteExecutionResultUtils.kt | 2 +- .../execution/UtExecutionInstrumentation.kt | 48 ++++--------------- .../execution/data/UtConcreteExecutionData.kt | 21 ++++++++ .../data/UtConcreteExecutionResult.kt | 18 +++++++ .../data/UtConcreteExecutionSpecification.kt | 24 ++++++++++ .../execution/phases/PhaseContext.kt | 4 +- .../execution/phases/PhasesController.kt | 21 ++++++-- .../kotlin/org/utbot/summary/TagGenerator.kt | 2 + 11 files changed, 127 insertions(+), 50 deletions(-) create mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionData.kt create mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionResult.kt create mode 100644 utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionSpecification.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt index 20748404fa..0bb396a163 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt @@ -21,6 +21,10 @@ sealed class UtExecutionFailure : UtExecutionResult() { get() = exception } +data class UtIgnoreFailure( + override val exception: Throwable, +) : UtExecutionFailure() + data class UtOverflowFailure( override val exception: Throwable, ) : UtExecutionFailure() diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 10a9138a8c..3cf7cc51f9 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -42,13 +42,15 @@ import org.utbot.fuzzer.* import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.Trie import org.utbot.instrumentation.ConcreteExecutor -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionData +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation import soot.jimple.Stmt import soot.tagkit.ParamNamesTag import java.lang.reflect.Method import kotlin.system.measureTimeMillis +import org.utbot.instrumentation.instrumentation.execution.data.FuzzingSpecification +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionSpecification val logger = KotlinLogging.logger {} val pathLogger = KotlinLogging.logger(logger.name + ".path") @@ -341,6 +343,7 @@ class UtBotSymbolicEngine( // Currently, fuzzer doesn't work with static methods with empty parameters return@flow } + val concreteExecutorSpecification = FuzzingSpecification() val errorStackTraceTracker = Trie(StackTraceElement::toString) var attempts = 0 val attemptsLimit = UtSettings.fuzzingMaxAttempts @@ -362,7 +365,12 @@ class UtBotSymbolicEngine( val initialEnvironmentModels = EnvironmentModels(thisInstance?.model, values.map { it.model }, mapOf()) val concreteExecutionResult: UtConcreteExecutionResult? = try { - concreteExecutor.executeConcretely(methodUnderTest, initialEnvironmentModels, listOf()) + concreteExecutor.executeConcretely( + methodUnderTest, + initialEnvironmentModels, + listOf(), + concreteExecutorSpecification, + ) } catch (e: CancellationException) { logger.debug { "Cancelled by timeout" }; null } catch (e: ConcreteExecutionFailureException) { @@ -374,6 +382,11 @@ class UtBotSymbolicEngine( // in case an exception occurred from the concrete execution concreteExecutionResult ?: return@runJavaFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.PASS) + if (concreteExecutionResult.isExpectedFailure()) { + logger.debug { "Expected failure in concrete executor: ${concreteExecutionResult.result.exceptionOrNull()}" } + return@runJavaFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.PASS) + } + if (concreteExecutionResult.violatesUtMockAssumption()) { logger.debug { "Generated test case by fuzzer violates the UtMock assumption: $concreteExecutionResult" } return@runJavaFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.PASS) @@ -559,14 +572,16 @@ private fun ResolvedModels.constructStateForMethod(methodUnderTest: ExecutableId private suspend fun ConcreteExecutor.executeConcretely( methodUnderTest: ExecutableId, stateBefore: EnvironmentModels, - instrumentation: List + instrumentation: List, + specification: UtConcreteExecutionSpecification? = null, ): UtConcreteExecutionResult = executeAsync( methodUnderTest.classId.name, methodUnderTest.signature, arrayOf(), parameters = UtConcreteExecutionData( stateBefore, - instrumentation + instrumentation, + specification = specification ) ).convertToAssemble(methodUnderTest.classId.packageName) @@ -623,3 +638,7 @@ private fun UtConcreteExecutionResult.violatesUtMockAssumption(): Boolean { // so we can't cast them to each other. return result.exceptionOrNull()?.javaClass?.name == UtMockAssumptionViolatedException::class.java.name } + +private fun UtConcreteExecutionResult.isExpectedFailure(): Boolean { + return result is UtIgnoreFailure +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt index d3bf6bfbe4..9bb9c788a4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt @@ -10,8 +10,8 @@ import org.utbot.framework.codegen.domain.NoStaticMocking import org.utbot.framework.codegen.domain.StaticsMocking import org.utbot.framework.codegen.domain.TestFramework import org.utbot.framework.codegen.services.language.CgLanguageAssistant -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionData +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/util/UtConcreteExecutionResultUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/util/UtConcreteExecutionResultUtils.kt index 6b9eedcd73..15caab1846 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/util/UtConcreteExecutionResultUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/util/UtConcreteExecutionResultUtils.kt @@ -4,7 +4,7 @@ import org.utbot.framework.assemble.AssembleModelGenerator import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtModel -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionResult import java.util.IdentityHashMap private fun UtConcreteExecutionResult.updateWithAssembleModels( diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt index 3ab2051f72..55cc2d8199 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/UtExecutionInstrumentation.kt @@ -3,53 +3,24 @@ package org.utbot.instrumentation.instrumentation.execution import java.security.ProtectionDomain import java.util.IdentityHashMap import kotlin.reflect.jvm.javaMethod -import org.utbot.framework.UtSettings -import org.utbot.instrumentation.instrumentation.execution.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy -import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor -import org.utbot.instrumentation.instrumentation.execution.mock.InstrumentationContext -import org.utbot.instrumentation.instrumentation.execution.phases.PhasesController -import org.utbot.instrumentation.instrumentation.execution.phases.start -import org.utbot.framework.plugin.api.Coverage import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.FieldId -import org.utbot.framework.plugin.api.UtExecutionResult -import org.utbot.framework.plugin.api.UtInstrumentation import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.util.singleExecutableId import org.utbot.instrumentation.instrumentation.ArgumentList import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.InvokeInstrumentation import org.utbot.instrumentation.instrumentation.et.TraceHandler +import org.utbot.instrumentation.instrumentation.execution.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionData +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.mock.InstrumentationContext +import org.utbot.instrumentation.instrumentation.execution.phases.PhasesController +import org.utbot.instrumentation.instrumentation.execution.phases.start import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor -/** - * Consists of the data needed to execute the method concretely. Also includes method arguments stored in models. - * - * @property [stateBefore] is necessary for construction of parameters of a concrete call. - * @property [instrumentation] is necessary for mocking static methods and new instances. - * @property [timeout] is timeout for specific concrete execution (in milliseconds). - * By default is initialized from [UtSettings.concreteExecutionTimeoutInInstrumentedProcess] - */ -data class UtConcreteExecutionData( - val stateBefore: EnvironmentModels, - val instrumentation: List, - val timeout: Long = UtSettings.concreteExecutionTimeoutInInstrumentedProcess -) - -class UtConcreteExecutionResult( - val stateAfter: EnvironmentModels, - val result: UtExecutionResult, - val coverage: Coverage -) { - override fun toString(): String = buildString { - appendLine("UtConcreteExecutionResult(") - appendLine("stateAfter=$stateAfter") - appendLine("result=$result") - appendLine("coverage=$coverage)") - } -} - object UtExecutionInstrumentation : Instrumentation { private val delegateInstrumentation = InvokeInstrumentation() @@ -78,7 +49,7 @@ object UtExecutionInstrumentation : Instrumentation { if (parameters !is UtConcreteExecutionData) { throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}") } - val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData + val (stateBefore, instrumentations, timeout, specification) = parameters // smart cast to UtConcreteExecutionData val methodId = clazz.singleExecutableId(methodSignature) val returnClassId = methodId.returnType @@ -86,7 +57,8 @@ object UtExecutionInstrumentation : Instrumentation { return PhasesController( instrumentationContext, traceHandler, - delegateInstrumentation + delegateInstrumentation, + specification, ).computeConcreteExecutionResult { // construction val (params, statics, cache) = valueConstructionContext.start { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionData.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionData.kt new file mode 100644 index 0000000000..8bcf18e0dd --- /dev/null +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionData.kt @@ -0,0 +1,21 @@ +package org.utbot.instrumentation.instrumentation.execution.data + +import org.utbot.framework.UtSettings +import org.utbot.framework.plugin.api.EnvironmentModels +import org.utbot.framework.plugin.api.UtInstrumentation + +/** + * Consists of the data needed to execute the method concretely. Also includes method arguments stored in models. + * + * @property [stateBefore] is necessary for construction of parameters of a concrete call. + * @property [instrumentation] is necessary for mocking static methods and new instances. + * @property [timeout] is timeout for specific concrete execution (in milliseconds). + * @property [specification] is strategy for controlling of results handling and validation (null means "without any validation"). + * By default, is initialized from [UtSettings.concreteExecutionTimeoutInInstrumentedProcess] + */ +data class UtConcreteExecutionData( + val stateBefore: EnvironmentModels, + val instrumentation: List, + val timeout: Long = UtSettings.concreteExecutionTimeoutInInstrumentedProcess, + val specification: UtConcreteExecutionSpecification? = null, +) \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionResult.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionResult.kt new file mode 100644 index 0000000000..eef55ded35 --- /dev/null +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionResult.kt @@ -0,0 +1,18 @@ +package org.utbot.instrumentation.instrumentation.execution.data + +import org.utbot.framework.plugin.api.Coverage +import org.utbot.framework.plugin.api.EnvironmentModels +import org.utbot.framework.plugin.api.UtExecutionResult + +class UtConcreteExecutionResult( + val stateAfter: EnvironmentModels, + val result: UtExecutionResult, + val coverage: Coverage +) { + override fun toString(): String = buildString { + appendLine("UtConcreteExecutionResult(") + appendLine("stateAfter=$stateAfter") + appendLine("result=$result") + appendLine("coverage=$coverage)") + } +} \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionSpecification.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionSpecification.kt new file mode 100644 index 0000000000..54261e58ac --- /dev/null +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/data/UtConcreteExecutionSpecification.kt @@ -0,0 +1,24 @@ +package org.utbot.instrumentation.instrumentation.execution.data + +import org.utbot.framework.plugin.api.UtIgnoreFailure +import org.utbot.instrumentation.instrumentation.execution.phases.ValueConstructionPhaseError + +/** + * Specification controls result handling and validation. + */ +interface UtConcreteExecutionSpecification { + + /** + * If an exception is expected, it will be handling and translate to [UtIgnoreFailure] + */ + fun exceptionIsExpected(exception: Exception): Boolean +} + +/** + * Fuzzing specification allows to ignore errors during values construction. + */ +class FuzzingSpecification : UtConcreteExecutionSpecification { + override fun exceptionIsExpected(exception: Exception): Boolean { + return exception is ValueConstructionPhaseError + } +} diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhaseContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhaseContext.kt index d1beaaa21b..3c1b86edbf 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhaseContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhaseContext.kt @@ -5,9 +5,11 @@ interface PhaseContext { fun wrapError(error: Throwable): E } -inline fun > T.start(block: T.() -> R): R = +internal inline fun > T.start(block: T.() -> R): R = try { block() + } catch (e: UtConcreteExecutionForceException) { + throw UtConcreteExecutionForceException(wrapError(e.cause)) } catch (e: Throwable) { throw wrapError(e) } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt index 58617a3a61..cf38045e89 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt @@ -1,21 +1,28 @@ package org.utbot.instrumentation.instrumentation.execution.phases +import com.jetbrains.rd.util.debug +import com.jetbrains.rd.util.getLogger import java.io.Closeable import java.security.AccessControlException -import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.mock.InstrumentationContext import org.utbot.framework.plugin.api.Coverage import org.utbot.framework.plugin.api.MissingState +import org.utbot.framework.plugin.api.UtIgnoreFailure import org.utbot.framework.plugin.api.UtSandboxFailure import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.et.TraceHandler +import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionSpecification class PhasesController( instrumentationContext: InstrumentationContext, traceHandler: TraceHandler, delegateInstrumentation: Instrumentation>, + private val specification: UtConcreteExecutionSpecification?, ) : Closeable { + private val logger by lazy { getLogger("InstrumentedProcess") } + val valueConstructionContext = ValueConstructionContext(instrumentationContext) val preparationContext = PreparationContext(traceHandler) @@ -28,7 +35,7 @@ class PhasesController( val postprocessingContext = PostprocessingContext() - inline fun computeConcreteExecutionResult(block: PhasesController.() -> UtConcreteExecutionResult): UtConcreteExecutionResult { + fun computeConcreteExecutionResult(block: PhasesController.() -> UtConcreteExecutionResult): UtConcreteExecutionResult { return use { try { block() @@ -40,7 +47,15 @@ class PhasesController( Coverage() ) } - // TODO: make failure results from different phase errors + if (specification != null && specification.exceptionIsExpected(e)) { + logger.debug { "ignore exception by specification:" } + logger.debug { e } + return@use UtConcreteExecutionResult( + MissingState, + UtIgnoreFailure(e), + Coverage() + ) + } throw e } } diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt index 9a42bae1d7..de8b33b872 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt @@ -6,6 +6,7 @@ import org.utbot.framework.plugin.api.UtExecution import org.utbot.framework.plugin.api.UtExecutionResult import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtExplicitlyThrownException +import org.utbot.framework.plugin.api.UtIgnoreFailure import org.utbot.framework.plugin.api.UtImplicitlyThrownException import org.utbot.framework.plugin.api.UtMethodTestSet import org.utbot.framework.plugin.api.UtOverflowFailure @@ -220,6 +221,7 @@ private fun UtExecutionResult.clusterKind() = when (this) { is UtTimeoutException -> ExecutionGroup.TIMEOUTS is UtConcreteExecutionFailure -> ExecutionGroup.CRASH_SUITE is UtSandboxFailure -> ExecutionGroup.SECURITY + is UtIgnoreFailure -> ExecutionGroup.CRASH_SUITE } /** From a0722aa3e75fe5f86e1ac76fc6485e776d4c35c6 Mon Sep 17 00:00:00 2001 From: Rustam Sadykov Date: Thu, 19 Jan 2023 21:52:15 +0100 Subject: [PATCH 2/2] add force exception --- .../constructors/MockValueConstructor.kt | 48 ++++++++++++------- .../execution/phases/PhasesController.kt | 14 ++++++ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/MockValueConstructor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/MockValueConstructor.kt index ba6f49c717..f143ffda05 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/MockValueConstructor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/MockValueConstructor.kt @@ -53,6 +53,7 @@ import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.method import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.plugin.api.util.anyInstance +import org.utbot.instrumentation.instrumentation.execution.phases.withForceException import org.utbot.instrumentation.process.runSandbox /** @@ -234,7 +235,10 @@ class MockValueConstructor( } private fun generateMockitoMock(clazz: Class<*>, mocks: Map>): Any { - return Mockito.mock(clazz, generateMockitoAnswer(mocks)) + val answer = generateMockitoAnswer(mocks) + return withForceException { + Mockito.mock(clazz, answer) + } } private fun computeConcreteValuesForMethods( @@ -261,13 +265,15 @@ class MockValueConstructor( if (method !is MethodId) { throw IllegalArgumentException("Expected MethodId, but got: $method") } - MethodMockController( - method.classId.jClass, - method.method, - instance, - values, - instrumentationContext - ) + withForceException { + MethodMockController( + method.classId.jClass, + method.method, + instance, + values, + instrumentationContext + ) + } } } @@ -289,11 +295,13 @@ class MockValueConstructor( instrumentations: List, ) { controllers += instrumentations.map { mock -> - InstanceMockController( - mock.classId, - mock.instances.map { mockAndGet(it) }, - mock.callSites.map { Type.getType(it.jClass).internalName }.toSet() - ) + withForceException { + InstanceMockController( + mock.classId, + mock.instances.map { mockAndGet(it) }, + mock.callSites.map { Type.getType(it.jClass).internalName }.toSet() + ) + } } } @@ -393,7 +401,9 @@ class MockValueConstructor( val capturedArguments = lambdaModel.capturedValues .map { model -> CapturedArgument(type = model.classId.jClass, value = value(model)) } .toTypedArray() - constructStaticLambda(samType, declaringClass, lambdaName, *capturedArguments) + withForceException { + constructStaticLambda(samType, declaringClass, lambdaName, *capturedArguments) + } } else { val capturedReceiverModel = lambdaModel.capturedValues.firstOrNull() ?: error("Non-static lambda must capture `this` instance, so there must be at least one captured value") @@ -403,7 +413,9 @@ class MockValueConstructor( val capturedArguments = lambdaModel.capturedValues.subList(1, lambdaModel.capturedValues.size) .map { model -> CapturedArgument(type = model.classId.jClass, value = value(model)) } .toTypedArray() - constructLambda(samType, declaringClass, lambdaName, capturedReceiver, *capturedArguments) + withForceException { + constructLambda(samType, declaringClass, lambdaName, capturedReceiver, *capturedArguments) + } } constructedObjects[lambdaModel] = lambda return lambda @@ -495,7 +507,7 @@ class MockValueConstructor( private fun javaClass(id: ClassId) = kClass(id).java - private fun kClass(id: ClassId) = + private fun kClass(id: ClassId) = withForceException { if (id.elementClassId != null) { arrayClassOf(id.elementClassId!!) } else { @@ -511,8 +523,9 @@ class MockValueConstructor( else -> classLoader.loadClass(id.name).kotlin } } + } - private fun arrayClassOf(elementClassId: ClassId): KClass<*> = + private fun arrayClassOf(elementClassId: ClassId): KClass<*> = withForceException { if (elementClassId.elementClassId != null) { val elementClass = arrayClassOf(elementClassId.elementClassId!!) java.lang.reflect.Array.newInstance(elementClass.java, 0)::class @@ -532,6 +545,7 @@ class MockValueConstructor( } } } + } override fun close() { controllers.forEach { it.close() } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt index cf38045e89..09cf64c357 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt @@ -14,6 +14,18 @@ import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.et.TraceHandler import org.utbot.instrumentation.instrumentation.execution.data.UtConcreteExecutionSpecification +internal class UtConcreteExecutionForceException(override val cause: Throwable) : Exception() + +internal inline fun withForceException(block: () -> T): T { + try { + return block() + } catch (e: UtConcreteExecutionForceException) { + throw e + } catch (e: Throwable) { + throw UtConcreteExecutionForceException(e) + } +} + class PhasesController( instrumentationContext: InstrumentationContext, traceHandler: TraceHandler, @@ -39,6 +51,8 @@ class PhasesController( return use { try { block() + } catch (e: UtConcreteExecutionForceException) { + throw e.cause } catch (e: PhaseError) { if (e.cause.cause is AccessControlException) { return@use UtConcreteExecutionResult(