From 9202b80303729976bf8b9f9d70d7dbfdeb6b4f71 Mon Sep 17 00:00:00 2001 From: Alexey Menshutin Date: Mon, 4 Jul 2022 21:16:53 +0300 Subject: [PATCH] ToString support for abstract collection using makeSymbolic #391 --- .../collections/AbstractCollection.java | 13 +++++++++++++ .../overrides/collections/UtArrayList.java | 2 +- .../engine/overrides/collections/UtHashMap.java | 5 ++--- .../utbot/engine/overrides/stream/Arrays.java | 9 +++++++++ .../org/utbot/engine/CollectionWrappers.kt | 17 ++++++++++++----- .../org/utbot/engine/UtBotSymbolicEngine.kt | 3 ++- .../org/utbot/framework/plugin/api/SootUtils.kt | 4 ++++ .../examples/strings/StringExamplesTest.kt | 10 ++++++++++ .../utbot/examples/strings/StringExamples.java | 6 ++++++ 9 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 utbot-framework/src/main/java/org/utbot/engine/overrides/collections/AbstractCollection.java diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/AbstractCollection.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/AbstractCollection.java new file mode 100644 index 0000000000..82ba954be4 --- /dev/null +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/AbstractCollection.java @@ -0,0 +1,13 @@ +package org.utbot.engine.overrides.collections; + +import org.utbot.api.annotation.UtClassMock; + +import static org.utbot.api.mock.UtMock.makeSymbolic; + +@UtClassMock(target = java.util.AbstractCollection.class, internalUsage = true) +public abstract class AbstractCollection implements java.util.Collection { + @Override + public String toString() { + return makeSymbolic(); + } +} diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtArrayList.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtArrayList.java index 04b4aad77c..5db94b3fb7 100644 --- a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtArrayList.java +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtArrayList.java @@ -19,9 +19,9 @@ import org.utbot.engine.overrides.stream.UtStream; import static org.utbot.api.mock.UtMock.assume; +import static org.utbot.api.mock.UtMock.assumeOrExecuteConcretely; import static org.utbot.engine.ResolverKt.MAX_LIST_SIZE; import static org.utbot.engine.overrides.UtOverrideMock.alreadyVisited; -import static org.utbot.api.mock.UtMock.assumeOrExecuteConcretely; import static org.utbot.engine.overrides.UtOverrideMock.executeConcretely; import static org.utbot.engine.overrides.UtOverrideMock.parameter; import static org.utbot.engine.overrides.UtOverrideMock.visit; diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtHashMap.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtHashMap.java index d709cec484..57aba7f5c4 100644 --- a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtHashMap.java +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtHashMap.java @@ -15,9 +15,9 @@ import org.jetbrains.annotations.Nullable; import static org.utbot.api.mock.UtMock.assume; +import static org.utbot.api.mock.UtMock.makeSymbolic; import static org.utbot.engine.overrides.UtOverrideMock.alreadyVisited; import static org.utbot.engine.overrides.UtOverrideMock.doesntThrow; -import static org.utbot.engine.overrides.UtOverrideMock.executeConcretely; import static org.utbot.engine.overrides.UtOverrideMock.parameter; import static org.utbot.engine.overrides.UtOverrideMock.visit; @@ -556,8 +556,7 @@ public final boolean remove(Object o) { // TODO rewrite it JIRA:1604 @Override public String toString() { - executeConcretely(); - return super.toString(); + return makeSymbolic(); } public final class Entry implements Map.Entry { diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/stream/Arrays.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/stream/Arrays.java index 01b5f7dcf7..9534452ff9 100644 --- a/utbot-framework/src/main/java/org/utbot/engine/overrides/stream/Arrays.java +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/stream/Arrays.java @@ -1,7 +1,9 @@ package org.utbot.engine.overrides.stream; import org.utbot.api.annotation.UtClassMock; +import org.utbot.engine.overrides.collections.UtArrayList; +import java.util.List; import java.util.stream.Stream; @UtClassMock(target = java.util.Arrays.class, internalUsage = true) @@ -16,5 +18,12 @@ public static Stream stream(T[] array, int startInclusive, int endExclusi return new UtStream<>(array, startInclusive, endExclusive); } + @SuppressWarnings({"unused", "varargs"}) + @SafeVarargs + public static List asList(T... a) { + // TODO immutable collection https://github.com/UnitTestBot/UTBotJava/issues/398 + return new UtArrayList<>(a); + } + // TODO primitive arrays https://github.com/UnitTestBot/UTBotJava/issues/146 } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt index 3aa0dff24d..55a65470cf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt @@ -83,16 +83,23 @@ abstract class BaseOverriddenWrapper(protected val overriddenClassName: String) return listOf(GraphResult(method.jimpleBody().graph())) } - val overriddenMethod = overriddenClass.findMethodOrNull(method.subSignature) - - if (overriddenMethod == null) { + // We need to find either an override from the class (for example, implementation + // of the method from the wrapper) or a method from its ancestors. + // Note that the method from the ancestor might have substitutions as well. + // I.e., it is `toString` method for `UtArrayList` that is defined in + // `AbstractCollection` and has its own overridden implementation. + val overriddenMethod = overriddenClass + .findMethodOrNull(method.subSignature) + ?.let { typeRegistry.findSubstitutionOrNull(it) ?: it } + + return if (overriddenMethod == null) { // No overridden method has been found, switch to concrete execution pathLogger.warn("Method ${overriddenClass.name}::${method.subSignature} not found, executing concretely") - return emptyList() + emptyList() } else { val jimpleBody = overriddenMethod.jimpleBody() val graphResult = GraphResult(jimpleBody.graph()) - return listOf(graphResult) + listOf(graphResult) } } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 3b1ea942dd..9874faf3a5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -2536,7 +2536,8 @@ class UtBotSymbolicEngine( if (methodSignature != makeSymbolicMethod.signature && methodSignature != nonNullableMakeSymbolic.signature) return null val method = environment.method - val isInternalMock = method.hasInternalMockAnnotation || method.declaringClass.allMethodsAreInternalMocks + val declaringClass = method.declaringClass + val isInternalMock = method.hasInternalMockAnnotation || declaringClass.allMethodsAreInternalMocks || declaringClass.isOverridden val parameters = resolveParameters(invokeExpr.args, invokeExpr.method.parameterTypes) val mockMethodResult = mockStaticMethod(invokeExpr.method, parameters)?.single() ?: error("Unsuccessful mock attempt of the `makeSymbolic` method call: $invokeExpr") diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/SootUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/SootUtils.kt index 693489bfff..a4be349dce 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/SootUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/SootUtils.kt @@ -32,6 +32,8 @@ import org.utbot.engine.overrides.collections.UtOptional import org.utbot.engine.overrides.collections.UtOptionalDouble import org.utbot.engine.overrides.collections.UtOptionalInt import org.utbot.engine.overrides.collections.UtOptionalLong +import org.utbot.engine.overrides.collections.AbstractCollection +import org.utbot.engine.overrides.stream.Arrays import org.utbot.engine.overrides.stream.Stream import org.utbot.engine.overrides.stream.UtStream import java.io.File @@ -91,6 +93,7 @@ private fun addBasicClasses(vararg classes: KClass<*>) { } private val classesToLoad = arrayOf( + AbstractCollection::class, UtMock::class, UtOverrideMock::class, UtLogicMock::class, @@ -133,6 +136,7 @@ private val classesToLoad = arrayOf( UtStringBuilder::class, UtStringBuffer::class, Stream::class, + Arrays::class, Collection::class, List::class, UtStream::class, diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt index 8252d96ce6..196b63e19f 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt @@ -589,4 +589,14 @@ internal class StringExamplesTest : AbstractTestCaseGeneratorTest( ) } } + + @Test + fun testListToString() { + check( + StringExamples::listToString, + eq(1), + { r -> r == "[a, b, c]"}, + coverage = DoNotCalculate + ) + } } diff --git a/utbot-sample/src/main/java/org/utbot/examples/strings/StringExamples.java b/utbot-sample/src/main/java/org/utbot/examples/strings/StringExamples.java index 3b746feb74..73c624ae92 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/strings/StringExamples.java +++ b/utbot-sample/src/main/java/org/utbot/examples/strings/StringExamples.java @@ -1,5 +1,7 @@ package org.utbot.examples.strings; +import java.util.Arrays; + import static java.lang.Boolean.valueOf; class IntPair { @@ -411,4 +413,8 @@ public String equalsIgnoreCase(String s) { return "failure"; } } + + public String listToString() { + return Arrays.asList("a", "b", "c").toString(); + } }