From 3a6f06f55e8bf68ef7b0508967bbff944446706e Mon Sep 17 00:00:00 2001 From: Alexey Menshutin Date: Mon, 24 Oct 2022 13:41:47 +0800 Subject: [PATCH 1/2] Map don't work without concrete Fixes: * aliasing between nested arrays of UtHashMap and its fields * unsat for get operation from Map --- .../examples/collections/MapsPart1Test.kt | 61 +++++++++++++ .../overrides/collections/UtHashMap.java | 19 +++- .../org/utbot/engine/ArrayObjectWrappers.kt | 89 +++++++++++-------- .../kotlin/org/utbot/engine/ObjectWrappers.kt | 15 ++++ .../org/utbot/engine/pc/UtExpression.kt | 2 +- .../org/utbot/examples/collections/Maps.java | 57 ++++++++++++ 6 files changed, 203 insertions(+), 40 deletions(-) diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt index 926f1fad71..5bd9cc935e 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge import org.utbot.testcheckers.withPushingStateFromPathSelectorForConcrete +import org.utbot.testcheckers.withoutConcrete import org.utbot.testcheckers.withoutMinimization import org.utbot.tests.infrastructure.CodeGeneration @@ -84,6 +85,45 @@ internal class MapsPart1Test : UtValueTestCaseChecker( ) } + @Test + fun testMapPutAndGet() { + withoutConcrete { + check( + Maps::mapPutAndGet, + eq(1), + { r -> r == 3 } + ) + } + } + + @Test + fun testPutInMapFromParameters() { + withoutConcrete { + check( + Maps::putInMapFromParameters, + ignoreExecutionsNumber, + { values, _ -> values == null }, + { values, r -> 1 in values.keys && r == 3 }, + { values, r -> 1 !in values.keys && r == 3 }, + ) + } + } + + // This test doesn't check anything specific, but the code from MUT + // caused errors with NPE as results while debugging `testPutInMapFromParameters`. + @Test + fun testContainsKeyAndPuts() { + withoutConcrete { + check( + Maps::containsKeyAndPuts, + eq(2), + { values, _ -> values == null }, + { values, r -> 1 !in values.keys && r == 3 }, + coverage = DoNotCalculate + ) + } + } + @Test fun testFindAllChars() { check( @@ -324,4 +364,25 @@ internal class MapsPart1Test : UtValueTestCaseChecker( coverage = DoNotCalculate ) } + + @Test + fun testCreateMapWithString() { + withoutConcrete { + check( + Maps::createMapWithString, + eq(1), + { r -> r!!.isEmpty() } + ) + } + } + @Test + fun testCreateMapWithEnum() { + withoutConcrete { + check( + Maps::createMapWithEnum, + eq(1), + { r -> r != null && r.size == 2 && r[Maps.WorkDays.Monday] == 112 && r[Maps.WorkDays.Friday] == 567 } + ) + } + } } \ No newline at end of file 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 f3a9b22405..97efe821d9 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 @@ -102,6 +102,12 @@ void preconditionCheck() { parameter(keys); parameter(keys.storage); + // Following three instructions are required to avoid possible aliasing + // between nested arrays + assume(keys.storage != values.storage); + assume(keys.storage != values.touched); + assume(values.storage != values.touched); + assume(values.size == keys.end); assume(values.touched.length == keys.end); doesntThrow(); @@ -205,11 +211,18 @@ public V put(K key, V value) { if (index == -1) { oldValue = null; keys.set(keys.end++, key); + values.store(key, value); } else { - // newKey equals to oldKey so we can use it instead - oldValue = values.select(key); + K oldKey = keys.get(index); + oldValue = values.select(oldKey); + values.store(oldKey, value); } - values.store(key, value); + + // Avoid optimization here. Despite the fact that old key is equal + // to a new one in case of `index != -1`, it is important to have + // this connection between `index`, `key`, `oldKey` and `value`. + // So, do not rewrite it with `values.store(key, value)` extracted from the if instruction + return oldValue; } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/ArrayObjectWrappers.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/ArrayObjectWrappers.kt index 5049d5d397..cfef9a2ea8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/ArrayObjectWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/ArrayObjectWrappers.kt @@ -215,13 +215,17 @@ class RangeModifiableUnlimitedArrayWrapper : WrapperInterface { createArray(addr, valueType, useConcreteType = false) } - listOf( - MethodResult( - SymbolicSuccess(resultObject), - typeRegistry.typeConstraintToGenericTypeParameter(addr, wrapper.addr, i = TYPE_PARAMETER_INDEX) - .asHardConstraint() - ) - ) + val typeIndex = wrapper.asWrapperOrNull?.getOperationTypeIndex + ?: error("Wrapper was expected, got $wrapper") + val typeConstraint = typeRegistry.typeConstraintToGenericTypeParameter( + addr, + wrapper.addr, + i = typeIndex + ).asHardConstraint() + + val methodResult = MethodResult(SymbolicSuccess(resultObject), typeConstraint) + + listOf(methodResult) } @Suppress("UNUSED_PARAMETER") @@ -418,16 +422,17 @@ class AssociativeArrayWrapper : WrapperInterface { val addr = UtAddrExpression(value) val resultObject = createObject(addr, OBJECT_TYPE, useConcreteType = false) - listOf( - MethodResult( - SymbolicSuccess(resultObject), - typeRegistry.typeConstraintToGenericTypeParameter( - addr, - wrapper.addr, - TYPE_PARAMETER_INDEX - ).asHardConstraint() - ) - ) + val typeIndex = wrapper.asWrapperOrNull?.selectOperationTypeIndex + ?: error("Wrapper was expected, got $wrapper") + val hardConstraints = typeRegistry.typeConstraintToGenericTypeParameter( + addr, + wrapper.addr, + typeIndex + ).asHardConstraint() + + val methodResult = MethodResult(SymbolicSuccess(resultObject), hardConstraints) + + listOf(methodResult) } @Suppress("UNUSED_PARAMETER") @@ -440,21 +445,31 @@ class AssociativeArrayWrapper : WrapperInterface { with(traverser) { val storageValue = getStorageArrayExpression(wrapper).store(parameters[0].addr, parameters[1].addr) val sizeValue = getIntFieldValue(wrapper, sizeField) + + // it is the reason why it's important to use an `oldKey` in `UtHashMap.put` method. + // We navigate in the associative array using only this old address, not a new one. val touchedValue = getTouchedArrayExpression(wrapper).store(sizeValue, parameters[0].addr) - listOf( - MethodResult( - SymbolicSuccess(voidValue), - memoryUpdates = arrayUpdateWithValue( - getStorageArrayField(wrapper.addr).addr, - OBJECT_TYPE.arrayType, - storageValue - ) + arrayUpdateWithValue( - getTouchedArrayField(wrapper.addr).addr, - OBJECT_TYPE.arrayType, - touchedValue, - ) + objectUpdate(wrapper, sizeField, Add(sizeValue.toIntValue(), 1.toPrimitiveValue())) - ) + val storageArrayAddr = getStorageArrayField(wrapper.addr).addr + val touchedArrayFieldAddr = getTouchedArrayField(wrapper.addr).addr + + val storageArrayUpdate = arrayUpdateWithValue( + storageArrayAddr, + OBJECT_TYPE.arrayType, + storageValue + ) + + val touchedArrayUpdate = arrayUpdateWithValue( + touchedArrayFieldAddr, + OBJECT_TYPE.arrayType, + touchedValue, ) + + val sizeUpdate = objectUpdate(wrapper, sizeField, Add(sizeValue.toIntValue(), 1.toPrimitiveValue())) + + val memoryUpdates = storageArrayUpdate + touchedArrayUpdate + sizeUpdate + val methodResult = MethodResult(SymbolicSuccess(voidValue), memoryUpdates = memoryUpdates) + + listOf(methodResult) } override val wrappedMethods: Map = mapOf( @@ -480,7 +495,7 @@ class AssociativeArrayWrapper : WrapperInterface { // construct model values of an array val touchedValues = UtArrayModel( resolver.holder.concreteAddr(UtAddrExpression(touchedArrayAddr)), - objectClassId, + objectArrayClassId, sizeValue, UtNullModel(objectClassId), stores = (0 until sizeValue).associateWithTo(mutableMapOf()) { i -> @@ -504,7 +519,7 @@ class AssociativeArrayWrapper : WrapperInterface { val storageValues = UtArrayModel( resolver.holder.concreteAddr(UtAddrExpression(storageArrayAddr)), - objectClassId, + objectArrayClassId, sizeValue, UtNullModel(objectClassId), stores = (0 until sizeValue).associateTo(mutableMapOf()) { i -> @@ -518,10 +533,12 @@ class AssociativeArrayWrapper : WrapperInterface { ) }) - val model = UtCompositeModel(resolver.holder.concreteAddr(wrapper.addr), associativeArrayId, false) + val model = UtCompositeModel(resolver.holder.concreteAddr(wrapper.addr), associativeArrayId, isMock = false) + model.fields[sizeField.fieldId] = UtPrimitiveModel(sizeValue) model.fields[touchedField.fieldId] = touchedValues model.fields[storageField.fieldId] = storageValues + return model } @@ -537,7 +554,7 @@ class AssociativeArrayWrapper : WrapperInterface { private fun Traverser.getStorageArrayExpression( wrapper: ObjectValue ): UtExpression = selectArrayExpressionFromMemory(getStorageArrayField(wrapper.addr)) -} -// Arrays and lists have the only type parameter with index zero -private const val TYPE_PARAMETER_INDEX = 0 + override val selectOperationTypeIndex: Int + get() = 1 +} 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 6bcc8a24ae..15e54fe332 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt @@ -244,6 +244,21 @@ interface WrapperInterface { } fun value(resolver: Resolver, wrapper: ObjectValue): UtModel + + /** + * It is an index for type parameter corresponding to the result + * value of `select` operation. For example, for arrays and lists it's zero, + * for associative array it's one. + */ + open val selectOperationTypeIndex: Int + get() = 0 + + /** + * Similar to [selectOperationTypeIndex], it is responsible for type index + * of the returning value from `get` operation + */ + open val getOperationTypeIndex: Int + get() = 0 } // TODO: perhaps we have to have wrapper around concrete value here diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtExpression.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtExpression.kt index 8a1da26d78..b0f7ea8b94 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtExpression.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtExpression.kt @@ -455,7 +455,7 @@ class UtIsGenericTypeExpression( override fun accept(visitor: UtExpressionVisitor): TResult = visitor.visit(this) override fun toString(): String { - return "(generic-is $addr $baseAddr<\$$parameterTypeIndex>)" + return "(generic-is $addr baseAddr: $baseAddr<\$$parameterTypeIndex>)" } override fun equals(other: Any?): Boolean { diff --git a/utbot-sample/src/main/java/org/utbot/examples/collections/Maps.java b/utbot-sample/src/main/java/org/utbot/examples/collections/Maps.java index 5bd4f6882d..2d20a80a72 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/collections/Maps.java +++ b/utbot-sample/src/main/java/org/utbot/examples/collections/Maps.java @@ -1,5 +1,7 @@ package org.utbot.examples.collections; +import org.utbot.api.mock.UtMock; + import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -25,6 +27,36 @@ String mapToString(long startTime, int pageSize, int pageNum) { return params.toString(); } + @SuppressWarnings("OverwrittenKey") + Integer mapPutAndGet() { + Map values = new HashMap<>(); + + values.put(1L, 2); + values.put(1L, 3); + + return values.get(1L); + } + + @SuppressWarnings("OverwrittenKey") + Integer putInMapFromParameters(Map values) { + values.put(1L, 2); + values.put(1L, 3); + + return values.get(1L); + } + + @SuppressWarnings("OverwrittenKey") + Integer containsKeyAndPuts(Map values) { + UtMock.assume(!values.containsKey(1L)); + + values.put(1L, 2); + values.put(1L, 3); + + UtMock.assume(values.get(1L).equals(3)); + + return values.get(1L); + } + Map countChars(String s) { Map map = new LinkedHashMap<>(); for (int i = 0; i < s.length(); i++) { @@ -261,4 +293,29 @@ public List mapOperator(Map map) { return new ArrayList<>(map.values()); } } + + public Map createMapWithString() { + Map map = new HashMap<>(); + map.put("tuesday", 354); + map.remove("tuesday"); + + return map; + } + public Map createMapWithEnum() { + Map map = new HashMap<>(); + map.put(WorkDays.Monday, 112); + map.put(WorkDays.Tuesday, 354); + map.put(WorkDays.Friday, 567); + map.remove(WorkDays.Tuesday); + + return map; + } + + public enum WorkDays { + Monday, + Tuesday, + Wednesday, + Thursday, + Friday + } } From 03ffb84d6dcbf4dce4f8c095c2f4c2d8b489b80b Mon Sep 17 00:00:00 2001 From: Alexey Menshutin Date: Wed, 26 Oct 2022 11:42:28 +0800 Subject: [PATCH 2/2] Fixes for type system and fallbacks in it --- .../org/utbot/framework/plugin/api/Api.kt | 3 +- .../examples/arrays/ArrayOfObjectsTest.kt | 20 +++---- .../examples/collections/MapEntrySetTest.kt | 4 +- .../examples/collections/MapsPart1Test.kt | 2 +- .../main/kotlin/org/utbot/engine/Resolver.kt | 53 ++++++++++++++++--- .../infrastructure/CompilationAndRunUtils.kt | 2 + 6 files changed, 65 insertions(+), 19 deletions(-) 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 723467a634..0c0f5efe08 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 @@ -1297,7 +1297,8 @@ enum class CodegenLanguage( JAVA -> listOf( "-d", buildDirectory, "-cp", classPath, - "-XDignore.symbol.file" // to let javac use classes from rt.jar + "-XDignore.symbol.file", // to let javac use classes from rt.jar + "--add-exports", "java.base/sun.reflect.generics.repository=ALL-UNNAMED" ).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/arrays/ArrayOfObjectsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArrayOfObjectsTest.kt index ae4fd7b874..0f279c793a 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArrayOfObjectsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArrayOfObjectsTest.kt @@ -103,14 +103,16 @@ internal class ArrayOfObjectsTest : UtValueTestCaseChecker( @Test fun testArrayOfArrays() { - check( - ArrayOfObjects::arrayOfArrays, - between(4..5), // might be two ClassCastExceptions - { a, _ -> a.any { it == null } }, - { a, _ -> a.any { it != null && it !is IntArray } }, - { a, r -> (a.all { it != null && it is IntArray && it.isEmpty() } || a.isEmpty()) && r == 0 }, - { a, r -> a.all { it is IntArray } && r == a.sumBy { (it as IntArray).sum() } }, - coverage = DoNotCalculate - ) + withEnabledTestingCodeGeneration(testCodeGeneration = false) { + check( + ArrayOfObjects::arrayOfArrays, + between(4..5), // might be two ClassCastExceptions + { a, _ -> a.any { it == null } }, + { a, _ -> a.any { it != null && it !is IntArray } }, + { a, r -> (a.all { it != null && it is IntArray && it.isEmpty() } || a.isEmpty()) && r == 0 }, + { a, r -> a.all { it is IntArray } && r == a.sumBy { (it as IntArray).sum() } }, + coverage = DoNotCalculate + ) + } } } \ No newline at end of file diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapEntrySetTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapEntrySetTest.kt index 7d62a1fa88..eb468a4bac 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapEntrySetTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapEntrySetTest.kt @@ -7,10 +7,10 @@ import org.utbot.tests.infrastructure.isException import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge import org.utbot.testcheckers.withPushingStateFromPathSelectorForConcrete import org.utbot.tests.infrastructure.CodeGeneration +import org.utbot.tests.infrastructure.ignoreExecutionsNumber // TODO failed Kotlin compilation SAT-1332 class MapEntrySetTest : UtValueTestCaseChecker( @@ -152,7 +152,7 @@ class MapEntrySetTest : UtValueTestCaseChecker( withPushingStateFromPathSelectorForConcrete { checkWithException( MapEntrySet::iterateWithIterator, - eq(6), + ignoreExecutionsNumber, { map, result -> map == null && result.isException() }, { map, result -> map.isEmpty() && result.getOrThrow().contentEquals(intArrayOf(0, 0)) }, { map, result -> map.size % 2 == 1 && result.isException() }, diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt index 5bd9cc935e..738e45f661 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt @@ -116,7 +116,7 @@ internal class MapsPart1Test : UtValueTestCaseChecker( withoutConcrete { check( Maps::containsKeyAndPuts, - eq(2), + ignoreExecutionsNumber, { values, _ -> values == null }, { values, r -> 1 !in values.keys && r == 3 }, coverage = DoNotCalculate diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt index 7d4fc70163..62f125640f 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt @@ -717,11 +717,16 @@ class Resolver( * Constructs a type for the addr. * * There are three options here: + * * * it successfully constructs a type suitable with defaultType and returns it; + * * * it constructs a type that cannot be assigned in a variable with the [defaultType] and we `touched` - * the [addr] during the analysis. In such case the method returns [defaultType] as a result - * if the constructed type is not an array, and in case of array it returns the [defaultType] if it has the same - * dimensions as the constructed type and its ancestors includes the constructed type, or null otherwise; + * the [addr] during the analysis. In such case we have only two options: either this object was aliased with + * an object of another type (by solver's decision) and we didn't touch it in fact, or it happened because + * of missed connection between an array type and types of its elements. For example, we might case + * array to a succ type after we `touched` it's element. In the first scenario null will be returns, in the + * second one -- a default type (that will be a subtype of actualType). + * * * it constructs a type that cannot be assigned in a variable with the [defaultType] and we did **not** `touched` * the [addr] during the analysis. It means we can create [UtNullModel] to represent such element. In such case * the method returns null as the result. @@ -816,12 +821,22 @@ class Resolver( // as const or store model. if (defaultBaseType is PrimType) return null + // There is no way you have java.lang.Object as a defaultType here, since it'd mean that + // some actualType is not an inheritor of it require(!defaultType.isJavaLangObject()) { "Object type $defaultType is unexpected in fallback to default type" } - if (defaultType.numDimensions == 0) { - return defaultType + // It might happen only if we have a wrong aliasing here: some object has not been touched + // during the execution, and solver returned for him an address of already existed object + // with another type. In such case `UtNullModel` should be constructed. + if (defaultBaseType.isJavaLangObject() && actualType.numDimensions < defaultType.numDimensions) { + return null + } + + // All cases with `java.lang.Object` as default base type should have been already processed + require(!defaultBaseType.isJavaLangObject()) { + "Unexpected `java.lang.Object` as a default base type" } val actualBaseType = actualType.baseType @@ -829,6 +844,12 @@ class Resolver( require(actualBaseType is RefType) { "Expected RefType, but $actualBaseType found" } require(defaultBaseType is RefType) { "Expected RefType, but $defaultBaseType found" } + + // The same idea about fake aliasing. It might happen only if there have been an aliasing + // because of the solver's decision. In fact an object for which we construct type has not been + // touched during analysis. + if (actualType.numDimensions != defaultType.numDimensions) return null + val ancestors = typeResolver.findOrConstructAncestorsIncludingTypes(defaultBaseType) // This is intended to fix a specific problem. We have code: @@ -840,7 +861,27 @@ class Resolver( // when the array is ColoredPoint[], but the first element of it got type Point from the solver. // In such case here we'll have ColoredPoint as defaultType and Point as actualType. It is obvious from the example // that we can construct ColoredPoint instance instead of it with randomly filled colored-specific fields. - return defaultType.takeIf { actualBaseType in ancestors && actualType.numDimensions == defaultType.numDimensions } + // Note that it won't solve a problem when this `array[0]` has already been constructed somewhere above, + // since a model for it is already presented in cache and will be taken by addr from it. + // TODO corresponding issue https://github.com/UnitTestBot/UTBotJava/issues/1232 + if (actualBaseType in ancestors) return defaultType + + val inheritors = typeResolver.findOrConstructInheritorsIncludingTypes(defaultBaseType) + + // If we have an actual type that is not a subclass of defaultBaseType and isTouched is true, + // it means that we have encountered unexpected aliasing between an object for which we resolve its type + // and some object in the system. The reason is `isTouched` means that we processed this object + // during the analysis, therefore we create correct type constraints for it. Since we have + // inappropriate actualType here, these constraints were supposed to define type for another object, + // and, in fact, we didn't touch our object. + // For example, we have an array of two elements: Integer[] = new Integer[2], and this instance: ThisClass. + // During the execution we `touched` only the first element of the array, and we know its type. + // During resolving we found that second element of the array has set in true `isTouched` field, + // and its actualType is `ThisClass`. So, we have wrong aliasing here and can return `null` to construct + // UtNullModel instead. + if (actualBaseType !in inheritors) return null + + return null } /** 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..151d34b1ec 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 @@ -61,6 +61,8 @@ fun runTests( val classpath = System.getProperty("java.class.path") + File.pathSeparator + buildDirectory val executionInvoke = generatedLanguage.executorInvokeCommand val additionalArguments = listOf( + "--add-opens", + "java.base/sun.reflect.generics.repository=ALL-UNNAMED", "-ea", // Enable assertions )