From f43a15d664f621d33894bcee4d8318d16c916f5d Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:16:50 +0300 Subject: [PATCH 01/14] Add assemble model heuristic --- .../assemble/AssembleModelGenerator.kt | 19 +++++++++++++++---- .../modifications/ConstructorAnalyzer.kt | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) 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 8a0456f3e3..3e44f4e312 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 @@ -357,7 +357,10 @@ class AssembleModelGenerator(private val methodUnderTest: UtMethod<*>) { /** * Finds most appropriate constructor in class. * - * We prefer constructor that allows to set more fields than others + * If the [compositeModel].fields is empty, we don't care about affected fields, we would like to take an empty + * constructor or an appropriate constructor with the least number of arguments. + * + * Otherwise, we prefer constructor that allows to set more fields than others * and use only simple assignments like "this.a = a". * * Returns null if no one appropriate constructor is found. @@ -366,11 +369,19 @@ class AssembleModelGenerator(private val methodUnderTest: UtMethod<*>) { val classId = compositeModel.classId if (!classId.isVisible || classId.isInner) return null - return classId.jClass.declaredConstructors + val constructorIds = classId.jClass.declaredConstructors .filter { it.isVisible } - .sortedByDescending { it.parameterCount } .map { it.executableId } - .firstOrNull { constructorAnalyzer.isAppropriate(it) } + + return if (compositeModel.fields.isEmpty()) { + constructorIds + .sortedBy { it.parameters.size } + .firstOrNull { it.parameters.isEmpty() || constructorAnalyzer.isAppropriate(it) } + } else { + constructorIds + .sortedByDescending { it.parameters.size } + .firstOrNull { constructorAnalyzer.isAppropriate(it) } + } } private val ClassId.isVisible : Boolean diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/ConstructorAnalyzer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/ConstructorAnalyzer.kt index bfc5aa9b66..2960364095 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/ConstructorAnalyzer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/ConstructorAnalyzer.kt @@ -172,7 +172,7 @@ class ConstructorAnalyzer { for (assn in assignments) { val jimpleLocal = assn.rightOp as? JimpleLocal ?: continue - val field = (assn.leftOp as JInstanceFieldRef).field + val field = (assn.leftOp as? JInstanceFieldRef)?.field ?: continue val parameterIndex = jimpleBody.locals.indexOfFirst { it.name == jimpleLocal.name } indexedFields[parameterIndex - 1] = FieldId(field.declaringClass.id, field.name) } From c74fb35605c125193e228d94903ec4d30befadc7 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:32:07 +0300 Subject: [PATCH 02/14] Fix comment --- .../main/kotlin/org/utbot/framework/minimization/Minimization.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt index 78850acc31..380ab74d2c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt @@ -109,6 +109,7 @@ private fun groupByBranchInstructions( * 2. {2, 3, 2, 6} * 3. {2, 3, 4, 3} * branch instructions are {2 -> (3, 4, 5, 6), 3 -> (2, 4), 4 -> (2, 3)} + * * we will build these lists representing their behaviour: * 1. {2 -> 3, 3 -> 2} (because of {__2__, __3__, 2, 4, 2, 5}) * 2. {2 -> 3, 3 -> 2} (because of {__2__, __3__, 2, 6}) From d935426b89dc94256d4693d080ff89400f1d8b80 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:53:15 +0300 Subject: [PATCH 03/14] Add UtLinkedListWithNullableCheck --- .../overrides/collections/UtLinkedList.java | 6 +- .../UtLinkedListWithNullableCheck.java | 122 ++++++++++++++++++ .../org/utbot/engine/CollectionWrappers.kt | 17 ++- .../org/utbot/framework/util/SootUtils.kt | 2 + 4 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedListWithNullableCheck.java diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedList.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedList.java index 55a577cb52..e4183cf698 100644 --- a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedList.java +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedList.java @@ -72,7 +72,7 @@ public UtLinkedList(Collection c) { *
  • elementData is marked as parameter
  • *
  • elementData.storage and it's elements are marked as parameters
  • */ - private void preconditionCheck() { + protected void preconditionCheck() { if (alreadyVisited(this)) { return; } @@ -88,13 +88,13 @@ private void preconditionCheck() { visit(this); } - private void rangeCheck(int index) { + protected void rangeCheck(int index) { if (index < 0 || index >= elementData.end - elementData.begin) { throw new IndexOutOfBoundsException(); } } - private void rangeCheckForAdd(int index) { + protected void rangeCheckForAdd(int index) { if (index < 0 || index > elementData.end - elementData.begin) { throw new IndexOutOfBoundsException(); } diff --git a/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedListWithNullableCheck.java b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedListWithNullableCheck.java new file mode 100644 index 0000000000..4def825276 --- /dev/null +++ b/utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtLinkedListWithNullableCheck.java @@ -0,0 +1,122 @@ +package org.utbot.engine.overrides.collections; + +import java.util.Collection; + +/** + * This list forbids inserting null elements to support some implementations of {@link java.util.Deque} like + * {@link java.util.ArrayDeque}. + * + * TODO: Support super calls in inherited wrappers + * + * @see UtLinkedList + * @param + */ +public class UtLinkedListWithNullableCheck extends UtLinkedList { + @SuppressWarnings("unused") + UtLinkedListWithNullableCheck(RangeModifiableUnlimitedArray elementData, int fromIndex, int toIndex) { + super(elementData, fromIndex, toIndex); + for (int i = elementData.begin; i < elementData.end; i++) { + if (elementData.get(i) == null) { + throw new NullPointerException(); + } + } + } + + @SuppressWarnings("unused") + public UtLinkedListWithNullableCheck() { + super(); + } + + @SuppressWarnings("unused") + public UtLinkedListWithNullableCheck(Collection c) { + super(c); + } + + @Override + public E set(int index, E element) { + if (element == null) { + throw new NullPointerException(); + } + preconditionCheck(); + rangeCheck(index); + E oldElement = elementData.get(index + elementData.begin); + elementData.set(index + elementData.begin, element); + return oldElement; + } + + @Override + public void addFirst(E e) { + if (e == null) { + throw new NullPointerException(); + } + preconditionCheck(); + elementData.set(--elementData.begin, e); + } + + @Override + public void addLast(E e) { + if (e == null) { + throw new NullPointerException(); + } + preconditionCheck(); + elementData.set(elementData.end++, e); + } + + @Override + public boolean offerFirst(E e) { + if (e == null) { + throw new NullPointerException(); + } + preconditionCheck(); + elementData.set(--elementData.begin, e); + return true; + } + + @Override + public boolean offerLast(E e) { + if (e == null) { + throw new NullPointerException(); + } + preconditionCheck(); + elementData.set(elementData.end++, e); + return true; + } + + @Override + public void add(int index, E element) { + if (element == null) { + throw new NullPointerException(); + } + preconditionCheck(); + rangeCheckForAdd(index); + elementData.end++; + elementData.insert(index + elementData.begin, element); + } + + @Override + public boolean addAll(Collection c) { + for (Object elem : c.toArray()) { + if (elem == null) { + throw new NullPointerException(); + } + } + preconditionCheck(); + elementData.setRange(elementData.end, c.toArray(), 0, c.size()); + elementData.end += c.size(); + return true; + } + + @Override + public boolean addAll(int index, Collection c) { + for (Object elem : c.toArray()) { + if (elem == null) { + throw new NullPointerException(); + } + } + preconditionCheck(); + rangeCheckForAdd(index); + elementData.insertRange(index + elementData.begin, c.toArray(), 0, c.size()); + elementData.end += c.size(); + return true; + } +} 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 2e2039dddc..ac007ba7af 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt @@ -8,6 +8,7 @@ import org.utbot.engine.overrides.collections.UtGenericStorage import org.utbot.engine.overrides.collections.UtHashMap import org.utbot.engine.overrides.collections.UtHashSet import org.utbot.engine.overrides.collections.UtLinkedList +import org.utbot.engine.overrides.collections.UtLinkedListWithNullableCheck import org.utbot.engine.pc.UtAddrExpression import org.utbot.engine.pc.UtExpression import org.utbot.engine.pc.select @@ -195,12 +196,14 @@ abstract class BaseGenericStorageBasedContainerWrapper(containerClassName: Strin */ enum class UtListClass { UT_ARRAY_LIST, - UT_LINKED_LIST; + UT_LINKED_LIST, + UT_LINKED_LIST_WITH_NULLABLE_CHECK; val className: String get() = when (this) { UT_ARRAY_LIST -> UtArrayList::class.java.canonicalName UT_LINKED_LIST -> UtLinkedList::class.java.canonicalName + UT_LINKED_LIST_WITH_NULLABLE_CHECK -> UtLinkedListWithNullableCheck::class.java.canonicalName } } @@ -208,11 +211,15 @@ enum class UtListClass { * BaseCollectionWrapper that uses implementation of [UtArrayList] or [UtLinkedList] * depending on specified [utListClass] parameter. * + * This class is also used for wrapping [java.util.Deque] as [UtLinkedList] and [UtLinkedListWithNullableCheck] + * implement [java.util.Deque]. + * * At resolving stage ListWrapper is resolved to [UtAssembleModel]. - * This model is instantiated by [java.util.ArrayList] constructor if utListClass is [UtListClass.UT_ARRAY_LIST] - * or by [java.util.LinkedList] constructor, if utListClass is [UtListClass.UT_LINKED_LIST] + * This model is instantiated by [java.util.ArrayList] constructor if utListClass is [UtListClass.UT_ARRAY_LIST], + * by [java.util.LinkedList] constructor if utListClass is [UtListClass.UT_LINKED_LIST] or by other constructors + * depending on concrete type from passed [ReferenceValue] in [resolveValueModels] function. * - * Modification chain consists of consequent [java.util.List.add] methods + * Modification chain consists of consequent [java.util.Collection.add] methods * that are arranged to iterating order of list. */ class ListWrapper(private val utListClass: UtListClass) : BaseGenericStorageBasedContainerWrapper(utListClass.className) { @@ -227,7 +234,7 @@ class ListWrapper(private val utListClass: UtListClass) : BaseGenericStorageBase } override val modificationMethodId: MethodId = methodId( - classId = java.util.List::class.id, + classId = java.util.Collection::class.id, name = "add", returnType = booleanClassId, arguments = arrayOf(objectClassId), diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt index 65953d900d..87287f2595 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt @@ -34,6 +34,7 @@ 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.collections.UtLinkedListWithNullableCheck import org.utbot.engine.overrides.stream.Arrays import org.utbot.engine.overrides.stream.Stream import org.utbot.engine.overrides.stream.UtStream @@ -129,6 +130,7 @@ private val classesToLoad = arrayOf( UtArrayList::class, UtArrayList.UtArrayListIterator::class, UtLinkedList::class, + UtLinkedListWithNullableCheck::class, UtLinkedList.UtLinkedListIterator::class, UtLinkedList.ReverseIteratorWrapper::class, UtHashSet::class, From 2724065138c0098183b8176fd7ff8c0664df3aca Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:54:50 +0300 Subject: [PATCH 04/14] Plug wrappers for queues in --- .../kotlin/org/utbot/engine/Extensions.kt | 11 ++- .../kotlin/org/utbot/engine/ObjectWrappers.kt | 70 +++++++++++-------- .../main/kotlin/org/utbot/engine/Traverser.kt | 21 +++++- 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Extensions.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Extensions.kt index edaec9a10b..2c7641b684 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Extensions.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Extensions.kt @@ -74,6 +74,13 @@ import soot.jimple.internal.JVirtualInvokeExpr import soot.jimple.internal.JimpleLocal import soot.tagkit.ArtificialEntityTag import java.lang.reflect.ParameterizedType +import java.util.LinkedList +import java.util.ArrayDeque +import java.util.Deque +import java.util.Queue +import kotlin.collections.ArrayList +import kotlin.collections.HashMap +import kotlin.collections.HashSet val JIdentityStmt.lines: String get() = tags.joinToString { "$it" } @@ -256,7 +263,9 @@ val libraryTargets: Map> = mapOf( Collection::class.java.name to listOf(ArrayList::class.java.name, HashSet::class.java.name), List::class.java.name to listOf(ArrayList::class.java.name), Set::class.java.name to listOf(HashSet::class.java.name), - Map::class.java.name to listOf(HashMap::class.java.name) + Map::class.java.name to listOf(HashMap::class.java.name), + Queue::class.java.name to listOf(LinkedList::class.java.name, ArrayDeque::class.java.name), + Deque::class.java.name to listOf(LinkedList::class.java.name, ArrayDeque::class.java.name) ) fun Collection<*>.prettify() = joinToString("\n", "\n", "\n") diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt index 7225af9c77..3cea048bc6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt @@ -4,6 +4,7 @@ import org.utbot.common.WorkaroundReason.MAKE_SYMBOLIC import org.utbot.common.workaround import org.utbot.engine.UtListClass.UT_ARRAY_LIST import org.utbot.engine.UtListClass.UT_LINKED_LIST +import org.utbot.engine.UtListClass.UT_LINKED_LIST_WITH_NULLABLE_CHECK import org.utbot.engine.UtOptionalClass.UT_OPTIONAL import org.utbot.engine.UtOptionalClass.UT_OPTIONAL_DOUBLE import org.utbot.engine.UtOptionalClass.UT_OPTIONAL_INT @@ -71,8 +72,12 @@ val classToWrapper: MutableMap = putSootClass(CopyOnWriteArrayList::class, UT_ARRAY_LIST.className) putSootClass(java.util.LinkedList::class, UT_LINKED_LIST.className) putSootClass(java.util.AbstractSequentialList::class, UT_LINKED_LIST.className) - // TODO mistake JIRA:1495 - putSootClass(java.util.ArrayDeque::class, UT_LINKED_LIST.className) + + putSootClass(java.util.ArrayDeque::class, UT_LINKED_LIST_WITH_NULLABLE_CHECK.className) + putSootClass(java.util.concurrent.ConcurrentLinkedDeque::class, UT_LINKED_LIST_WITH_NULLABLE_CHECK.className) + putSootClass(java.util.concurrent.ConcurrentLinkedQueue::class, UT_LINKED_LIST_WITH_NULLABLE_CHECK.className) + putSootClass(java.util.concurrent.LinkedBlockingDeque::class, UT_LINKED_LIST_WITH_NULLABLE_CHECK.className) + putSootClass(java.util.concurrent.LinkedBlockingQueue::class, UT_LINKED_LIST_WITH_NULLABLE_CHECK.className) putSootClass(java.util.Set::class, UtHashSet::class) putSootClass(java.util.AbstractSet::class, UtHashSet::class) @@ -83,6 +88,7 @@ val classToWrapper: MutableMap = putSootClass(java.util.AbstractMap::class, UtHashMap::class) putSootClass(java.util.LinkedHashMap::class, UtHashMap::class) putSootClass(java.util.HashMap::class, UtHashMap::class) + putSootClass(java.util.concurrent.ConcurrentHashMap::class, UtHashMap::class) putSootClass(java.util.stream.BaseStream::class, UT_STREAM.className) putSootClass(java.util.stream.Stream::class, UT_STREAM.className) @@ -143,48 +149,50 @@ private val wrappers = mapOf( wrap(AssociativeArray::class) { type, addr -> objectValue(type, addr, AssociativeArrayWrapper()) }, + // list wrappers - wrap(java.util.List::class) { _, addr -> - objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) - }, - wrap(java.util.AbstractList::class) { _, addr -> - objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) - }, - wrap(java.util.ArrayList::class) { _, addr -> - objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) - }, - wrap(CopyOnWriteArrayList::class) { _, addr -> - objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) - }, + wrap(java.util.List::class) { _, addr -> objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) }, + wrap(java.util.AbstractList::class) { _, addr -> objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) }, + wrap(java.util.ArrayList::class) { _, addr -> objectValue(ARRAY_LIST_TYPE, addr, ListWrapper(UT_ARRAY_LIST)) }, - wrap(java.util.LinkedList::class) { _, addr -> - objectValue(LINKED_LIST_TYPE, addr, ListWrapper(UT_LINKED_LIST)) - }, - wrap(java.util.AbstractSequentialList::class) { _, addr -> - objectValue(LINKED_LIST_TYPE, addr, ListWrapper(UT_LINKED_LIST)) + + wrap(CopyOnWriteArrayList::class) { type, addr -> objectValue(type, addr, ListWrapper(UT_ARRAY_LIST)) }, + + wrap(java.util.LinkedList::class) { _, addr -> objectValue(LINKED_LIST_TYPE, addr, ListWrapper(UT_LINKED_LIST)) }, + wrap(java.util.AbstractSequentialList::class) { _, addr -> objectValue(LINKED_LIST_TYPE, addr, ListWrapper(UT_LINKED_LIST)) }, + + // queue, deque wrappers + wrap(java.util.ArrayDeque::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - // TODO mistake JIRA:1495 - wrap(java.util.ArrayDeque::class) { _, addr -> - objectValue(LINKED_LIST_TYPE, addr, ListWrapper(UT_LINKED_LIST)) + wrap(java.util.ArrayDeque::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - // set wrappers - wrap(java.util.Set::class) { _, addr -> - objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) + wrap(java.util.concurrent.ConcurrentLinkedDeque::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - wrap(java.util.AbstractSet::class) { _, addr -> - objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) + wrap(java.util.concurrent.ConcurrentLinkedQueue::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - wrap(java.util.HashSet::class) { _, addr -> - objectValue(HASH_SET_TYPE, addr, SetWrapper()) + wrap(java.util.concurrent.LinkedBlockingDeque::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - wrap(java.util.LinkedHashSet::class) { _, addr -> - objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) + wrap(java.util.concurrent.LinkedBlockingQueue::class) { type, addr -> + objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, + + // set wrappers + wrap(java.util.Set::class) { _, addr -> objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) }, + wrap(java.util.AbstractSet::class) { _, addr -> objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) }, + wrap(java.util.HashSet::class) { _, addr -> objectValue(HASH_SET_TYPE, addr, SetWrapper()) }, + wrap(java.util.LinkedHashSet::class) { _, addr -> objectValue(LINKED_HASH_SET_TYPE, addr, SetWrapper()) }, + // map wrappers wrap(java.util.Map::class) { _, addr -> objectValue(LINKED_HASH_MAP_TYPE, addr, MapWrapper()) }, wrap(java.util.AbstractMap::class) { _, addr -> objectValue(LINKED_HASH_MAP_TYPE, addr, MapWrapper()) }, wrap(java.util.LinkedHashMap::class) { _, addr -> objectValue(LINKED_HASH_MAP_TYPE, addr, MapWrapper()) }, wrap(java.util.HashMap::class) { _, addr -> objectValue(HASH_MAP_TYPE, addr, MapWrapper()) }, + wrap(java.util.concurrent.ConcurrentHashMap::class) { _, addr -> objectValue(HASH_MAP_TYPE, addr, MapWrapper()) }, // stream wrappers wrap(java.util.stream.BaseStream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) }, diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index f4bdeb29b7..3ce10a2527 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -2437,6 +2437,9 @@ class Traverser( val method = invokeExpr.retrieveMethod() val parameters = resolveParameters(invokeExpr.args, method.parameterTypes) val invocation = Invocation(instance, method, parameters, InvocationTarget(instance, method)) + + // Calls with super syntax are represented by invokeSpecial instruction, but we don't support them in wrappers + // TODO: https://github.com/UnitTestBot/UTBotJava/issues/819 -- Support super calls in inherited wrappers return commonInvokePart(invocation) } @@ -2455,7 +2458,23 @@ class Traverser( * Returns results of native calls cause other calls push changes directly to path selector. */ private fun TraversalContext.commonInvokePart(invocation: Invocation): List { - // First, check if there is override for the invocation itself, not for the targets + /** + * First, check if there is override for the invocation itself, not for the targets. + * + * Note that calls with super syntax are represented by invokeSpecial instruction, but we don't support them in wrappers, + * so here we resolve [invocation] to the inherited method invocation if it's something like: + * + * ```java + * public class InheritedWrapper extends BaseWrapper { + * public void add(Object o) { + * // some stuff + * super.add(o); // this resolves to InheritedWrapper::add instead of BaseWrapper::add + * } + * } + * ``` + * + * TODO: https://github.com/UnitTestBot/UTBotJava/issues/819 -- Support super calls in inherited wrappers + */ val artificialMethodOverride = overrideInvocation(invocation, target = null) // If so, return the result of the override From 1bf06ec48875a5a326ec78fa0d787fd24dd16130 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:55:11 +0300 Subject: [PATCH 05/14] Add UtModelConstructors in ConcreteExecutor --- .../concrete/UtAssembleModelConstructors.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt index 0d22eb6268..9a335798a6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtAssembleModelConstructors.kt @@ -7,6 +7,7 @@ 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.concurrent.CopyOnWriteArrayList private val predefinedConstructors = mutableMapOf, () -> UtAssembleModelConstructorBase>( /** @@ -24,18 +25,33 @@ private val predefinedConstructors = mutableMapOf, () -> UtAssembleMode java.util.ArrayList::class.java to { CollectionConstructor() }, java.util.AbstractList::class.java to { CollectionConstructor() }, java.util.List::class.java to { CollectionConstructor() }, - java.util.Deque::class.java to { CollectionConstructor() }, + java.util.concurrent.CopyOnWriteArrayList::class.java to { CollectionConstructor() }, + + + /** + * Queues, deques + */ + java.util.PriorityQueue::class.java to { CollectionConstructor() }, java.util.ArrayDeque::class.java to { CollectionConstructor() }, + java.util.concurrent.LinkedBlockingQueue::class.java to { CollectionConstructor() }, java.util.concurrent.LinkedBlockingDeque::class.java to { CollectionConstructor() }, + java.util.concurrent.ConcurrentLinkedQueue::class.java to { CollectionConstructor() }, + java.util.concurrent.ConcurrentLinkedDeque::class.java to { CollectionConstructor() }, + java.util.Queue::class.java to { CollectionConstructor() }, + java.util.Deque::class.java to { CollectionConstructor() }, + /** * Sets */ java.util.HashSet::class.java to { CollectionConstructor() }, + java.util.TreeSet::class.java to { CollectionConstructor() }, java.util.LinkedHashSet::class.java to { CollectionConstructor() }, java.util.AbstractSet::class.java to { CollectionConstructor() }, java.util.Set::class.java to { CollectionConstructor() }, + + /** * Maps */ From cfee03cfc9d4812aa9f85030ae4f18a89a31bff6 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 30 Aug 2022 16:55:18 +0300 Subject: [PATCH 06/14] Add tests --- .../examples/collections/QueueUsagesTest.kt | 127 ++++++++++++++++++ .../structures/StandardStructuresTest.kt | 3 +- .../examples/collections/QueueUsages.java | 92 +++++++++++++ 3 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt create mode 100644 utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt new file mode 100644 index 0000000000..8e6b43e148 --- /dev/null +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt @@ -0,0 +1,127 @@ +package org.utbot.examples.collections + +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.utbot.examples.UtValueTestCaseChecker +import org.utbot.examples.eq +import org.utbot.examples.isException +import org.utbot.framework.codegen.CodeGeneration +import org.utbot.framework.plugin.api.CodegenLanguage + +class QueueUsagesTest : UtValueTestCaseChecker( + testClass = QueueUsages::class, + testCodeGeneration = true, + languagePipelines = listOf( + CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), + CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) + ) +) { + @Test + fun testCreateArrayDeque() { + checkWithException( + QueueUsages::createArrayDeque, + eq(3), + { init, next, r -> init == null && next == null && r.isException() }, + { init, next, r -> init != null && next == null && r.isException() }, + { init, next, r -> init != null && next != null && r.getOrNull() == 2 }, + ) + } + + @Test + fun testCreateLinkedList() { + checkWithException( + QueueUsages::createLinkedList, + eq(1), + { _, _, r -> r.getOrNull()!! == 2 }, + ) + } + + @Test + fun testCreateLinkedBlockingDeque() { + checkWithException( + QueueUsages::createLinkedBlockingDeque, + eq(3), + { init, next, r -> init == null && next == null && r.isException() }, + { init, next, r -> init != null && next == null && r.isException() }, + { init, next, r -> init != null && next != null && r.getOrNull() == 2 }, + ) + } + + @Test + fun testContainsQueue() { + checkWithException( + QueueUsages::containsQueue, + eq(3), + { q, _, r -> q == null && r.isException() }, + { q, x, r -> x in q && r.getOrNull() == 1 }, + { q, x, r -> x !in q && r.getOrNull() == 0 }, + ) + } + + @Test + fun testAddQueue() { + checkWithException( + QueueUsages::addQueue, + eq(3), + { q, _, r -> q == null && r.isException() }, + { q, x, r -> q != null && x in r.getOrNull()!! }, + { q, x, r -> q != null && x == null && r.isException() }, ) + } + + @Test + fun testAddAllQueue() { + checkWithException( + QueueUsages::addAllQueue, + eq(3), + { q, _, r -> q == null && r.isException() }, + { q, x, r -> q != null && x != null && x in r.getOrNull()!! }, + { q, x, r -> q != null && x == null && r.isException() }, + ) + } + + @Test + fun testCastQueueToDeque() { + check( + QueueUsages::castQueueToDeque, + eq(2), + { q, r -> q !is java.util.Deque<*> && r == null }, + { q, r -> q is java.util.Deque<*> && r is java.util.Deque<*> }, + ) + } + + @Test + fun testCheckSubtypesOfQueue() { + check( + QueueUsages::checkSubtypesOfQueue, + eq(4), + { q, r -> q == null && r == 0 }, + { q, r -> q is java.util.LinkedList<*> && r == 1 }, + { q, r -> q is java.util.ArrayDeque<*> && r == 2 }, + { q, r -> q !is java.util.LinkedList<*> && q !is java.util.ArrayDeque && r == 3 } + ) + } + + @Test + @Disabled("TODO: Related to https://github.com/UnitTestBot/UTBotJava/issues/820") + fun testCheckSubtypesOfQueueWithUsage() { + check( + QueueUsages::checkSubtypesOfQueueWithUsage, + eq(4), + { q, r -> q == null && r == 0 }, + { q, r -> q is java.util.LinkedList<*> && r == 1 }, + { q, r -> q is java.util.ArrayDeque<*> && r == 2 }, + { q, r -> q !is java.util.LinkedList<*> && q !is java.util.ArrayDeque && r == 3 } // this is uncovered + ) + } + + @Test + fun testAddConcurrentLinkedQueue() { + checkWithException( + QueueUsages::addConcurrentLinkedQueue, + eq(3), + { q, _, r -> q == null && r.isException() }, + { q, x, r -> q != null && x != null && x in r.getOrNull()!! }, + { q, x, r -> q != null && x == null && r.isException() }, + ) + } +} \ No newline at end of file diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt index 673d033edd..1f8984de7d 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt @@ -45,7 +45,6 @@ internal class StandardStructuresTest : UtValueTestCaseChecker(testClass = Stand } @Test - @Disabled("TODO use correct wrapper JIRA:1495") fun testGetDeque() { val dequeSummary = listOf( DocPreTagStatement( @@ -72,7 +71,7 @@ internal class StandardStructuresTest : UtValueTestCaseChecker(testClass = Stand { d, r -> d is LinkedList && r is LinkedList }, { d, r -> d == null && r == null }, { d, r -> - d !is ArrayDeque<*> && d !is LinkedList && d != null && r !is ArrayDeque<*> && r !is LinkedList && r != null + d !is java.util.ArrayDeque<*> && d !is LinkedList && d != null && r !is java.util.ArrayDeque<*> && r !is LinkedList && r != null }, coverage = DoNotCalculate, summaryTextChecks = listOf( diff --git a/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java b/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java new file mode 100644 index 0000000000..8dea9ab506 --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java @@ -0,0 +1,92 @@ +package org.utbot.examples.collections; + +import org.utbot.examples.objects.WrappedInt; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.LinkedBlockingDeque; + +public class QueueUsages { + public int createArrayDeque(WrappedInt init, WrappedInt next) { + Queue q = new ArrayDeque<>(Collections.singletonList(init)); + q.add(next); + return q.size(); + } + + public int createLinkedList(WrappedInt init, WrappedInt next) { + Queue q = new LinkedList<>(Collections.singletonList(init)); + q.add(next); + return q.size(); + } + + public int createLinkedBlockingDeque(WrappedInt init, WrappedInt next) { + Queue q = new LinkedBlockingDeque<>(Collections.singletonList(init)); + q.add(next); + return q.size(); + } + + public int containsQueue(Queue q, int x) { + if (q.contains(x)) { + return 1; + } else { + return 0; + } + } + + public Queue addQueue(Queue q, WrappedInt x) { + q.add(x); + return q; + } + + public Queue addAllQueue(Queue q, WrappedInt o) { + Collection lst = Arrays.asList(new WrappedInt(1), o); + q.addAll(lst); + return q; + } + + public Deque castQueueToDeque(Queue q) { + if (q instanceof Deque) { + return (Deque)q; + } else { + return null; + } + } + + public int checkSubtypesOfQueue(Queue q) { + if (q == null) { + return 0; + } + if (q instanceof LinkedList) { + return 1; + } else if (q instanceof ArrayDeque) { + return 2; + } else { + return 3; + } + } + + public int checkSubtypesOfQueueWithUsage(Queue q) { + if (q == null) { + return 0; + } + q.add(1); + if (q instanceof LinkedList) { + return 1; + } else if (q instanceof ArrayDeque) { + return 2; + } else { + return 3; + } + } + + public ConcurrentLinkedQueue addConcurrentLinkedQueue(ConcurrentLinkedQueue q, WrappedInt o) { + q.add(o); + return q; + } +} From 5c21f15912cd2c3ed705a60f771d0a5f15d4fb13 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 09:47:24 +0300 Subject: [PATCH 07/14] Fix pipeline phases --- .../utbot/examples/structures/StandardStructuresTest.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt index 1f8984de7d..b946c53c1f 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt @@ -14,7 +14,13 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -internal class StandardStructuresTest : UtValueTestCaseChecker(testClass = StandardStructures::class) { +internal class StandardStructuresTest : UtValueTestCaseChecker( + testClass = StandardStructures::class, + languagePipelines = listOf( + CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), + CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) + ) +) { @Test @Disabled("TODO down cast for object wrapper JIRA:1480") fun testGetList() { From 9329c1dc56bf7d00fa385705f28a7af3bebf5b59 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 11:14:46 +0300 Subject: [PATCH 08/14] Fix UtBotJavaApiTest --- .../java/org/utbot/examples/manual/KotlinWrappers.kt | 12 +----------- .../org/utbot/examples/manual/UtBotJavaApiTest.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt b/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt index 29566f0138..411cb9f3bd 100644 --- a/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt +++ b/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt @@ -1,25 +1,15 @@ package org.utbot.examples.manual -import org.utbot.common.FileUtil import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtPrimitiveModel -import java.nio.file.Path object SootUtils { @JvmStatic fun runSoot(clazz: Class<*>) { - val buildDir = FileUtil.locateClassPath(clazz.kotlin) ?: FileUtil.isolateClassFiles(clazz.kotlin) - val buildDirPath = buildDir.toPath() - - if (buildDirPath != previousBuildDir) { - org.utbot.framework.util.runSoot(buildDirPath, null) - previousBuildDir = buildDirPath - } + org.utbot.framework.SootUtils.runSoot(clazz.kotlin) } - - private var previousBuildDir: Path? = null } fun fields( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java b/utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java index 25ba275781..3620956a2a 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java @@ -31,7 +31,13 @@ import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; -import java.util.*; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static org.utbot.external.api.UtModelFactoryKt.classIdForType; @@ -60,7 +66,6 @@ public class UtBotJavaApiTest { @BeforeEach public void setUp() { - SootUtils.runSoot(PrimitiveFields.class); context = UtContext.Companion.setUtContext(new UtContext(PrimitiveFields.class.getClassLoader())); modelFactory = new UtModelFactory(); } @@ -1221,6 +1226,7 @@ public void testOnObjectWithArrayOfComplexArrays() { @Test public void testFuzzingSimple() { + SootUtils.runSoot(StringSwitchExample.class); UtBotJavaApi.setStopConcreteExecutorOnExit(false); String classpath = getClassPath(StringSwitchExample.class); From afa97d177e1a2939e9b2144cd8419a124f909295 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 11:52:06 +0300 Subject: [PATCH 09/14] Fix Egor's migration --- .../kotlin => main/java}/org/utbot/framework/SootUtils.kt | 0 .../org/utbot/examples/manual/UtBotJavaApiTest.java | 0 .../org/utbot/examples/collections/QueueUsagesTest.kt | 8 ++++---- .../utbot/examples/structures/StandardStructuresTest.kt | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) rename utbot-framework-test/src/{test/kotlin => main/java}/org/utbot/framework/SootUtils.kt (100%) rename utbot-framework-test/src/test/{kotlin => java}/org/utbot/examples/manual/UtBotJavaApiTest.java (100%) diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/SootUtils.kt b/utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt similarity index 100% rename from utbot-framework-test/src/test/kotlin/org/utbot/framework/SootUtils.kt rename to utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java b/utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java similarity index 100% rename from utbot-framework-test/src/test/kotlin/org/utbot/examples/manual/UtBotJavaApiTest.java rename to utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt index 8e6b43e148..8a181df077 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt @@ -2,11 +2,11 @@ package org.utbot.examples.collections import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.utbot.examples.UtValueTestCaseChecker -import org.utbot.examples.eq -import org.utbot.examples.isException -import org.utbot.framework.codegen.CodeGeneration import org.utbot.framework.plugin.api.CodegenLanguage +import org.utbot.testcheckers.eq +import org.utbot.tests.infrastructure.CodeGeneration +import org.utbot.tests.infrastructure.UtValueTestCaseChecker +import org.utbot.tests.infrastructure.isException class QueueUsagesTest : UtValueTestCaseChecker( testClass = QueueUsages::class, diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt index b946c53c1f..aff33bc2d3 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/structures/StandardStructuresTest.kt @@ -12,7 +12,9 @@ import java.util.LinkedList import java.util.TreeMap import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test +import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.testcheckers.eq +import org.utbot.tests.infrastructure.CodeGeneration internal class StandardStructuresTest : UtValueTestCaseChecker( testClass = StandardStructures::class, From 77e6a57f6712dcd00d844a7ad6e7ccecc553837a Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 12:22:57 +0300 Subject: [PATCH 10/14] Fix duplicate line --- .../src/main/kotlin/org/utbot/engine/ObjectWrappers.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt index 3cea048bc6..3fdeb2bfb9 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt @@ -165,9 +165,6 @@ private val wrappers = mapOf( wrap(java.util.ArrayDeque::class) { type, addr -> objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, - wrap(java.util.ArrayDeque::class) { type, addr -> - objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) - }, wrap(java.util.concurrent.ConcurrentLinkedDeque::class) { type, addr -> objectValue(type, addr, ListWrapper(UT_LINKED_LIST_WITH_NULLABLE_CHECK)) }, From 72f40b57885267099364af412e28ffde16761c76 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 15:16:04 +0300 Subject: [PATCH 11/14] Fix kotlin documentation on ListWrapper --- .../kotlin/org/utbot/engine/CollectionWrappers.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 ac007ba7af..fa0b5b89e8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt @@ -208,16 +208,15 @@ enum class UtListClass { } /** - * BaseCollectionWrapper that uses implementation of [UtArrayList] or [UtLinkedList] + * BaseCollectionWrapper that uses implementation of [UtArrayList], [UtLinkedList], or [UtLinkedListWithNullableCheck] * depending on specified [utListClass] parameter. * - * This class is also used for wrapping [java.util.Deque] as [UtLinkedList] and [UtLinkedListWithNullableCheck] - * implement [java.util.Deque]. + * This class is also used for wrapping [java.util.Queue], because [UtLinkedList] and [UtLinkedListWithNullableCheck] + * both implement [java.util.Queue]. * * At resolving stage ListWrapper is resolved to [UtAssembleModel]. - * This model is instantiated by [java.util.ArrayList] constructor if utListClass is [UtListClass.UT_ARRAY_LIST], - * by [java.util.LinkedList] constructor if utListClass is [UtListClass.UT_LINKED_LIST] or by other constructors - * depending on concrete type from passed [ReferenceValue] in [resolveValueModels] function. + * This model is instantiated by constructor which is taken from the type from the passed [ReferenceValue] in [value] + * function. * * Modification chain consists of consequent [java.util.Collection.add] methods * that are arranged to iterating order of list. From 82176b2d316ff1477636b831e7010d9dbd50e1fe Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 15:16:31 +0300 Subject: [PATCH 12/14] Fix incorrect matcher --- .../kotlin/org/utbot/examples/collections/QueueUsagesTest.kt | 2 +- .../main/java/org/utbot/examples/collections/QueueUsages.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt index 8a181df077..f218b23945 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/QueueUsagesTest.kt @@ -74,7 +74,7 @@ class QueueUsagesTest : UtValueTestCaseChecker( QueueUsages::addAllQueue, eq(3), { q, _, r -> q == null && r.isException() }, - { q, x, r -> q != null && x != null && x in r.getOrNull()!! }, + { q, x, r -> q != null && x in r.getOrNull()!! }, // we can cover this line with x == null or x != null { q, x, r -> q != null && x == null && r.isException() }, ) } diff --git a/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java b/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java index 8dea9ab506..5a2586e844 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java +++ b/utbot-sample/src/main/java/org/utbot/examples/collections/QueueUsages.java @@ -44,8 +44,8 @@ public Queue addQueue(Queue q, WrappedInt x) { return q; } - public Queue addAllQueue(Queue q, WrappedInt o) { - Collection lst = Arrays.asList(new WrappedInt(1), o); + public Queue addAllQueue(Queue q, WrappedInt x) { + Collection lst = Arrays.asList(new WrappedInt(1), x); q.addAll(lst); return q; } From bf44d090a0115069fa7020b2ad5cb3ee66bdd933 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 15:17:08 +0300 Subject: [PATCH 13/14] Limit new heuristic usage --- .../org/utbot/framework/assemble/AssembleModelGenerator.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 3e44f4e312..db372f0da7 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 @@ -358,7 +358,8 @@ class AssembleModelGenerator(private val methodUnderTest: UtMethod<*>) { * Finds most appropriate constructor in class. * * If the [compositeModel].fields is empty, we don't care about affected fields, we would like to take an empty - * constructor or an appropriate constructor with the least number of arguments. + * constructor if the declaring class is from [java.util] package or an appropriate constructor with the least + * number of arguments. * * Otherwise, we prefer constructor that allows to set more fields than others * and use only simple assignments like "this.a = a". @@ -374,9 +375,10 @@ class AssembleModelGenerator(private val methodUnderTest: UtMethod<*>) { .map { it.executableId } return if (compositeModel.fields.isEmpty()) { + val fromUtilPackage = classId.packageName.startsWith("java.util") constructorIds .sortedBy { it.parameters.size } - .firstOrNull { it.parameters.isEmpty() || constructorAnalyzer.isAppropriate(it) } + .firstOrNull { it.parameters.isEmpty() && fromUtilPackage || constructorAnalyzer.isAppropriate(it) } } else { constructorIds .sortedByDescending { it.parameters.size } From b04251670f63c1852029abfbde350ecd48e1dd7c Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 31 Aug 2022 15:18:54 +0300 Subject: [PATCH 14/14] Clean up runSoot usages --- .../utbot/examples/manual/KotlinWrappers.kt | 2 +- .../java/org/utbot/framework/SootUtils.kt | 24 ----------------- .../assemble/AssembleModelGeneratorTests.kt | 2 +- .../UtBotFieldModificatorsTest.kt | 2 +- .../framework/plugin/api/TestCaseGenerator.kt | 4 +-- .../org/utbot/framework/util/SootUtils.kt | 27 ++++++++++++++++++- 6 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt diff --git a/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt b/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt index 411cb9f3bd..31aa00d2ae 100644 --- a/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt +++ b/utbot-framework-test/src/main/java/org/utbot/examples/manual/KotlinWrappers.kt @@ -8,7 +8,7 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel object SootUtils { @JvmStatic fun runSoot(clazz: Class<*>) { - org.utbot.framework.SootUtils.runSoot(clazz.kotlin) + org.utbot.framework.util.SootUtils.runSoot(clazz.kotlin) } } diff --git a/utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt b/utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt deleted file mode 100644 index bfd9ea4750..0000000000 --- a/utbot-framework-test/src/main/java/org/utbot/framework/SootUtils.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.utbot.framework - -import org.utbot.common.FileUtil -import org.utbot.framework.util.runSoot -import java.nio.file.Path -import kotlin.reflect.KClass - -object SootUtils { - - /** - * Runs Soot in tests if it hasn't already been done. - */ - fun runSoot(clazz: KClass<*>) { - val buildDir = FileUtil.locateClassPath(clazz) ?: FileUtil.isolateClassFiles(clazz) - val buildDirPath = buildDir.toPath() - - if (buildDirPath != previousBuildDir) { - runSoot(buildDirPath, null) - previousBuildDir = buildDirPath - } - } - - private var previousBuildDir: Path? = null -} diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt b/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt index fdc2fc5044..c390e05654 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt @@ -31,7 +31,6 @@ import org.utbot.examples.assemble.constructors.PrivateConstructor import org.utbot.examples.assemble.defaults.DefaultFieldWithSetter import org.utbot.examples.assemble.defaults.DefaultPackagePrivateField import org.utbot.examples.assemble.statics.StaticField -import org.utbot.framework.SootUtils import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.MethodId @@ -56,6 +55,7 @@ import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test +import org.utbot.framework.util.SootUtils /** * Test classes must be located in the same folder as [AssembleTestUtils] class. diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt index 38b2b768b5..9962d76c05 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt @@ -12,7 +12,6 @@ import org.utbot.examples.modificators.StronglyConnectedComponents import org.utbot.examples.modificators.coupling.ClassA import org.utbot.examples.modificators.coupling.ClassB import org.utbot.examples.modificators.hierarchy.InheritedModifications -import org.utbot.framework.SootUtils import org.utbot.framework.modifications.AnalysisMode import org.utbot.framework.modifications.AnalysisMode.AllModificators import org.utbot.framework.modifications.AnalysisMode.SettersAndDirectAccessors @@ -25,6 +24,7 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.utbot.framework.util.SootUtils internal class UtBotFieldModificatorsTest { private lateinit var fieldsModificatorsSearcher: UtBotFieldsModificatorsSearcher 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 ab7eb7e770..5aff213ab4 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 @@ -34,8 +34,8 @@ import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.intArrayClassId import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.plugin.api.util.withUtContext +import org.utbot.framework.util.SootUtils import org.utbot.framework.util.jimpleBody -import org.utbot.framework.util.runSoot import org.utbot.framework.util.toModel import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.warmup @@ -78,7 +78,7 @@ open class TestCaseGenerator( } timeoutLogger.trace().bracket("Soot initialization") { - runSoot(buildDir, classpath) + SootUtils.runSoot(buildDir, classpath) } //warmup diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt index 87287f2595..ed389b7ed4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/util/SootUtils.kt @@ -52,10 +52,35 @@ import soot.jimple.JimpleBody import soot.options.Options import soot.toolkits.graph.ExceptionalUnitGraph +object SootUtils { + /** + * Runs Soot in tests if it hasn't already been done. + */ + fun runSoot(clazz: KClass<*>) { + val buildDir = FileUtil.locateClassPath(clazz) ?: FileUtil.isolateClassFiles(clazz) + val buildDirPath = buildDir.toPath() + + runSoot(buildDirPath, null) + } + + fun runSoot(buildDirPath: Path, classPath: String?) { + synchronized(this) { + if (buildDirPath != previousBuildDir || classPath != previousClassPath) { + org.utbot.framework.util.runSoot(buildDirPath, classPath) + previousBuildDir = buildDirPath + previousClassPath = classPath + } + } + } + + private var previousBuildDir: Path? = null + private var previousClassPath: String? = null +} + /** Convert code to Jimple */ -fun runSoot(buildDir: Path, classpath: String?) { +private fun runSoot(buildDir: Path, classpath: String?) { G.reset() val options = Options.v()