diff --git a/utbot-core/src/main/kotlin/org/utbot/common/ThreadUtil.kt b/utbot-core/src/main/kotlin/org/utbot/common/ThreadUtil.kt index 453f2d2468..66dc0eb4d0 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/ThreadUtil.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/ThreadUtil.kt @@ -31,11 +31,16 @@ class ThreadBasedExecutor { /** - * Invoke [action] with timeout. + * Invoke [action] with timeout and call [prepare] before without timeout. * - * [stopWatch] is used to respect specific situations (such as class loading and transforming) while invoking. + * @param stopWatch is used to respect specific situations (such as class loading and transforming) while invoking. */ - fun invokeWithTimeout(timeoutMillis: Long, stopWatch: StopWatch? = null, action:() -> Any?) : Result? { + fun invokeWithTimeout( + timeoutMillis: Long, + stopWatch: StopWatch? = null, + prepare: () -> Unit = {}, + action: () -> Any? + ) : Result? { if (thread?.isAlive != true) { requestQueue = ArrayBlockingQueue<() -> Any?>(1) responseQueue = ArrayBlockingQueue>(1) @@ -50,6 +55,9 @@ class ThreadBasedExecutor { } } + requestQueue.offer(prepare) + responseQueue.take().getOrThrow() + requestQueue.offer { try { stopWatch?.start() diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index ae9921257e..20455cc23a 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1277,13 +1277,20 @@ enum class CodegenLanguage( override fun toString(): String = id - fun getCompilationCommand(buildDirectory: String, classPath: String, sourcesFiles: List): List { + fun getCompilationCommand( + buildDirectory: String, + classPath: String, + sourcesFiles: List, + opens: List = emptyList() + ): List { val arguments = when (this) { - JAVA -> listOf( + JAVA -> opens.flatMap { + listOf("--add-opens", "$it=ALL-UNNAMED") + }.plus(listOf( "-d", buildDirectory, "-cp", classPath, "-XDignore.symbol.file" // to let javac use classes from rt.jar - ).plus(sourcesFiles) + )).plus(sourcesFiles) KOTLIN -> listOf("-d", buildDirectory, "-jvm-target", jvmTarget, "-cp", classPath).plus(sourcesFiles) } diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/ImageIOUsageTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/ImageIOUsageTest.kt new file mode 100644 index 0000000000..99bc6ad6b4 --- /dev/null +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/ImageIOUsageTest.kt @@ -0,0 +1,38 @@ +package org.utbot.examples.mixed + +import org.junit.jupiter.api.Test +import org.utbot.framework.plugin.api.MockStrategyApi +import org.utbot.framework.plugin.api.UtInstrumentation +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation +import org.utbot.framework.plugin.api.isNotNull +import org.utbot.framework.plugin.api.isNull +import org.utbot.testcheckers.eq +import org.utbot.tests.infrastructure.DoNotCalculate +import org.utbot.tests.infrastructure.UtValueTestCaseChecker + +internal class ImageIOUsageTest : UtValueTestCaseChecker( + testClass = ImageIOUsage::class, + testCodeGeneration = false +) { + + @Test + fun testIsAlphaPremultiplied() { + checkMocksAndInstrumentation( + ImageIOUsage::isAlphaPremultiplied, + eq(2), + { _, _, instrumentation, _ -> theOnlyStaticMockValue(instrumentation).isNull() }, + { _, _, instrumentation, _ -> theOnlyStaticMockValue(instrumentation).isNotNull() }, + coverage = DoNotCalculate, + mockStrategy = MockStrategyApi.OTHER_CLASSES + ) + } + + private fun theOnlyStaticMockValue(instrumentation: List): UtModel = + instrumentation + .filterIsInstance() + .single() + .values + .single() + +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt index bd454e3e83..6f12e82465 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt @@ -1,5 +1,7 @@ package org.utbot.framework.assemble +import java.lang.reflect.Constructor +import java.util.IdentityHashMap import org.utbot.common.isPrivate import org.utbot.common.isPublic import org.utbot.engine.ResolvedExecution @@ -36,11 +38,8 @@ import org.utbot.framework.plugin.api.hasDefaultValue import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.defaultValueModel import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.isSubtypeOf import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.util.nextModelName -import java.lang.reflect.Constructor -import java.util.IdentityHashMap /** * Creates [UtAssembleModel] from any [UtModel] or it's inner models if possible @@ -173,7 +172,7 @@ class AssembleModelGenerator(private val basePackageName: String) { val collectedCallChain = callChain.toMutableList() // We cannot create an assemble model for an anonymous class instance - if (utModel.classId.isAnonymous) { + if (utModel !is UtLambdaModel && utModel.classId.isAnonymous) { return utModel } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt index c7f3e214bd..5b24b763fc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstanceMockController.kt @@ -6,17 +6,17 @@ import org.objectweb.asm.Type class InstanceMockController( clazz: ClassId, - instances: List, - callSites: Set, + private val instances: List, + private val callSites: Set, ) : MockController { private val type = Type.getInternalName(clazz.jClass) - init { - InstrumentationContext.MockGetter.updateCallSites(type, callSites) - InstrumentationContext.MockGetter.updateMocks(null, "$type.", instances) + override fun init() { + MockGetter.updateCallSites(type, callSites) + MockGetter.updateMocks(type, instances) } override fun close() { - InstrumentationContext.MockGetter.updateCallSites(type, emptySet()) + MockGetter.updateCallSites(type, emptySet()) } } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt deleted file mode 100644 index 0233c7b6d9..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/InstrumentationContext.kt +++ /dev/null @@ -1,72 +0,0 @@ -package org.utbot.framework.concrete - -import org.utbot.framework.plugin.api.util.signature -import java.lang.reflect.Method -import java.util.IdentityHashMap - -/** - * Some information, which is computed after classes instrumentation. - * - * This information will be used later in `invoke` function. - */ -class InstrumentationContext { - /** - * Contains unique id for each method, which is required for this method mocking. - */ - val methodSignatureToId = mutableMapOf() - - object MockGetter { - data class MockContainer(private val values: List<*>) { - private var ptr: Int = 0 - fun hasNext(): Boolean = ptr < values.size - fun nextValue(): Any? = values[ptr++] - } - - /** - * Instance -> method -> list of values in the return order - */ - private val mocks = IdentityHashMap>() - private val callSites = HashMap>() - - /** - * Returns possibility of taking mock object of method with supplied [methodSignature] on an [obj] object. - */ - @JvmStatic - fun hasMock(obj: Any?, methodSignature: String): Boolean = - mocks[obj]?.get(methodSignature)?.hasNext() ?: false - - /** - * Returns the next value for mocked method with supplied [methodSignature] on an [obj] object. - * - * This function has only to be called from the instrumented bytecode everytime - * we need a next value for a mocked method. - */ - @JvmStatic - fun getMock(obj: Any?, methodSignature: String): Any? = - mocks[obj]?.get(methodSignature).let { container -> - container ?: error("Can't get mock container for method [$obj\$$methodSignature]") - container.nextValue() - } - - /** - * Returns current callSites for mocking new instance of [instanceType] contains [callSite] or not - */ - @JvmStatic - fun checkCallSite(instanceType: String, callSite: String): Boolean { - return callSites.getOrDefault(instanceType, emptySet()).contains(callSite) - } - - fun updateCallSites(instanceType: String, instanceCallSites: Set) { - callSites[instanceType] = instanceCallSites - } - - fun updateMocks(obj: Any?, methodSignature: String, values: List<*>) { - val methodMocks = mocks.getOrPut(obj) { mutableMapOf() } - methodMocks[methodSignature] = MockContainer(values) - } - - fun updateMocks(obj: Any?, method: Method, values: List<*>) { - updateMocks(obj, method.signature, values) - } - } -} diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt deleted file mode 100644 index 342c867a15..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MethodMockController.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.utbot.framework.concrete - -import org.utbot.common.withAccessibility -import org.utbot.framework.plugin.api.util.signature -import org.utbot.instrumentation.instrumentation.mock.MockConfig -import java.lang.reflect.Field -import java.lang.reflect.Method -import java.lang.reflect.Modifier - - -/** - * Helper class that handles work with mock fields. - * - * This object is created for every mocked method for a specific [instance]. There can be several [MethodMockController]s - * for the same [instance], but they will be constructed with different method parameters. - * - * @param [mockedValues] consists of return elements for this mocked method in the order of calling. - * @param [instance] is an object with mocked methods. Should be `null` for mocking static methods. - */ -class MethodMockController( - clazz: Class<*>, - method: Method, - val instance: Any?, - mockedValues: List, - instrumentationContext: InstrumentationContext -) : MockController { - private val isMockField: Field - - init { - if (!Modifier.isStatic(method.modifiers) && instance == null) { - error("$method is an instance method, but instance is null!") - } - - val id = instrumentationContext.methodSignatureToId[method.signature] - - isMockField = clazz.declaredFields.firstOrNull { it.name == MockConfig.IS_MOCK_FIELD + id } - ?: error("No field ${MockConfig.IS_MOCK_FIELD + id} in $clazz") - - isMockField.withAccessibility { - isMockField.set(instance, true) - } - - if (method.returnType != Void.TYPE) { - InstrumentationContext.MockGetter.updateMocks(instance, method, mockedValues) - } - } - - override fun close() { - isMockField.withAccessibility { - isMockField.set(instance, false) - } - } -} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt index 679925c30e..1255fc98fc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockController.kt @@ -2,4 +2,9 @@ package org.utbot.framework.concrete import java.io.Closeable -interface MockController : Closeable \ No newline at end of file +interface MockController : Closeable { + /** + * Will be called before invocation on the same thread. + */ + fun init() +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockGetter.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockGetter.kt new file mode 100644 index 0000000000..06324b5773 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockGetter.kt @@ -0,0 +1,54 @@ +package org.utbot.framework.concrete + +/** + * Some information for mocking new instance. + */ +object MockGetter { + data class MockContainer(private val values: List<*>) { + private var ptr: Int = 0 + fun hasNext(): Boolean = ptr < values.size + fun nextValue(): Any? = values[ptr++] + } + + /** + * Class -> list of values in the return order. + */ + private val mocks = mutableMapOf() + private val callSites = HashMap>() + + /** + * Returns possibility of taking mock object of [className]. + */ + @JvmStatic + fun hasMock(className: String): Boolean = + mocks[className]?.hasNext() ?: false + + /** + * Returns the next value for mocked [className]. + * + * This function has only to be called from the instrumented bytecode everytime + * we need a next value for a mocked new instance. + */ + @JvmStatic + fun getMock(className: String): Any? = + mocks[className].let { container -> + container ?: error("Can't get mock container for $className") + container.nextValue() + } + + /** + * Returns current callSites for mocking new instance of [instanceType] contains [callSite] or not + */ + @JvmStatic + fun checkCallSite(instanceType: String, callSite: String): Boolean { + return callSites.getOrDefault(instanceType, emptySet()).contains(callSite) + } + + fun updateCallSites(instanceType: String, instanceCallSites: Set) { + callSites[instanceType] = instanceCallSites + } + + fun updateMocks(className: String, values: List<*>) { + mocks[className] = MockContainer(values) + } +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockUtil.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockUtil.kt new file mode 100644 index 0000000000..0f1155a690 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockUtil.kt @@ -0,0 +1,32 @@ +package org.utbot.framework.concrete + +import org.mockito.stubbing.Answer +import org.utbot.framework.plugin.api.ExecutableId +import org.utbot.framework.plugin.api.util.executableId + +/** + * Create [Answer] that mocks each method by specified values in order. + * If there isn't next value it will call real method. + */ +fun buildAnswer( + methodToValues: Map> +) : Answer { + val pointers = methodToValues.mapValues { (_, _) -> 0 }.toMutableMap() + val answer = Answer { invocation -> + with(invocation.method) { + pointers[executableId].let { pointer -> + methodToValues[executableId].let { values -> + if (pointer != null && values != null && pointer < values.size) { + pointers[executableId] = pointer + 1 + values[pointer].run { + if (this is Unit) null else this + } + } else { + invocation.callRealMethod() + } + } + } + } + } + return answer +} diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt index 182c0c2f9d..0194b30184 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt @@ -1,6 +1,17 @@ package org.utbot.framework.concrete +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.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.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.ExecutableId @@ -20,6 +31,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 @@ -30,25 +42,12 @@ import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation 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.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 /** @@ -62,9 +61,7 @@ import org.utbot.instrumentation.process.runSandbox * Note that `clearState` was deleted! */ // TODO: JIRA:1379 -- Refactor ValueConstructor and MockValueConstructor -class MockValueConstructor( - private val instrumentationContext: InstrumentationContext -) : Closeable { +class MockValueConstructor : Closeable { private val classLoader: ClassLoader get() = utContext.classLoader @@ -86,7 +83,7 @@ class MockValueConstructor( /** * Controllers contain info about mocked methods and have to be closed to restore initial state. */ - private val controllers = mutableListOf() + val controllers = mutableListOf() /** * Sets mock context (possible mock target) before block execution and restores previous one after block execution. @@ -202,8 +199,7 @@ class MockValueConstructor( return classInstance } - private fun generateMockitoAnswer(methodToValues: Map>): Answer<*> { - val pointers = methodToValues.mapValues { (_, _) -> 0 }.toMutableMap() + private fun generateMockitoAnswer(methodToValues: Map>): Answer<*> { val concreteValues = methodToValues.mapValues { (_, models) -> models.map { model -> val mockId = MockId("mock${++mockCounter}") @@ -212,20 +208,7 @@ class MockValueConstructor( // This model has to be already constructed, so it is OK to pass null as a target } } - return Answer { invocation -> - with(invocation.method) { - pointers[executableId].let { pointer -> - concreteValues[executableId].let { values -> - if (pointer != null && values != null && pointer < values.size) { - pointers[executableId] = pointer + 1 - values[pointer] - } else { - invocation.callRealMethod() - } - } - } - } - } + return buildAnswer(concreteValues) } private fun generateMockitoMock(clazz: Class<*>, mocks: Map>): Any { @@ -238,34 +221,15 @@ class MockValueConstructor( models.map { mockAndGet(it) } } - /** - * Mocks methods on [instance] with supplied [methodToValues]. - * - * Also add new controllers to [controllers]. Each controller corresponds to one method. If it is a static method, then the controller - * must be closed. If it is a non-static method and you don't change the mocks behaviour on the passed instance, - * then the controller doesn't have to be closed - * - * @param [instance] must be non-`null` for non-static methods. - * @param [methodToValues] return values for methods. - */ - private fun mockMethods( - instance: Any?, - methodToValues: Map>, - ) { - controllers += computeConcreteValuesForMethods(methodToValues).map { (method, values) -> - if (method !is MethodId) { - throw IllegalArgumentException("Expected MethodId, but got: $method") + private fun groupByClass( + methodToModels: Map> + ): Map>> = + methodToModels + .asIterable() + .groupBy { it.key.classId } + .mapValues { (_, entries) -> + entries.associate { it.key to it.value } } - MethodMockController( - method.classId.jClass, - method.method, - instance, - values, - instrumentationContext - ) - } - - } /** * Mocks static methods according to instrumentations. @@ -273,8 +237,12 @@ class MockValueConstructor( fun mockStaticMethods( instrumentations: List, ) { - val methodToValues = instrumentations.associate { it.methodId as ExecutableId to it.values } - mockMethods(null, methodToValues) + val methodToModels = instrumentations.associate { (it.methodId as ExecutableId) to it.values } + val methodToModelsGroupedByClass = groupByClass(methodToModels) + controllers += methodToModelsGroupedByClass.map { (classId, method2modelValues) -> + val methodToValues = computeConcreteValuesForMethods(method2modelValues) + StaticMethodMockController(classId.jClass, methodToValues) + } } /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StaticMethodMockController.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StaticMethodMockController.kt new file mode 100644 index 0000000000..31edf10513 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StaticMethodMockController.kt @@ -0,0 +1,30 @@ +package org.utbot.framework.concrete + +import org.mockito.MockedStatic +import org.mockito.Mockito +import org.utbot.framework.plugin.api.ExecutableId + + +/** + * Helper class that handles work with mockito. + * + * This object is created for every mocked static method for a specific [clazz]. There can't be several [StaticMethodMockController]s + * for the same [clazz]. + * + * @param [methodToValues] consists of return elements for mocked methods in the order of calling. + */ +class StaticMethodMockController( + private val clazz: Class<*>, + private val methodToValues: Map> +) : MockController { + + override fun init() { + mockStatic = Mockito.mockStatic(clazz, buildAnswer(methodToValues)) + } + + private lateinit var mockStatic: MockedStatic<*> + + override fun close() { + mockStatic.close() + } +} \ No newline at end of file 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 ab0b69e8b2..b940bee651 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,5 +1,9 @@ package org.utbot.framework.concrete +import java.security.AccessControlException +import java.security.ProtectionDomain +import java.util.IdentityHashMap +import kotlin.reflect.jvm.javaMethod import org.objectweb.asm.Type import org.utbot.common.StopWatch import org.utbot.common.ThreadBasedExecutor @@ -42,10 +46,6 @@ 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. @@ -117,8 +117,6 @@ class UtConcreteExecutionResult( object UtExecutionInstrumentation : Instrumentation { private val delegateInstrumentation = InvokeInstrumentation() - private val instrumentationContext = InstrumentationContext() - private val traceHandler = TraceHandler() private val pathsToUserClasses = mutableSetOf() @@ -150,7 +148,7 @@ object UtExecutionInstrumentation : Instrumentation { val returnClassId = methodId.returnType traceHandler.resetTrace() - return MockValueConstructor(instrumentationContext).use { constructor -> + return MockValueConstructor().use { constructor -> val params = try { constructor.constructMethodParameters(parametersModels) } catch (e: Throwable) { @@ -178,10 +176,16 @@ object UtExecutionInstrumentation : Instrumentation { 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) { + val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout( + timeout, + stopWatch, + prepare = { // it's needed to call mockStatic on invocation's thread + constructor.controllers.forEach(MockController::init) + traceHandler.resetTrace() + } + ) { withUtContext(context) { delegateInstrumentation.invoke(clazz, methodSignature, params.map { it.value }) } @@ -282,19 +286,15 @@ object UtExecutionInstrumentation : Instrumentation { traceHandler.registerClass(className) instrumenter.visitInstructions(traceHandler.computeInstructionVisitor(className)) - val mockClassVisitor = instrumenter.visitClass { writer -> + instrumenter.visitClass { writer -> MockClassVisitor( writer, - InstrumentationContext.MockGetter::getMock.javaMethod!!, - InstrumentationContext.MockGetter::checkCallSite.javaMethod!!, - InstrumentationContext.MockGetter::hasMock.javaMethod!! + MockGetter::getMock.javaMethod!!, + MockGetter::checkCallSite.javaMethod!!, + MockGetter::hasMock.javaMethod!! ) } - mockClassVisitor.signatureToId.forEach { (method, id) -> - instrumentationContext.methodSignatureToId += method to id - } - return instrumenter.classByteCode } diff --git a/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/CompilationAndRunUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/CompilationAndRunUtils.kt index ddf523586a..cb9a68faee 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/CompilationAndRunUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/CompilationAndRunUtils.kt @@ -39,17 +39,45 @@ fun writeTest( return writeFile(testContents, classUnderTest.generatedTestFile) } +private const val compilationTries = 2 + +private data class UnnamedPackageInfo(val pack: String, val module: String) + +private fun findAllNotVisiblePackages(report: String): List { + val regex = """package ([\d\w.]+) is declared in module ([\d\w.]+), which does not export it to the unnamed module""".toRegex() + return regex.findAll(report).map { + val pack = it.groupValues[1] + val module = it.groupValues[2] + UnnamedPackageInfo(pack, module) + }.toList().distinct() +} + fun compileTests( buildDirectory: String, sourcesFiles: List, generatedLanguage: CodegenLanguage ) { val classpath = System.getProperty("java.class.path") - val command = generatedLanguage.getCompilationCommand(buildDirectory, classpath, sourcesFiles) - - logger.trace { "Command to compile [${sourcesFiles.joinToString(" ")}]: [${command.joinToString(" ")}]" } - val exitCode = execCommandLine(command, "Tests compilation") - logger.info { "Compilation exit code: $exitCode" } + var command: List = generatedLanguage.getCompilationCommand(buildDirectory, classpath, sourcesFiles) + + repeat(compilationTries) { iter -> + try { + logger.trace { "Command to compile [${sourcesFiles.joinToString(" ")}]: [${command.joinToString(" ")}]" } + val exitCode = execCommandLine(command, "Tests compilation") + logger.info { "Compilation exit code: $exitCode" } + return + } catch (e: ReportByProcessException) { + if (iter + 1 == compilationTries) { + throw e + } + val unnamedPackages = e.report?.let { findAllNotVisiblePackages(it) } ?: emptyList() + val opens = unnamedPackages.map { + "${it.module}/${it.pack}" + } + logger.info { "Add opens: ${opens.joinToString()}" } + command = generatedLanguage.getCompilationCommand(buildDirectory, classpath, sourcesFiles, opens) + } + } } fun runTests( @@ -100,6 +128,8 @@ private fun constructProcess(command: List, classpath: String? = null): return process } +private class ReportByProcessException(val report: String? = null, message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause) + private fun generateReportByProcess(process: Process, executionName: String, command: List): Int { val report = process.inputStream.reader().readText() @@ -110,7 +140,7 @@ private fun generateReportByProcess(process: Process, executionName: String, com if (exitCode != 0) { logger.warn { "Exit code for process run: $exitCode" } logger.warn { "The command line led to the pipeline failure: [${command.joinToString(" ")}]" } - throw RuntimeException("$executionName failed with non-zero exit code = $exitCode") + throw ReportByProcessException(report, "$executionName failed with non-zero exit code = $exitCode") } return exitCode diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt index c80e1a7714..64468c52e1 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/agent/DynamicClassTransformer.kt @@ -52,7 +52,6 @@ class DynamicClassTransformer : ClassFileTransformer { companion object { private val packsToAlwaysTransform = listOf( - "org/slf4j", "org/utbot/instrumentation/warmup" ) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/mock/MockClassVisitor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/mock/MockClassVisitor.kt index 37dceb7efe..29fb95059f 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/mock/MockClassVisitor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/mock/MockClassVisitor.kt @@ -1,7 +1,5 @@ package org.utbot.instrumentation.instrumentation.mock -import org.utbot.instrumentation.Settings -import org.utbot.instrumentation.instrumentation.instrumenter.visitors.util.FieldInitializer import java.lang.reflect.Method import org.objectweb.asm.ClassVisitor import org.objectweb.asm.Label @@ -10,10 +8,7 @@ import org.objectweb.asm.Opcodes import org.objectweb.asm.Type import org.objectweb.asm.commons.AdviceAdapter import org.objectweb.asm.commons.Method.getMethod - -object MockConfig { - const val IS_MOCK_FIELD = "\$__is_mock_" -} +import org.utbot.instrumentation.Settings class MockClassVisitor( classVisitor: ClassVisitor, @@ -21,10 +16,7 @@ class MockClassVisitor( callSiteChecker: Method, hasMock: Method ) : ClassVisitor(Settings.ASM_API, classVisitor) { - val signatureToId = mutableMapOf() - private lateinit var internalClassName: String - private val extraFields = mutableListOf() private val mockGetterOwner = Type.getType(mockGetter.declaringClass) private val mockGetterMethod = getMethod(mockGetter) @@ -57,30 +49,19 @@ class MockClassVisitor( val isNotSynthetic = access.and(Opcodes.ACC_SYNTHETIC) == 0 // we do not want to mock or or synthetic methods return if (name != "" && name != "" && isNotSynthetic) { - visitStaticMethod(access, name, descriptor, signature, exceptions) + visitMethodImpl(access, name, descriptor, signature, exceptions) } else { cv.visitMethod(access, name, descriptor, signature, exceptions) } } - private fun visitStaticMethod( + private fun visitMethodImpl( access: Int, name: String, descriptor: String, signature: String?, exceptions: Array? ): MethodVisitor { - val isStatic = access and Opcodes.ACC_STATIC != 0 - val isVoidMethod = Type.getReturnType(descriptor) == Type.VOID_TYPE - - val computedSignature = name + descriptor - val id = signatureToId.size - signatureToId[computedSignature] = id - - val isMockInitializer = - StaticPrimitiveInitializer(internalClassName, MockConfig.IS_MOCK_FIELD + id, Type.BOOLEAN_TYPE) - extraFields += isMockInitializer - val mv = cv.visitMethod(access, name, descriptor, signature, exceptions) return object : AdviceAdapter(Settings.ASM_API, mv, access, name, descriptor) { @@ -98,15 +79,13 @@ class MockClassVisitor( invokeStatic(callSiteCheckerOwner, callSiteCheckerMethod) ifZCmp(IFEQ, newLabel) - // if (hasMock(null, type.)) - visitInsn(ACONST_NULL) - push("$type.") + // if (hasMock(type)) + push(type) invokeStatic(hasMockOwner, hasMockMethod) ifZCmp(IFEQ, newLabel) - // getMock(null, type.) - visitInsn(ACONST_NULL) - push("$type.") + // getMock(type) + push(type) invokeStatic(mockGetterOwner, mockGetterMethod) visitTypeInsn(CHECKCAST, type) goTo(afterLabel) @@ -129,67 +108,7 @@ class MockClassVisitor( afterLabels.removeLastOrNull()?.let { visitLabel(it) } } } - - override fun onMethodEnter() { - val afterIfLabel = Label() - - visitFieldInsn( - GETSTATIC, - internalClassName, - isMockInitializer.name, - isMockInitializer.descriptor - ) - ifZCmp(IFEQ, afterIfLabel) - - if (isVoidMethod) { - visitInsn(RETURN) - } else { - if (isStatic) { - visitInsn(ACONST_NULL) - } else { - loadThis() - } - push(computedSignature) - - invokeStatic(hasMockOwner, hasMockMethod) - ifZCmp(IFEQ, afterIfLabel) - - if (isStatic) { - visitInsn(ACONST_NULL) - } else { - loadThis() - } - push(computedSignature) - - invokeStatic(mockGetterOwner, mockGetterMethod) - - if (returnType.sort == Type.OBJECT || returnType.sort == Type.ARRAY) { - checkCast(returnType) - } else { // primitive here - unbox(returnType) - } - returnValue() - } - - visitLabel(afterIfLabel) - } } } - - override fun visitEnd() { - extraFields.forEach { addField(it) } - cv.visitEnd() - } - - private fun addField(field: FieldInitializer) { - val fv = cv.visitField( - Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_FINAL, - field.name, - field.descriptor, - field.signature, - null - ) - fv.visitEnd() - } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt index e49e207fa2..1cdfb7ee62 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt @@ -2,6 +2,14 @@ package org.utbot.instrumentation.process import com.jetbrains.rd.util.* import com.jetbrains.rd.util.lifetime.Lifetime +import java.io.File +import java.io.OutputStream +import java.io.PrintStream +import java.net.URLClassLoader +import java.security.AllPermission +import kotlin.system.measureTimeMillis +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.* import org.utbot.common.* import org.utbot.framework.plugin.api.util.UtContext @@ -17,14 +25,6 @@ import org.utbot.rd.CallsSynchronizer import org.utbot.rd.ClientProtocolBuilder import org.utbot.rd.findRdPort import org.utbot.rd.loggers.UtRdConsoleLoggerFactory -import java.io.File -import java.io.OutputStream -import java.io.PrintStream -import java.net.URLClassLoader -import java.security.AllPermission -import kotlin.system.measureTimeMillis -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds /** * We use this ClassLoader to separate user's classes and our dependency classes. @@ -34,19 +34,6 @@ internal object HandlerClassesLoader : URLClassLoader(emptyArray()) { fun addUrls(urls: Iterable) { urls.forEach { super.addURL(File(it).toURI().toURL()) } } - - /** - * System classloader can find org.slf4j thus when we want to mock something from org.slf4j - * we also want this class will be loaded by [HandlerClassesLoader] - */ - override fun loadClass(name: String, resolve: Boolean): Class<*> { - if (name.startsWith("org.slf4j")) { - return (findLoadedClass(name) ?: findClass(name)).apply { - if (resolve) resolveClass(this) - } - } - return super.loadClass(name, resolve) - } } /** diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/MockHelper.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/MockHelper.kt index e7b10fc982..145fdaf213 100644 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/MockHelper.kt +++ b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/MockHelper.kt @@ -1,14 +1,9 @@ package org.utbot.instrumentation.examples.mock -import org.utbot.common.withAccessibility -import org.utbot.framework.plugin.api.util.signature -import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter -import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor -import org.utbot.instrumentation.instrumentation.mock.MockConfig -import java.lang.reflect.Method -import java.util.IdentityHashMap import kotlin.reflect.jvm.javaMethod import org.objectweb.asm.Type +import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter +import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor /** * Helper for generating tests with methods mocks. @@ -47,31 +42,11 @@ class MockHelper( instrumentedClazz = memoryClassLoader.loadClass(clazz.name) } - inline fun withMockedMethod(method: Method, instance: Any?, mockedValues: List<*>, block: (Any?) -> T): T { - if (method.returnType == Void.TYPE) { - error("Can't mock function returning void!") - } - - val sign = method.signature - val methodId = mockClassVisitor.signatureToId[sign] - - val isMockField = instrumentedClazz.getDeclaredField(MockConfig.IS_MOCK_FIELD + methodId) - MockGetter.updateMocks(instance, method, mockedValues) - - return isMockField.withAccessibility { - isMockField.set(instance, true) - val res = block(instance) - isMockField.set(instance, false) - res - } - } - inline fun withMockedConstructor(clazz: Class<*>, callSites: Set>, mockedValues: List<*>, block: () -> T): T { val type = Type.getInternalName(clazz) - val sign = "$type." MockGetter.updateCallSites(type, callSites.map { Type.getInternalName(it) }.toSet()) - MockGetter.updateMocks(null, sign, mockedValues) + MockGetter.updateMocks(type, mockedValues) val res = block() @@ -79,6 +54,10 @@ class MockHelper( return res } + + /** + * Some information for mocking new instance. + */ object MockGetter { data class MockContainer(private val values: List<*>) { private var ptr: Int = 0 @@ -87,27 +66,28 @@ class MockHelper( } /** - * Instance -> method -> list of values in the return order + * Class -> list of values in the return order. */ - private val mocks = IdentityHashMap>() + private val mocks = mutableMapOf() private val callSites = HashMap>() /** - * Returns possibility of taking mock object of method with supplied [methodSignature] on an [obj] object. + * Returns possibility of taking mock object of [className]. */ @JvmStatic - fun hasMock(obj: Any?, methodSignature: String): Boolean = - mocks[obj]?.get(methodSignature)?.hasNext() ?: false + fun hasMock(className: String): Boolean = + mocks[className]?.hasNext() ?: false + /** - * Returns the next value for mocked method with supplied [methodSignature] on an [obj] object. + * Returns the next value for mocked [className]. * * This function has only to be called from the instrumented bytecode everytime - * we need a next value for a mocked method. + * we need a next value for a mocked new instance. */ @JvmStatic - fun getMock(obj: Any?, methodSignature: String): Any? = - mocks[obj]?.get(methodSignature).let { container -> - container ?: error("Can't get mock container for method [$obj\$$methodSignature]") + fun getMock(className: String): Any? = + mocks[className].let { container -> + container ?: error("Can't get mock container for $className") container.nextValue() } @@ -123,13 +103,8 @@ class MockHelper( callSites[instanceType] = instanceCallSites } - fun updateMocks(obj: Any?, methodSignature: String, values: List<*>) { - val methodMocks = mocks.getOrPut(obj) { mutableMapOf() } - methodMocks[methodSignature] = MockContainer(values) - } - - fun updateMocks(obj: Any?, method: Method, values: List<*>) { - updateMocks(obj, method.signature, values) + fun updateMocks(className: String, values: List<*>) { + mocks[className] = MockContainer(values) } } } \ No newline at end of file diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestIncompleteMock.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestIncompleteMock.kt deleted file mode 100644 index 9610580834..0000000000 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestIncompleteMock.kt +++ /dev/null @@ -1,164 +0,0 @@ -package org.utbot.instrumentation.examples.mock - -import org.utbot.common.withAccessibility -import org.utbot.instrumentation.samples.mock.ClassForMock -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test - -class TestIncompleteMock { - @Test - fun testClassForMock_getX() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "getX" } - - val defaultValue = 15 - assertEquals(defaultValue, method.invoke(instance)) - - val mockValues = listOf(1, 2, 3, 4, 5) - mockHelper.withMockedMethod(method, instance, mockValues) { - mockValues.forEach { - assertEquals(it, method.invoke(instance)) - } - // must call real function - (1..5).forEach { _ -> - assertEquals(defaultValue, method.invoke(instance)) - } - } - } - - @Test - fun getClassForMock_getX_multipleCalls() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "getX" } - val xField = instrumentedClazz.getDeclaredField("x") - - var currentX = 15 - assertEquals(currentX, method.invoke(instance)) - - val mockValues1 = listOf(1, 2, 3, 4, 5) - mockHelper.withMockedMethod(method, instance, mockValues1) { - mockValues1.forEach { - assertEquals(it, method.invoke(instance)) - } - (1..5).forEach { value -> - currentX = value - xField.apply { - withAccessibility { - setInt(instance, value) - } - } - assertEquals(currentX, method.invoke(instance)) - } - } - - assertEquals(currentX, method.invoke(instance)) // should be the same as it was before mocking - - val mockValues2 = listOf(-1, -2, -3, -4, -5) - mockHelper.withMockedMethod(method, instance, mockValues2) { - mockValues2.forEach { - assertEquals(it, method.invoke(instance)) - } - (1..5).forEach { _ -> - assertEquals(currentX, method.invoke(instance)) - } - } - } - - @Test - fun testClassForMock_getString() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = null // static method - val method = instrumentedClazz.declaredMethods.first { it.name == "getString" } - - val defaultValue = "string" - assertEquals(defaultValue, method.invoke(instance)) - - val mockValues = listOf("a", "b", "c", "aa", "", "aaaaaa") - mockHelper.withMockedMethod(method, instance, mockValues) { - mockValues.forEach { - assertEquals(it, method.invoke(instance)) - } - (1..5).forEach { _ -> - assertEquals(defaultValue, method.invoke(instance)) - } - } - } - - @Test - fun testClassForMock_complicateMethod() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "complicatedMethod" } - - assertEquals("x + y == z", method.invoke(instance, 1, 2, 3, null)) - - val mockValues1 = listOf("azaza", "lol", "ha", "kek") - mockHelper.withMockedMethod(method, instance, mockValues1) { - mockValues1.forEach { - assertEquals(it, method.invoke(instance, 1, 2, 3, instance)) - } - assertEquals("none", method.invoke(instance, 1, 2, 6, null)) - assertEquals("x + y == z", method.invoke(instance, 1, 2, 3, null)) - assertEquals("equals", method.invoke(instance, 0, 0, 0, instance)) - } - - assertEquals("equals", method.invoke(instance, 0, 0, 0, instance)) - - val mockValues2 = listOf("ok", "ok", "", "da") - mockHelper.withMockedMethod(method, instance, mockValues2) { - mockValues2.forEach { - assertEquals(it, method.invoke(instance, 1, 2, 3, instance)) - } - assertEquals("none", method.invoke(instance, 1, 2, 6, null)) - assertEquals("x + y == z", method.invoke(instance, 1, 2, 3, null)) - assertEquals("equals", method.invoke(instance, 0, 0, 0, instance)) - } - } - - @Test - fun testClassForMock_provideInt_mocksBoth() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance1 = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val instance2 = instrumentedClazz.constructors.first { it.parameters.size == 1 }.newInstance("") - val method = instrumentedClazz.declaredMethods.first { it.name == "provideInt" } - - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - - mockHelper.withMockedMethod(method, instance1, listOf(3, 3)) { - mockHelper.withMockedMethod(method, instance2, listOf(1, 3)) { - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - assertEquals(method.invoke(instance1), method.invoke(instance2)) - assertEquals(15, method.invoke(instance1)) - assertEquals(10, method.invoke(instance2)) - } - } - } - - @Test - fun testClassForMock_check_usesMockedValues() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance1 = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val instance2 = instrumentedClazz.constructors.first { it.parameters.size == 1 }.newInstance("") - val method = instrumentedClazz.declaredMethods.first { it.name == "provideInt" } - val methodCheck = instrumentedClazz.declaredMethods.first { it.name == "check" } - - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - - mockHelper.withMockedMethod(method, instance1, listOf(3, 3)) { - mockHelper.withMockedMethod(method, instance2, listOf(1, 3)) { - assertEquals(false, methodCheck.invoke(instance1, instance2)) - assertEquals(true, methodCheck.invoke(instance1, instance2)) - assertEquals(false, methodCheck.invoke(instance1, instance2)) - } - } - } -} \ No newline at end of file diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInstanceMethodMock.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInstanceMethodMock.kt deleted file mode 100644 index 1da24f04be..0000000000 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInstanceMethodMock.kt +++ /dev/null @@ -1,85 +0,0 @@ -package org.utbot.instrumentation.examples.mock - -import org.utbot.instrumentation.samples.mock.ClassForMockInstanceMethods -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - -class TestInstanceMethodMock { - private fun testMethod(methodName: String, mockedValues: List<*>) { - val mockHelper = MockHelper(ClassForMockInstanceMethods::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == methodName } - method.isAccessible = true - - mockHelper.withMockedMethod(method, instance, mockedValues) { - mockedValues.forEach { - assertEquals(it, method.invoke(instance)) - } - } - } - - @Test - fun testInt() { - testMethod("testI", listOf(0, 0, 1, 10, -20)) - } - - @Test - fun testLong() { - testMethod("testL", listOf(0L, 1L, -1L, 1337L)) - } - - @Test - fun testObject() { - testMethod( - "testObject", - listOf(ClassForMockInstanceMethods.SomeClass(1337), ClassForMockInstanceMethods.SomeClass(228)) - ) - } - - @Test - fun testChar() { - testMethod("testChar", listOf('a', 'Z', 0.toChar(), 255.toChar(), '-', '\n')) - } - - @Test - fun testFloat() { - testMethod("testFloat", listOf(1.0f, -1.0f)) - } - - @Test - fun testByte() { - testMethod("testByte", listOf(1.toByte(), (-1).toByte())) - } - - @Test - fun testDouble() { - testMethod("testDouble", listOf(1.0, -1.0, 1337.0)) - } - - @Test - fun testArray() { - testMethod("testArray", listOf(intArrayOf(1, 2, 3), intArrayOf(-1, -2, -3))) - } - - @Test - fun testShort() { - testMethod("testShort", listOf(1.toShort(), 2.toShort(), 3.toShort())) - } - - @Test - fun testBoolean() { - testMethod("testBoolean", listOf(false, true, true, false, false)) - } - - @Test - fun testVoid() { - assertThrows { - testMethod( - "testVoid", - listOf(null, "Kek", 1337) - ) // we don't have to instrument function returning void at any case - } - } -} \ No newline at end of file diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInterfaceMock.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInterfaceMock.kt deleted file mode 100644 index 3f493aa059..0000000000 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestInterfaceMock.kt +++ /dev/null @@ -1,48 +0,0 @@ -package org.utbot.instrumentation.examples.mock - -import org.utbot.instrumentation.samples.mock.ClassForMockInterface -import org.utbot.instrumentation.samples.mock.IProvider -import java.lang.reflect.Method -import kotlin.reflect.jvm.javaMethod -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - - -@Disabled("Mocking interfaces is not supported by our instrumentation (we use Mockito for them)") -class TestInterfaceMock { - private fun testMethod(method: Method, clazz: Class<*>, mockedValues: List<*>) { - val mockHelper = MockHelper(method.declaringClass) - val mockHelperClass = MockHelper(clazz) - val instrumentedMethod = mockHelper.instrumentedClazz.declaredMethods.first { it.name == method.name } - val instance = mockHelperClass.instrumentedClazz.newInstance() - instrumentedMethod.isAccessible = true - - mockHelper.withMockedMethod(instrumentedMethod, instance, mockedValues) { - mockedValues.forEach { - System.err.println(instrumentedMethod.declaringClass.cast(instance)) - assertEquals(it, instrumentedMethod.invoke(instance)) - } - } - } - - - @Test - fun testInt() { - testMethod(ClassForMockInterface::provideInt.javaMethod!!, ClassForMockInterface::class.java, listOf(3, 2, 1)) - } - - @Test - fun testIntDefault() { - testMethod( - ClassForMockInterface::provideIntDefault.javaMethod!!, - ClassForMockInterface::class.java, - listOf(3, 2, 1) - ) - } - - @Test - fun testString() { - testMethod(IProvider::provideInt.javaMethod!!, ClassForMockInterface::class.java, listOf(3, 2, 1)) - } -} \ No newline at end of file diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestMock.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestMock.kt deleted file mode 100644 index 088ae7e8f9..0000000000 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestMock.kt +++ /dev/null @@ -1,132 +0,0 @@ -package org.utbot.instrumentation.examples.mock - -import org.utbot.instrumentation.samples.mock.ClassForMock -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test - -class TestMock { - @Test - fun testClassForMock_getX() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "getX" } - - assertEquals(15, method.invoke(instance)) - - val mockValues = listOf(1, 2, 3, 4, 5) - mockHelper.withMockedMethod(method, instance, mockValues) { - mockValues.forEach { - assertEquals(it, method.invoke(instance)) - } - } - } - - @Test - fun getClassForMock_getX_multipleCalls() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "getX" } - - assertEquals(15, method.invoke(instance)) - - val mockValues1 = listOf(1, 2, 3, 4, 5) - mockHelper.withMockedMethod(method, instance, mockValues1) { - mockValues1.forEach { - assertEquals(it, method.invoke(instance)) - } - } - - assertEquals(15, method.invoke(instance)) // should be the same as it was before mocking - - val mockValues2 = listOf(-1, -2, -3, -4, -5) - mockHelper.withMockedMethod(method, instance, mockValues2) { - mockValues2.forEach { - assertEquals(it, method.invoke(instance)) - } - } - } - - @Test - fun testClassForMock_getString() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = null // static method - val method = instrumentedClazz.declaredMethods.first { it.name == "getString" } - - assertEquals("string", method.invoke(instance)) - - val mockValues = listOf("a", "b", "c", "aa", "", "aaaaaa") - mockHelper.withMockedMethod(method, instance, mockValues) { - mockValues.forEach { - assertEquals(it, method.invoke(instance)) - } - } - } - - @Test - fun testClassForMock_complicateMethod() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val method = instrumentedClazz.declaredMethods.first { it.name == "complicatedMethod" } - - assertEquals("x + y == z", method.invoke(instance, 1, 2, 3, null)) - - val mockValues1 = listOf("azaza", "lol", "ha", "kek") - mockHelper.withMockedMethod(method, instance, mockValues1) { - mockValues1.forEach { - assertEquals(it, method.invoke(instance, 1, 2, 3, instance)) - } - } - - assertEquals("equals", method.invoke(instance, 0, 0, 0, instance)) - - val mockValues2 = listOf("ok", "ok", "", "da") - mockHelper.withMockedMethod(method, instance, mockValues2) { - mockValues2.forEach { - assertEquals(it, method.invoke(instance, 1, 2, 3, instance)) - } - } - } - - @Test - fun testClassForMock_provideInt_mocksBoth() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance1 = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val instance2 = instrumentedClazz.constructors.first { it.parameters.size == 1 }.newInstance("") - val method = instrumentedClazz.declaredMethods.first { it.name == "provideInt" } - - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - - mockHelper.withMockedMethod(method, instance1, listOf(3, 3)) { - mockHelper.withMockedMethod(method, instance2, listOf(1, 3)) { - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - assertEquals(method.invoke(instance1), method.invoke(instance2)) - } - } - } - - @Test - fun testClassForMock_check_usesMockedValues() { - val mockHelper = MockHelper(ClassForMock::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance1 = instrumentedClazz.constructors.first { it.parameters.isEmpty() }.newInstance() - val instance2 = instrumentedClazz.constructors.first { it.parameters.size == 1 }.newInstance("") - val method = instrumentedClazz.declaredMethods.first { it.name == "provideInt" } - val methodCheck = instrumentedClazz.declaredMethods.first { it.name == "check" } - - assertNotEquals(method.invoke(instance1), method.invoke(instance2)) - - mockHelper.withMockedMethod(method, instance1, listOf(3, 3)) { - mockHelper.withMockedMethod(method, instance2, listOf(1, 3)) { - assertEquals(false, methodCheck.invoke(instance1, instance2)) - assertEquals(true, methodCheck.invoke(instance1, instance2)) - } - } - } -} - diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestStaticMethodMock.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestStaticMethodMock.kt deleted file mode 100644 index a9d5dc6cf8..0000000000 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/examples/mock/TestStaticMethodMock.kt +++ /dev/null @@ -1,85 +0,0 @@ -package org.utbot.instrumentation.examples.mock - -import org.utbot.instrumentation.samples.mock.ClassForMockStaticMethods -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - -class TestStaticMethodMock { - private fun testMethod(methodName: String, mockedValues: List<*>) { - val mockHelper = MockHelper(ClassForMockStaticMethods::class.java) - val instrumentedClazz = mockHelper.instrumentedClazz - val instance = null - val method = instrumentedClazz.declaredMethods.first { it.name == methodName } - method.isAccessible = true - - mockHelper.withMockedMethod(method, instance, mockedValues) { - mockedValues.forEach { - Assertions.assertEquals(it, method.invoke(instance)) - } - } - } - - @Test - fun testInt() { - testMethod("testI", listOf(0, 0, 1, 10, -20)) - } - - @Test - fun testLong() { - testMethod("testL", listOf(0L, 1L, -1L, 1337L)) - } - - @Test - fun testObject() { - testMethod( - "testObject", - listOf(ClassForMockStaticMethods.SomeClass2(1337), ClassForMockStaticMethods.SomeClass2(228)) - ) - } - - @Test - fun testChar() { - testMethod("testChar", listOf('a', 'Z', 0.toChar(), 255.toChar(), '-', '\n')) - } - - @Test - fun testFloat() { - testMethod("testFloat", listOf(1.0f, -1.0f)) - } - - @Test - fun testByte() { - testMethod("testByte", listOf(1.toByte(), (-1).toByte())) - } - - @Test - fun testDouble() { - testMethod("testDouble", listOf(1.0, -1.0, 1337.0)) - } - - @Test - fun testArray() { - testMethod("testArray", listOf(intArrayOf(1, 2, 3), intArrayOf(-1, -2, -3))) - } - - @Test - fun testShort() { - testMethod("testShort", listOf(1.toShort(), 2.toShort(), 3.toShort())) - } - - @Test - fun testBoolean() { - testMethod("testBoolean", listOf(false, true, true, false, false)) - } - - @Test - fun testVoid() { - assertThrows { - testMethod( - "testVoid", - listOf(null, "Kek", 1337) - ) // we don't have to instrument function returning void at any case - } - } -} diff --git a/utbot-sample/src/main/java/org/utbot/examples/mixed/ImageIOUsage.java b/utbot-sample/src/main/java/org/utbot/examples/mixed/ImageIOUsage.java new file mode 100644 index 0000000000..1fd83cb6ed --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/mixed/ImageIOUsage.java @@ -0,0 +1,13 @@ +package org.utbot.examples.mixed; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class ImageIOUsage { + public boolean isAlphaPremultiplied(File file) throws IOException { + BufferedImage bimg = ImageIO.read(file); + return bimg.isAlphaPremultiplied(); + } +}