diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/concrete/constructors/BaseConstructorTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/framework/concrete/constructors/BaseConstructorTest.kt index 71c63531fa..3a54a192a1 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/framework/concrete/constructors/BaseConstructorTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/framework/concrete/constructors/BaseConstructorTest.kt @@ -1,7 +1,6 @@ package org.utbot.framework.concrete.constructors import org.utbot.engine.ValueConstructor -import org.utbot.framework.concrete.UtModelConstructor import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.id diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt index 75a210f776..0ade2e9dbb 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt @@ -1,50 +1,30 @@ package org.utbot.framework.concrete -import org.objectweb.asm.Type -import org.utbot.common.StopWatch -import org.utbot.common.ThreadBasedExecutor -import org.utbot.common.withAccessibility +import java.security.ProtectionDomain +import java.util.IdentityHashMap +import kotlin.reflect.jvm.javaMethod import org.utbot.framework.UtSettings import org.utbot.framework.assemble.AssembleModelGenerator +import org.utbot.framework.concrete.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy +import org.utbot.framework.concrete.constructors.UtModelConstructor +import org.utbot.framework.concrete.mock.InstrumentationContext +import org.utbot.framework.concrete.phases.PhasesController +import org.utbot.framework.concrete.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.Instruction -import org.utbot.framework.plugin.api.MissingState -import org.utbot.framework.plugin.api.TimeoutException import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtExecutionFailure 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.UtImplicitlyThrownException import org.utbot.framework.plugin.api.UtInstrumentation import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation -import org.utbot.framework.plugin.api.UtSandboxFailure -import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation -import org.utbot.framework.plugin.api.visible.UtStreamConsumingException -import org.utbot.framework.plugin.api.UtStreamConsumingFailure -import org.utbot.framework.plugin.api.UtTimeoutException -import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.singleExecutableId -import org.utbot.framework.plugin.api.util.utContext -import org.utbot.framework.plugin.api.util.withUtContext -import org.utbot.framework.util.isInaccessibleViaReflection import org.utbot.instrumentation.instrumentation.ArgumentList import org.utbot.instrumentation.instrumentation.Instrumentation import org.utbot.instrumentation.instrumentation.InvokeInstrumentation -import org.utbot.instrumentation.instrumentation.et.EtInstruction -import org.utbot.instrumentation.instrumentation.et.ExplicitThrowInstruction import org.utbot.instrumentation.instrumentation.et.TraceHandler import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor -import java.security.AccessControlException -import java.security.ProtectionDomain -import java.util.IdentityHashMap -import kotlin.reflect.jvm.javaMethod /** * Consists of the data needed to execute the method concretely. Also includes method arguments stored in models. @@ -142,107 +122,78 @@ object UtExecutionInstrumentation : Instrumentation { throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}") } val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData - val parametersModels = listOfNotNull(stateBefore.thisInstance) + stateBefore.parameters val methodId = clazz.singleExecutableId(methodSignature) val returnClassId = methodId.returnType - traceHandler.resetTrace() - - return MockValueConstructor(instrumentationContext).use { constructor -> - val params = try { - constructor.constructMethodParameters(parametersModels) - } catch (e: Throwable) { - if (e.cause is AccessControlException) { - return@use UtConcreteExecutionResult( - MissingState, - UtSandboxFailure(e.cause!!), - Coverage() - ) - } - throw e + return PhasesController( + instrumentationContext, + traceHandler, + delegateInstrumentation + ).computeConcreteExecutionResult { + // construction + val (params, statics, cache) = valueConstructionContext.start { + val params = constructParameters(stateBefore) + val statics = constructStatics(stateBefore) + + mock(instrumentations) + + Triple(params, statics, getCache()) } - val staticFields = constructor - .constructStatics( - stateBefore - .statics - .filterKeys { !it.isInaccessibleViaReflection } - ) - .mapValues { (_, value) -> value.value } - - val concreteExecutionResult = withStaticFields(staticFields) { - val staticMethodsInstrumentation = instrumentations.filterIsInstance() - constructor.mockStaticMethods(staticMethodsInstrumentation) - val newInstanceInstrumentation = instrumentations.filterIsInstance() - constructor.mockNewInstances(newInstanceInstrumentation) - - traceHandler.resetTrace() - val stopWatch = StopWatch() - val context = UtContext(utContext.classLoader, stopWatch) - val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout(timeout, stopWatch) { - withUtContext(context) { - delegateInstrumentation.invoke(clazz, methodSignature, params.map { it.value }) - } - }?.getOrThrow() as? Result<*> ?: Result.failure(TimeoutException("Timeout $timeout elapsed")) - val traceList = traceHandler.computeInstructionList() - - val cache = constructor.objectToModelCache - val utCompositeModelStrategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(pathsToUserClasses, cache) - val utModelConstructor = UtModelConstructor(cache, utCompositeModelStrategy) - utModelConstructor.run { - val concreteUtModelResult = concreteResult.fold({ - try { - val model = construct(it, returnClassId) - UtExecutionSuccess(model) - } catch (e: Exception) { - processExceptionDuringModelConstruction(e) - } - }) { - sortOutException(it) + + // preparation + val savedStatics = preparationContext.start { + val savedStatics = setStaticFields(statics) + resetTrace() + savedStatics + } + + try { + // invocation + val concreteResult = invocationContext.start { + invoke(clazz, methodSignature, params.map { it.value }, timeout) + } + + // statistics collection + val coverage = statisticsCollectionContext.start { + getCoverage(clazz) + } + + // model construction + val (executionResult, stateAfter) = modelConstructionContext.start { + configureConstructor { + this.cache = cache + strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(pathsToUserClasses, cache) } - val stateAfterParametersWithThis = params.map { construct(it.value, it.clazz.id) } - val stateAfterStatics = (staticFields.keys/* + traceHandler.computePutStatics()*/) - .associateWith { fieldId -> - fieldId.jField.run { - val computedValue = withAccessibility { get(null) } - val knownModel = stateBefore.statics[fieldId] - val knownValue = staticFields[fieldId] - if (knownModel != null && knownValue != null && knownValue == computedValue) { - knownModel - } else { - construct(computedValue, fieldId.type) - } - } - } + val executionResult = convertToExecutionResult(concreteResult, returnClassId) + + val stateAfterParametersWithThis = constructParameters(params) + val stateAfterStatics = constructStatics(statics.keys/* + traceHandler.computePutStatics()*/) val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) { null to stateAfterParametersWithThis } else { stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1) } val stateAfter = EnvironmentModels(stateAfterThis, stateAfterParameters, stateAfterStatics) - UtConcreteExecutionResult( - stateAfter, - concreteUtModelResult, - traceList.toApiCoverage( - traceHandler.processingStorage.getInstructionsCount( - Type.getInternalName(clazz) - ) - ) - ) + + executionResult to stateAfter } - } - concreteExecutionResult + UtConcreteExecutionResult( + stateAfter, + executionResult, + coverage + ) + } finally { + // postprocessing + postprocessingContext.start { + resetStaticFields(savedStatics) + } + } } } - private fun processExceptionDuringModelConstruction(e: Exception): UtExecutionResult = - when (e) { - is UtStreamConsumingException -> UtStreamConsumingFailure(e) - else -> throw e - } - override fun getStaticField(fieldId: FieldId): Result = delegateInstrumentation.getStaticField(fieldId).map { value -> val cache = IdentityHashMap() @@ -254,30 +205,6 @@ object UtExecutionInstrumentation : Instrumentation { } } - private fun sortOutException(exception: Throwable): UtExecutionFailure { - if (exception is TimeoutException) { - return UtTimeoutException(exception) - } - if (exception is AccessControlException || - exception is ExceptionInInitializerError && exception.exception is AccessControlException) { - return UtSandboxFailure(exception) - } - // there also can be other cases, when we need to wrap internal exception... I suggest adding them on demand - - val instrs = traceHandler.computeInstructionList() - val isNested = if (instrs.isEmpty()) { - false - } else { - instrs.first().callId != instrs.last().callId - } - return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) { - UtExplicitlyThrownException(exception, isNested) - } else { - UtImplicitlyThrownException(exception, isNested) - } - - } - override fun transform( loader: ClassLoader?, className: String, @@ -305,36 +232,4 @@ object UtExecutionInstrumentation : Instrumentation { return instrumenter.classByteCode } - - private fun withStaticFields(staticFields: Map, block: () -> T): T { - val savedFields = mutableMapOf() - try { - staticFields.forEach { (fieldId, value) -> - fieldId.jField.run { - withAccessibility { - savedFields[fieldId] = get(null) - set(null, value) - } - } - } - return block() - } finally { - savedFields.forEach { (fieldId, value) -> - fieldId.jField.run { - withAccessibility { - set(null, value) - } - } - } - } - } } - -/** - * Transforms a list of internal [EtInstruction]s to a list of api [Instruction]s. - */ -private fun List.toApiCoverage(instructionsCount: Long? = null): Coverage = - Coverage( - map { Instruction(it.className, it.methodSignature, it.line, it.id) }, - instructionsCount - ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/IterableConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/IterableConstructors.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/IterableConstructors.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/IterableConstructors.kt index 6866000d06..147456d95c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/IterableConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/IterableConstructors.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/MockValueConstructor.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/MockValueConstructor.kt index 9b06437078..59c79fe516 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/MockValueConstructor.kt @@ -1,6 +1,21 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors +import java.io.Closeable +import java.lang.reflect.Modifier +import java.util.IdentityHashMap +import kotlin.reflect.KClass +import org.mockito.Mockito +import org.mockito.stubbing.Answer +import org.objectweb.asm.Type +import org.utbot.common.Reflection import org.utbot.common.invokeCatching +import org.utbot.engine.util.lambda.CapturedArgument +import org.utbot.engine.util.lambda.constructLambda +import org.utbot.engine.util.lambda.constructStaticLambda +import org.utbot.framework.concrete.mock.InstanceMockController +import org.utbot.framework.concrete.mock.InstrumentationContext +import org.utbot.framework.concrete.mock.MethodMockController +import org.utbot.framework.concrete.mock.MockController import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.ExecutableId @@ -20,6 +35,7 @@ import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtDirectSetFieldModel import org.utbot.framework.plugin.api.UtEnumConstantModel import org.utbot.framework.plugin.api.UtExecutableCallModel +import org.utbot.framework.plugin.api.UtLambdaModel import org.utbot.framework.plugin.api.UtMockValue import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation @@ -31,25 +47,12 @@ import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.constructor import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.jField +import org.utbot.framework.plugin.api.util.isStatic import org.utbot.framework.plugin.api.util.jClass +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.util.anyInstance -import java.io.Closeable -import java.lang.reflect.Field -import java.lang.reflect.Modifier -import java.util.IdentityHashMap -import kotlin.reflect.KClass -import org.mockito.Mockito -import org.mockito.stubbing.Answer -import org.objectweb.asm.Type -import org.utbot.common.Reflection -import org.utbot.engine.util.lambda.CapturedArgument -import org.utbot.engine.util.lambda.constructLambda -import org.utbot.engine.util.lambda.constructStaticLambda -import org.utbot.framework.plugin.api.UtLambdaModel -import org.utbot.framework.plugin.api.util.isStatic import org.utbot.instrumentation.process.runSandbox /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/OptionalConstructors.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/OptionalConstructors.kt index ae3b062c47..8e24ff1c7b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/OptionalConstructors.kt @@ -1,5 +1,10 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors +import java.util.Optional +import java.util.OptionalDouble +import java.util.OptionalInt +import java.util.OptionalLong +import kotlin.reflect.KFunction1 import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.MethodId import org.utbot.framework.plugin.api.UtAssembleModel @@ -10,11 +15,6 @@ import org.utbot.framework.plugin.api.util.intClassId import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.objectClassId -import java.util.Optional -import java.util.OptionalDouble -import java.util.OptionalInt -import java.util.OptionalLong -import kotlin.reflect.KFunction1 internal sealed class OptionalConstructorBase : UtAssembleModelConstructorBase() { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/PrimitiveWrapperConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/PrimitiveWrapperConstructor.kt similarity index 96% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/PrimitiveWrapperConstructor.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/PrimitiveWrapperConstructor.kt index d9521caf3f..d5f70856c7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/PrimitiveWrapperConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/PrimitiveWrapperConstructor.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtAssembleModel diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StreamConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/StreamConstructors.kt similarity index 99% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StreamConstructors.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/StreamConstructors.kt index 82cb2908e5..bedb13eb84 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StreamConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/StreamConstructors.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.MethodId diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtAssembleModelConstructors.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtAssembleModelConstructors.kt index 82be902336..7c3b2db86f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtAssembleModelConstructors.kt @@ -1,18 +1,17 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors +import java.util.stream.BaseStream +import java.util.stream.DoubleStream +import java.util.stream.IntStream +import java.util.stream.LongStream import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtStatementModel -import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.primitiveWrappers import org.utbot.framework.plugin.api.util.voidWrapperClassId import org.utbot.framework.util.nextModelName -import java.util.stream.BaseStream -import java.util.stream.DoubleStream -import java.util.stream.IntStream -import java.util.stream.LongStream private val predefinedConstructors = mutableMapOf, () -> UtAssembleModelConstructorBase>( /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtModelConstructor.kt similarity index 99% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtModelConstructor.kt index 38c61d7590..ea0207f431 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/UtModelConstructor.kt @@ -1,5 +1,8 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.constructors +import java.lang.reflect.Modifier +import java.util.IdentityHashMap +import java.util.stream.BaseStream import org.utbot.common.asPathToFile import org.utbot.common.withAccessibility import org.utbot.framework.plugin.api.ClassId @@ -14,7 +17,6 @@ import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel -import org.utbot.framework.plugin.api.visible.UtStreamConsumingException import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.booleanClassId @@ -30,12 +32,10 @@ import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.objectClassId import org.utbot.framework.plugin.api.util.shortClassId +import org.utbot.framework.plugin.api.util.utContext +import org.utbot.framework.plugin.api.visible.UtStreamConsumingException import org.utbot.framework.util.isInaccessibleViaReflection import org.utbot.framework.util.valueToClassId -import java.lang.reflect.Modifier -import java.util.IdentityHashMap -import java.util.stream.BaseStream -import org.utbot.framework.plugin.api.util.utContext /** * Represents common interface for model constructors. diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstanceMockController.kt similarity index 93% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstanceMockController.kt index c7f3e214bd..d2d09bb926 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstanceMockController.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.mock import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.util.jClass diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstrumentationContext.kt similarity index 98% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstrumentationContext.kt index 09fba7410d..f349af45f5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/InstrumentationContext.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.mock import java.lang.reflect.Method import java.util.IdentityHashMap diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MethodMockController.kt similarity index 97% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MethodMockController.kt index 9b3ff5790f..813e21e620 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MethodMockController.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.mock import java.lang.reflect.Field import java.lang.reflect.Method diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MockController.kt similarity index 60% rename from utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt rename to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MockController.kt index 679925c30e..3d51933c2d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/mock/MockController.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.concrete +package org.utbot.framework.concrete.mock import java.io.Closeable diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/InvocationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/InvocationContext.kt new file mode 100644 index 0000000000..21b3875963 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/InvocationContext.kt @@ -0,0 +1,42 @@ +package org.utbot.framework.concrete.phases + +import org.utbot.common.StopWatch +import org.utbot.common.ThreadBasedExecutor +import org.utbot.framework.plugin.api.TimeoutException +import org.utbot.framework.plugin.api.util.UtContext +import org.utbot.framework.plugin.api.util.utContext +import org.utbot.framework.plugin.api.util.withUtContext +import org.utbot.instrumentation.instrumentation.Instrumentation + +class InvocationPhaseError(cause: Throwable) : PhaseError( + message = "Error during user's code invocation phase", + cause +) + +/** + * This phase is about invoking user's code using [delegateInstrumentation]. + */ +class InvocationContext( + private val delegateInstrumentation: Instrumentation> +) : PhaseContext { + + override fun wrapError(error: Throwable): InvocationPhaseError = + InvocationPhaseError(error) + + fun invoke( + clazz: Class<*>, + methodSignature: String, + params: List, + timeout: Long, + ): Result<*> { + val stopWatch = StopWatch() + val context = UtContext(utContext.classLoader, stopWatch) + val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout(timeout, stopWatch) { + withUtContext(context) { + delegateInstrumentation.invoke(clazz, methodSignature, params) + } + }?.getOrThrow() as? Result<*> ?: Result.failure(TimeoutException("Timeout $timeout elapsed")) + return concreteResult + } + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ModelConstructionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ModelConstructionContext.kt new file mode 100644 index 0000000000..f33be90842 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ModelConstructionContext.kt @@ -0,0 +1,114 @@ +package org.utbot.framework.concrete.phases + +import java.security.AccessControlException +import java.util.IdentityHashMap +import org.utbot.common.withAccessibility +import org.utbot.framework.concrete.constructors.UtCompositeModelStrategy +import org.utbot.framework.concrete.constructors.UtModelConstructor +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.TimeoutException +import org.utbot.framework.plugin.api.UtConcreteValue +import org.utbot.framework.plugin.api.UtExecutionFailure +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.UtImplicitlyThrownException +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.UtSandboxFailure +import org.utbot.framework.plugin.api.UtStreamConsumingFailure +import org.utbot.framework.plugin.api.UtTimeoutException +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.jField +import org.utbot.framework.plugin.api.visible.UtStreamConsumingException +import org.utbot.instrumentation.instrumentation.et.ExplicitThrowInstruction +import org.utbot.instrumentation.instrumentation.et.TraceHandler + +class ModelConstructionPhaseError(cause: Throwable) : PhaseError( + message = "Error during model construction phase", + cause +) + +/** + * This phase of model construction from concrete values. + */ +class ModelConstructionContext( + private val traceHandler: TraceHandler +) : PhaseContext { + + override fun wrapError(error: Throwable): ModelConstructionPhaseError = + ModelConstructionPhaseError(error) + + private lateinit var constructor: UtModelConstructor + + class ConstructorConfiguration { + lateinit var cache: IdentityHashMap + lateinit var strategy: UtCompositeModelStrategy + } + + fun configureConstructor(block: ConstructorConfiguration.() -> Unit) { + ConstructorConfiguration().run { + block() + constructor = UtModelConstructor(cache, strategy) + } + } + + fun constructParameters(params: List>): List = + params.map { + constructor.construct(it.value, it.clazz.id) + } + + fun constructStatics(staticFields: Set): Map = + staticFields.associateWith { fieldId -> + fieldId.jField.run { + val computedValue = withAccessibility { get(null) } + constructor.construct(computedValue, fieldId.type) + } + } + + fun convertToExecutionResult(concreteResult: Result<*>, returnClassId: ClassId): UtExecutionResult { + val result = concreteResult.fold({ + try { + val model = constructor.construct(it, returnClassId) + UtExecutionSuccess(model) + } catch (e: Exception) { + processExceptionDuringModelConstruction(e) + } + }) { + sortOutException(it) + } + return result + } + + private fun sortOutException(exception: Throwable): UtExecutionFailure { + if (exception is TimeoutException) { + return UtTimeoutException(exception) + } + if (exception is AccessControlException || + exception is ExceptionInInitializerError && exception.exception is AccessControlException + ) { + return UtSandboxFailure(exception) + } + // there also can be other cases, when we need to wrap internal exception... I suggest adding them on demand + + val instrs = traceHandler.computeInstructionList() + val isNested = if (instrs.isEmpty()) { + false + } else { + instrs.first().callId != instrs.last().callId + } + return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) { + UtExplicitlyThrownException(exception, isNested) + } else { + UtImplicitlyThrownException(exception, isNested) + } + + } + + private fun processExceptionDuringModelConstruction(e: Exception): UtExecutionResult = + when (e) { + is UtStreamConsumingException -> UtStreamConsumingFailure(e) + else -> throw e + } + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhaseContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhaseContext.kt new file mode 100644 index 0000000000..bc92b9bae5 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhaseContext.kt @@ -0,0 +1,13 @@ +package org.utbot.framework.concrete.phases + +abstract class PhaseError(message: String, override val cause: Throwable) : Exception(message) +interface PhaseContext { + fun wrapError(error: Throwable): E +} + +inline fun > T.start(block: T.() -> R): R = + try { + block() + } catch (e: Throwable) { + throw wrapError(e) + } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhasesController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhasesController.kt new file mode 100644 index 0000000000..f45f42bf88 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PhasesController.kt @@ -0,0 +1,53 @@ +package org.utbot.framework.concrete.phases + +import java.io.Closeable +import java.security.AccessControlException +import org.utbot.framework.concrete.UtConcreteExecutionResult +import org.utbot.framework.concrete.mock.InstrumentationContext +import org.utbot.framework.plugin.api.Coverage +import org.utbot.framework.plugin.api.MissingState +import org.utbot.framework.plugin.api.UtSandboxFailure +import org.utbot.instrumentation.instrumentation.Instrumentation +import org.utbot.instrumentation.instrumentation.et.TraceHandler + +class PhasesController( + instrumentationContext: InstrumentationContext, + traceHandler: TraceHandler, + delegateInstrumentation: Instrumentation>, +) : Closeable { + + val valueConstructionContext = ValueConstructionContext(instrumentationContext) + + val preparationContext = PreparationContext(traceHandler) + + val invocationContext = InvocationContext(delegateInstrumentation) + + val statisticsCollectionContext = StatisticsCollectionContext(traceHandler) + + val modelConstructionContext = ModelConstructionContext(traceHandler) + + val postprocessingContext = PostprocessingContext() + + inline fun computeConcreteExecutionResult(block: PhasesController.() -> UtConcreteExecutionResult): UtConcreteExecutionResult { + return use { + try { + block() + } catch (e: PhaseError) { + if (e.cause.cause is AccessControlException) { + return@use UtConcreteExecutionResult( + MissingState, + UtSandboxFailure(e.cause.cause!!), + Coverage() + ) + } + // TODO: make failure results from different phase errors + throw e + } + } + } + + override fun close() { + valueConstructionContext.close() + } + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PostprocessingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PostprocessingContext.kt new file mode 100644 index 0000000000..42eb41e632 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PostprocessingContext.kt @@ -0,0 +1,30 @@ +package org.utbot.framework.concrete.phases + +import org.utbot.common.withAccessibility +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.util.jField + +class PostprocessingPhaseError(cause: Throwable) : PhaseError( + message = "Error during postprocessing phase", + cause +) + +/** + * The responsibility of this phase is resetting environment to the initial state. + */ +class PostprocessingContext : PhaseContext { + + override fun wrapError(error: Throwable): PostprocessingPhaseError = + PostprocessingPhaseError(error) + + fun resetStaticFields(staticFields: Map) { + staticFields.forEach { (fieldId, value) -> + fieldId.jField.run { + withAccessibility { + set(null, value) + } + } + } + } + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PreparationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PreparationContext.kt new file mode 100644 index 0000000000..e3ad8172fe --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/PreparationContext.kt @@ -0,0 +1,41 @@ +package org.utbot.framework.concrete.phases + +import org.utbot.common.withAccessibility +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.UtConcreteValue +import org.utbot.framework.plugin.api.util.jField +import org.utbot.instrumentation.instrumentation.et.TraceHandler + +class PreparationPhaseError(cause: Throwable) : PhaseError( + message = "Error during environment preparation phase", + cause +) + +/** + * The responsibility of this phase is environment preparation before execution. + */ +class PreparationContext( + private val traceHandler: TraceHandler +) : PhaseContext { + + override fun wrapError(error: Throwable): PreparationPhaseError = + PreparationPhaseError(error) + + fun setStaticFields(staticFieldsValues: Map>): Map { + val savedStaticFields = mutableMapOf() + staticFieldsValues.forEach { (fieldId, value) -> + fieldId.jField.run { + withAccessibility { + savedStaticFields[fieldId] = get(null) + set(null, value.value) + } + } + } + return savedStaticFields + } + + fun resetTrace() { + traceHandler.resetTrace() + } + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/StatisticsCollectionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/StatisticsCollectionContext.kt new file mode 100644 index 0000000000..4d69943059 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/StatisticsCollectionContext.kt @@ -0,0 +1,42 @@ +package org.utbot.framework.concrete.phases + +import org.objectweb.asm.Type +import org.utbot.framework.plugin.api.Coverage +import org.utbot.framework.plugin.api.Instruction +import org.utbot.instrumentation.instrumentation.et.EtInstruction +import org.utbot.instrumentation.instrumentation.et.TraceHandler + +class StatisticsCollectionPhaseError(cause: Throwable) : PhaseError( + message = "Error during statistics collection phase", + cause +) + +/** + * This phase is about collection statistics such as coverage. + */ +class StatisticsCollectionContext( + private val traceHandler: TraceHandler +) : PhaseContext { + + override fun wrapError(error: Throwable): StatisticsCollectionPhaseError = + StatisticsCollectionPhaseError(error) + + fun getCoverage(clazz: Class<*>): Coverage { + return traceHandler + .computeInstructionList() + .toApiCoverage( + traceHandler.processingStorage.getInstructionsCount( + Type.getInternalName(clazz) + ) + ) + } + + /** + * Transforms a list of internal [EtInstruction]s to a list of api [Instruction]s. + */ + private fun List.toApiCoverage(instructionsCount: Long? = null): Coverage = + Coverage( + map { Instruction(it.className, it.methodSignature, it.line, it.id) }, + instructionsCount + ) +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ValueConstructionContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ValueConstructionContext.kt new file mode 100644 index 0000000000..f700616cf6 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/phases/ValueConstructionContext.kt @@ -0,0 +1,66 @@ +package org.utbot.framework.concrete.phases + +import java.io.Closeable +import java.util.IdentityHashMap +import org.utbot.framework.concrete.constructors.MockValueConstructor +import org.utbot.framework.concrete.mock.InstrumentationContext +import org.utbot.framework.plugin.api.EnvironmentModels +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.UtConcreteValue +import org.utbot.framework.plugin.api.UtInstrumentation +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation +import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation +import org.utbot.framework.util.isInaccessibleViaReflection + +class ValueConstructionPhaseError(cause: Throwable) : PhaseError( + message = "Error during phase of constructing values from models", + cause +) + +/** + * This phase of values instantiation from given models. + */ +class ValueConstructionContext( + instrumentationContext: InstrumentationContext +) : PhaseContext, Closeable { + + override fun wrapError(error: Throwable): ValueConstructionPhaseError = + ValueConstructionPhaseError(error) + + private val constructor = MockValueConstructor(instrumentationContext) + + fun getCache(): IdentityHashMap { + return constructor.objectToModelCache + } + + fun constructParameters(state: EnvironmentModels): List> { + val parametersModels = listOfNotNull(state.thisInstance) + state.parameters + return constructor.constructMethodParameters(parametersModels) + } + + fun constructStatics(state: EnvironmentModels): Map> = + constructor.constructStatics( + state.statics.filterKeys { !it.isInaccessibleViaReflection } + ) + + fun mock(instrumentations: List) { + mockStaticMethods(instrumentations) + mockNewInstances(instrumentations) + } + + private fun mockStaticMethods(instrumentations: List) { + val staticMethodsInstrumentation = instrumentations.filterIsInstance() + constructor.mockStaticMethods(staticMethodsInstrumentation) + } + + private fun mockNewInstances(instrumentations: List) { + val newInstanceInstrumentation = instrumentations.filterIsInstance() + constructor.mockNewInstances(newInstanceInstrumentation) + } + + override fun close() { + constructor.close() + } + +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt index 7ed73a6c51..facabf617f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt @@ -27,7 +27,7 @@ import org.utbot.framework.UtSettings.warmupConcreteExecution import org.utbot.framework.plugin.api.utils.checkFrameworkDependencies import org.utbot.framework.concrete.UtConcreteExecutionData import org.utbot.framework.concrete.UtExecutionInstrumentation -import org.utbot.framework.concrete.UtModelConstructor +import org.utbot.framework.concrete.constructors.UtModelConstructor import org.utbot.framework.minimization.minimizeTestCase import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.id diff --git a/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt b/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt index 9ca0140c57..2b1012e4c6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt @@ -1,7 +1,7 @@ package org.utbot.fuzzer import org.utbot.common.isPublic -import org.utbot.framework.concrete.UtModelConstructor +import org.utbot.framework.concrete.constructors.UtModelConstructor import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel @@ -9,7 +9,6 @@ import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel -import org.utbot.framework.plugin.api.UtStatementModel import org.utbot.framework.plugin.api.util.defaultValueModel import org.utbot.framework.plugin.api.util.executableId import org.utbot.framework.plugin.api.util.id @@ -22,7 +21,6 @@ import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.kClass import org.utbot.fuzzer.providers.AbstractModelProvider import java.util.* -import java.util.function.IntSupplier import kotlin.collections.ArrayList import kotlin.collections.HashMap import kotlin.reflect.KClass diff --git a/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt b/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt index 3fc882774e..5101612b97 100644 --- a/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt +++ b/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt @@ -1,7 +1,7 @@ package api import fuzzer.providers.JsObjectModelProvider -import org.utbot.framework.concrete.UtModelConstructorInterface +import org.utbot.framework.concrete.contructors.UtModelConstructorInterface import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtExecutableCallModel