From 0be9abee84810fd40d3c7bd60b50bcb46158f698 Mon Sep 17 00:00:00 2001 From: Yury Kamenev Date: Wed, 5 Apr 2023 17:56:22 +0300 Subject: [PATCH 1/4] Enabled mocking of for concrete executions --- .../instrumentation/instrumentation/mock/MockClassVisitor.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ec108974e3..72f4e560a3 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 @@ -65,8 +65,8 @@ class MockClassVisitor( exceptions: Array? ): MethodVisitor { val isNotSynthetic = access.and(Opcodes.ACC_SYNTHETIC) == 0 - // we do not want to mock or or synthetic methods - return if (name != "" && name != "" && isNotSynthetic) { + // we do not want to mock or synthetic methods + return if (name != "" && isNotSynthetic) { visitStaticMethod(access, name, descriptor, signature, exceptions) } else { cv.visitMethod(access, name, descriptor, signature, exceptions) From 5ae9f3a4bdbdc68d54fa40f9dfd25289470f7346 Mon Sep 17 00:00:00 2001 From: Yury Kamenev Date: Thu, 6 Apr 2023 13:30:26 +0300 Subject: [PATCH 2/4] Added test with mocked field in another class --- .../ClassUsingClassWithRandomFieldTest.kt | 41 +++++++++++++++++++ .../ClassUsingClassWithRandomField.java | 9 ++++ .../mock/fields/ClassWithRandomField.java | 11 +++++ 3 files changed, 61 insertions(+) create mode 100644 utbot-framework-test/src/test/kotlin/org/utbot/examples/mock/fields/ClassUsingClassWithRandomFieldTest.kt create mode 100644 utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassUsingClassWithRandomField.java create mode 100644 utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassWithRandomField.java diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/mock/fields/ClassUsingClassWithRandomFieldTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mock/fields/ClassUsingClassWithRandomFieldTest.kt new file mode 100644 index 0000000000..11e8146240 --- /dev/null +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mock/fields/ClassUsingClassWithRandomFieldTest.kt @@ -0,0 +1,41 @@ +package org.utbot.examples.mock.fields + +import org.junit.jupiter.api.Test +import org.utbot.framework.plugin.api.CodegenLanguage +import org.utbot.framework.plugin.api.UtCompositeModel +import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation +import org.utbot.framework.plugin.api.UtPrimitiveModel +import org.utbot.framework.plugin.api.util.id +import org.utbot.testcheckers.eq +import org.utbot.testing.CodeGeneration +import org.utbot.testing.UtValueTestCaseChecker + +class ClassUsingClassWithRandomFieldTest : UtValueTestCaseChecker( + testClass = ClassUsingClassWithRandomField::class, + testCodeGeneration = true, + pipelines = listOf( + TestLastStage(CodegenLanguage.JAVA), + TestLastStage(CodegenLanguage.KOTLIN, CodeGeneration) // because of mocks + ) +) { + @Test + fun testUseClassWithRandomField() { + checkMocksAndInstrumentation( + ClassUsingClassWithRandomField::useClassWithRandomField, + eq(1), + { mocks, instrumentation, r -> + val noMocks = mocks.isEmpty() + + val constructorMock = instrumentation.single() as UtNewInstanceInstrumentation + val classIdEquality = constructorMock.classId == java.util.Random::class.id + val callSiteIdEquality = constructorMock.callSites.single() == ClassWithRandomField::class.id + val instance = constructorMock.instances.single() as UtCompositeModel + val methodMock = instance.mocks.entries.single() + val methodNameEquality = methodMock.key.name == "nextInt" + val mockValueResult = r == (methodMock.value.single() as UtPrimitiveModel).value as Int + + noMocks && classIdEquality && callSiteIdEquality && instance.isMock && methodNameEquality && mockValueResult + } + ) + } +} diff --git a/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassUsingClassWithRandomField.java b/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassUsingClassWithRandomField.java new file mode 100644 index 0000000000..7e611f3b50 --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassUsingClassWithRandomField.java @@ -0,0 +1,9 @@ +package org.utbot.examples.mock.fields; + +public class ClassUsingClassWithRandomField { + public int useClassWithRandomField() { + ClassWithRandomField classWithRandomField = new ClassWithRandomField(); + + return classWithRandomField.nextInt(); + } +} diff --git a/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassWithRandomField.java b/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassWithRandomField.java new file mode 100644 index 0000000000..cfb9ae137d --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/mock/fields/ClassWithRandomField.java @@ -0,0 +1,11 @@ +package org.utbot.examples.mock.fields; + +import java.util.Random; + +public class ClassWithRandomField { + public Random random = new Random(); + + public int nextInt() { + return random.nextInt(); + } +} From 11ebaa89b61dc0dc16e9be432fcc14ee1b3b5fa6 Mon Sep 17 00:00:00 2001 From: Yury Kamenev Date: Thu, 6 Apr 2023 16:55:31 +0300 Subject: [PATCH 3/4] Removed default serializer for `Throwable` --- .../main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt index efd5045c4c..18495dec67 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt @@ -108,7 +108,7 @@ internal class TunedKryo : Kryo() { this.setOptimizedGenerics(false) // TODO: JIRA:1492 - addDefaultSerializer(java.lang.Throwable::class.java, JavaSerializerWrapper()) +// addDefaultSerializer(java.lang.Throwable::class.java, JavaSerializerWrapper()) val factory = object : SerializerFactory.FieldSerializerFactory() {} factory.config.ignoreSyntheticFields = true From 0448dc24c0d8c172385520204bc83813c41b5a58 Mon Sep 17 00:00:00 2001 From: Yury Kamenev Date: Thu, 6 Apr 2023 17:38:58 +0300 Subject: [PATCH 4/4] Used ignoring serialVersionUID deserializer for `Throwable` --- .../util/JavaSerializerWrapper.kt | 30 +++++++++++++++++-- .../utbot/instrumentation/util/KryoHelper.kt | 3 +- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/JavaSerializerWrapper.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/JavaSerializerWrapper.kt index bf7e1fd310..0fe2ee0c86 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/JavaSerializerWrapper.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/JavaSerializerWrapper.kt @@ -17,7 +17,7 @@ class JavaSerializerWrapper : JavaSerializer() { val graphContext = kryo.graphContext var objectStream = graphContext.get(this) as ObjectInputStream? if (objectStream == null) { - objectStream = WrappingObjectInputStream(input, kryo) + objectStream = IgnoringUidWrappingObjectInputStream(input, kryo) graphContext.put(this, objectStream) } objectStream.readObject() @@ -27,7 +27,7 @@ class JavaSerializerWrapper : JavaSerializer() { } } -class WrappingObjectInputStream(iss : InputStream?, private val kryo: Kryo) : ObjectInputStream(iss) { +class IgnoringUidWrappingObjectInputStream(iss : InputStream?, private val kryo: Kryo) : ObjectInputStream(iss) { override fun resolveClass(type: ObjectStreamClass): Class<*>? { return try { Class.forName(type.name, false, kryo.classLoader) @@ -43,4 +43,28 @@ class WrappingObjectInputStream(iss : InputStream?, private val kryo: Kryo) : Ob } } } -} \ No newline at end of file + + // This overriding allows to ignore serialVersionUID during deserialization. + // For more info, see https://stackoverflow.com/a/1816711 + override fun readClassDescriptor(): ObjectStreamClass { + var resultClassDescriptor = super.readClassDescriptor() // initially streams descriptor + + // the class in the local JVM that this descriptor represents. + val localClass: Class<*> = try { + Class.forName(resultClassDescriptor.name) + } catch (e: ClassNotFoundException) { + return resultClassDescriptor + } + + val localClassDescriptor = ObjectStreamClass.lookup(localClass) ?: return resultClassDescriptor + + // only if class implements serializable + val localSUID = localClassDescriptor.serialVersionUID + val streamSUID = resultClassDescriptor.serialVersionUID + if (streamSUID != localSUID) { // check for serialVersionUID mismatch. + resultClassDescriptor = localClassDescriptor // Use local class descriptor for deserialization + } + + return resultClassDescriptor + } +} diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt index 18495dec67..4dc6680d43 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt @@ -107,8 +107,9 @@ internal class TunedKryo : Kryo() { this.setOptimizedGenerics(false) + // Kryo cannot (at least, the current used version) deserialize stacktraces that are required for SARIF reports. // TODO: JIRA:1492 -// addDefaultSerializer(java.lang.Throwable::class.java, JavaSerializerWrapper()) + addDefaultSerializer(java.lang.Throwable::class.java, JavaSerializerWrapper()) val factory = object : SerializerFactory.FieldSerializerFactory() {} factory.config.ignoreSyntheticFields = true