From 5900dc350f28234c48e05f06c788c694d0929342 Mon Sep 17 00:00:00 2001 From: Nikita Vlaev Date: Fri, 12 Aug 2022 17:03:29 +0300 Subject: [PATCH] Generics in Kotlin codegen (#88) Refactored imports to support kotlin builtins (List, Map, e.t.c). Added generics propagation using callables. Added filling generics with Any? and *. Reworked Kotlin type render. Fixed assemble model generation in concrete. Fixed bug with backticks. --- .../main/kotlin/org/utbot/common/HackUtil.kt | 10 + .../org/utbot/framework/plugin/api/Api.kt | 213 +++++++++++- .../examples/algorithms/BinarySearchTest.kt | 2 +- .../examples/arrays/ArrayOfObjectsTest.kt | 12 +- .../arrays/ArraysOverwriteValueTest.kt | 12 +- .../examples/arrays/IntArrayBasicsTest.kt | 14 +- .../examples/arrays/PrimitiveArraysTest.kt | 12 +- .../examples/casts/ArrayCastExampleTest.kt | 12 +- .../utbot/examples/casts/CastExampleTest.kt | 12 +- .../examples/casts/InstanceOfExampleTest.kt | 14 +- .../codegen/deepequals/DeepEqualsTest.kt | 14 +- .../examples/collections/LinkedListsTest.kt | 12 +- .../collections/ListAlgorithmsTest.kt | 12 +- .../examples/collections/ListIteratorsTest.kt | 12 +- .../collections/ListWrapperReturnsVoidTest.kt | 12 +- .../examples/collections/ListsPart3Test.kt | 14 +- .../examples/collections/MapEntrySetTest.kt | 12 +- .../examples/collections/MapKeySetTest.kt | 12 +- .../examples/collections/MapValuesTest.kt | 14 +- .../examples/collections/MapsPart1Test.kt | 12 +- .../examples/collections/SetIteratorsTest.kt | 12 +- .../utbot/examples/collections/SetsTest.kt | 14 +- .../utbot/examples/mixed/LoggerExampleTest.kt | 11 +- .../models/ModelsIdEqualityChecker.kt | 12 +- .../examples/objects/ClassWithClassRefTest.kt | 2 +- .../examples/strings/StringExamplesTest.kt | 13 +- .../examples/wrappers/CharacterWrapperTest.kt | 12 +- .../examples/wrappers/LongWrapperTest.kt | 11 +- .../org/utbot/engine/UtBotSymbolicEngine.kt | 5 +- .../org/utbot/framework/codegen/Domain.kt | 24 +- .../model/constructor/name/CgNameGenerator.kt | 3 +- .../tree/CgCallableAccessManager.kt | 6 +- .../constructor/tree/CgMethodConstructor.kt | 2 +- .../constructor/util/ConstructorUtils.kt | 7 +- .../model/visitor/CgAbstractRenderer.kt | 10 +- .../codegen/model/visitor/CgJavaRenderer.kt | 7 +- .../codegen/model/visitor/CgKotlinRenderer.kt | 91 +++-- .../codegen/model/visitor/UtilMethods.kt | 2 +- .../concrete/OptionalConstructors.kt | 2 +- .../plugin/api/GenericsProcessing.kt | 315 ++++++++++++++++++ .../utbot/framework/plugin/api/TestFlow.kt | 3 +- .../org/utbot/fuzzer/UtFuzzedExecution.kt | 22 ++ .../generator/CodeGenerationController.kt | 2 +- 43 files changed, 685 insertions(+), 342 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/GenericsProcessing.kt diff --git a/utbot-core/src/main/kotlin/org/utbot/common/HackUtil.kt b/utbot-core/src/main/kotlin/org/utbot/common/HackUtil.kt index 881b708f55..bf949e06e3 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/HackUtil.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/HackUtil.kt @@ -67,4 +67,14 @@ enum class WorkaroundReason { * requires thorough [investigation](https://github.com/UnitTestBot/UTBotJava/issues/716). */ IGNORE_STATICS_FROM_TRUSTED_LIBRARIES, + + /** + * Special handling of collection constructors from other collections (for generics processing) + */ + COLLECTION_CONSTRUCTOR_FROM_COLLECTION, + + /** + * Assume that in calls to methods in modification chain always require the same type parameters as class has + */ + MODIFICATION_CHAIN_GENERICS_FROM_CLASS, } \ No newline at end of file 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 fcfb6abc0c..4cfa72a995 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 @@ -28,6 +28,7 @@ import org.utbot.framework.plugin.api.util.isPrimitive import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.method +import org.utbot.framework.plugin.api.util.objectClassId import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull import org.utbot.framework.plugin.api.util.safeJField import org.utbot.framework.plugin.api.util.shortClassId @@ -56,6 +57,7 @@ import kotlin.jvm.internal.CallableReference import kotlin.reflect.KCallable import kotlin.reflect.KClass import kotlin.reflect.KFunction +import kotlin.reflect.KType import kotlin.reflect.full.instanceParameter import kotlin.reflect.jvm.javaConstructor import kotlin.reflect.jvm.javaType @@ -152,7 +154,28 @@ abstract class UtExecution( var summary: List? = null, var testMethodName: String? = null, var displayName: String? = null -) : UtResult() +) : UtResult() { + abstract fun copy( + stateBefore: EnvironmentModels = this.stateBefore, + stateAfter: EnvironmentModels = this.stateAfter, + result: UtExecutionResult = this.result, + coverage: Coverage? = this.coverage, + summary: List? = this.summary, + testMethodName: String? = this.testMethodName, + displayName: String? = this.displayName, + ): UtExecution + // { +// return UtExecution( +// stateBefore, +// stateAfter, +// result, +// coverage, +// summary, +// testMethodName, +// displayName +// ) +// } +} /** * Symbolic execution. @@ -207,8 +230,15 @@ class UtSymbolicExecution( appendOptional("instrumentation", instrumentation) append(")") } - - fun copy(stateAfter: EnvironmentModels, result: UtExecutionResult, coverage: Coverage): UtResult { + override fun copy( + stateBefore: EnvironmentModels, + stateAfter: EnvironmentModels, + result: UtExecutionResult, + coverage: Coverage?, + summary: List?, + testMethodName: String?, + displayName: String?, + ): UtSymbolicExecution { return UtSymbolicExecution( stateBefore, stateAfter, @@ -243,7 +273,27 @@ class UtFailedExecution( summary: List? = null, testMethodName: String? = null, displayName: String? = null -) : UtExecution(stateBefore, MissingState, result, coverage, summary, testMethodName, displayName) +) : UtExecution(stateBefore, MissingState, result, coverage, summary, testMethodName, displayName) { + override fun copy( + stateBefore: EnvironmentModels, + stateAfter: EnvironmentModels, + result: UtExecutionResult, + coverage: Coverage?, + summary: List?, + testMethodName: String?, + displayName: String? + ): UtExecution { + // TODO possible problem? + return UtFailedExecution( + stateBefore, + result as UtExecutionFailure, + coverage, + summary, + testMethodName, + displayName + ) + } +} open class EnvironmentModels( val thisInstance: UtModel?, @@ -699,9 +749,25 @@ val Type.classId: ClassId open class ClassId @JvmOverloads constructor( val name: String, val elementClassId: ClassId? = null, - // Treat simple class ids as non-nullable - open val isNullable: Boolean = false + // Treat simple class ids as non-nullable and having no type parameters + open val isNullable: Boolean = false, + /** + * This might cause problems in case of reusing the same [ClassId] for different models. + */ + open val typeParameters: TypeParameters = TypeParameters() ) { + open fun copy( + name: String = this.name, + elementClassId: ClassId? = this.elementClassId, + isNullable: Boolean = this.isNullable, + typeParameters: TypeParameters = this.typeParameters, + ) : ClassId = + ClassId( + name, + elementClassId, + isNullable, + typeParameters, + ) open val canonicalName: String get() = jClass.canonicalName ?: error("ClassId $name does not have canonical name") @@ -781,9 +847,6 @@ open class ClassId @JvmOverloads constructor( open val allConstructors: Sequence get() = jClass.declaredConstructors.asSequence().map { it.executableId } - open val typeParameters: TypeParameters - get() = TypeParameters() - open val outerClass: Class<*>? get() = jClass.enclosingClass @@ -925,6 +988,34 @@ open class FieldId(val declaringClass: ClassId, val name: String) { open val type: ClassId get() = strategy.type + // required to store and update type parameters + // TODO check if by lazy works correctly in newer Kotlin (https://stackoverflow.com/questions/47638464/kotlin-lazy-var-throwing-classcastexception-kotlin-uninitialized-value) + // val fixedType: ClassId by lazy { type } + private var hiddenFixedType: ClassId? = null + + val fixedType: ClassId + get() { + if (hiddenFixedType == null) { + hiddenFixedType = type + } + return hiddenFixedType!! + } + + fun copy( + declaringClass: ClassId = this.declaringClass, + name: String = this.name, + hiddenFixedType: ClassId? = this.hiddenFixedType, + ): FieldId { + val newFieldId = FieldId( + declaringClass, + name + ) + + newFieldId.hiddenFixedType = hiddenFixedType + + return newFieldId + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -1000,6 +1091,19 @@ sealed class ExecutableId : StatementId() { abstract val isProtected: Boolean abstract val isPrivate: Boolean + /** + * This might cause problems in case of reusing the same [ExecutableId] for different models. + */ + abstract val typeParameters: TypeParameters + + abstract fun copy( + classId: ClassId = this.classId, + name: String = this.name, + returnType: ClassId = this.returnType, + parameters: List = this.parameters, + typeParameters: TypeParameters = this.typeParameters + ) : ExecutableId + val isPackagePrivate: Boolean get() = !(isPublic || isProtected || isPrivate) @@ -1041,8 +1145,23 @@ open class MethodId( override val classId: ClassId, override val name: String, override val returnType: ClassId, - override val parameters: List + override val parameters: List, + override val typeParameters: TypeParameters = TypeParameters(), ) : ExecutableId() { + override fun copy( + classId: ClassId, + name: String, + returnType: ClassId, + parameters: List, + typeParameters: TypeParameters, + ): ExecutableId = MethodId( + classId, + name, + returnType, + parameters, + typeParameters + ) + open val isStatic: Boolean get() = Modifier.isStatic(method.modifiers) @@ -1056,10 +1175,23 @@ open class MethodId( get() = Modifier.isPrivate(method.modifiers) } -class ConstructorId( +data class ConstructorId( override val classId: ClassId, - override val parameters: List + override val parameters: List, + override val typeParameters: TypeParameters = TypeParameters(), ) : ExecutableId() { + override fun copy( + classId: ClassId, + name: String, + returnType: ClassId, + parameters: List, + typeParameters: TypeParameters, + ): ConstructorId = ConstructorId( + classId, + parameters, + typeParameters, + ) + override val name: String = "" override val returnType: ClassId = voidClassId @@ -1078,16 +1210,67 @@ class BuiltinMethodId( name: String, returnType: ClassId, parameters: List, + typeParameters: TypeParameters = TypeParameters(), // by default we assume that the builtin method is non-static and public override val isStatic: Boolean = false, override val isPublic: Boolean = true, override val isProtected: Boolean = false, override val isPrivate: Boolean = false -) : MethodId(classId, name, returnType, parameters) +) : MethodId(classId, name, returnType, parameters, typeParameters) { + override fun copy( + classId: ClassId, + name: String, + returnType: ClassId, + parameters: List, + typeParameters: TypeParameters, + ): BuiltinMethodId = BuiltinMethodId( + classId, + name, + returnType, + parameters, + typeParameters, + ) +} + +open class TypeParameters(val parameters: List = emptyList()) { + override fun hashCode(): Int = parameters.toTypedArray().contentHashCode() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false -open class TypeParameters(val parameters: List = emptyList()) + other as TypeParameters + + // structural equality + if (parameters != other.parameters) return false + + return true + } +} + +fun ClassId.copyTypeParametersFromKType(type: KType): ClassId { + if (type.arguments.isEmpty()) return this + + val newTypeParameters = type.arguments.map { + when (val clazz = it.type?.classifier) { + is KClass<*> -> { + val classId = clazz.id + it.type?.let { t -> + classId.copyTypeParametersFromKType(t) + } ?: error("") + + classId + } + else -> objectClassId + } + } + + return copy( + typeParameters = TypeParameters(newTypeParameters) + ) +} -class WildcardTypeParameter : TypeParameters(emptyList()) +object WildcardTypeParameter: ClassId("org.utbot.framework.plugin.api.WildcardTypeParameter") interface CodeGenerationSettingItem { val displayName: String diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/algorithms/BinarySearchTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/algorithms/BinarySearchTest.kt index d197e8a838..3918a94772 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/algorithms/BinarySearchTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/algorithms/BinarySearchTest.kt @@ -9,7 +9,7 @@ import org.utbot.framework.plugin.api.DocRegularStmt import org.utbot.framework.plugin.api.DocStatement import org.junit.jupiter.api.Test -class BinarySearchTest : UtValueTestCaseChecker(testClass = BinarySearch::class,) { +class BinarySearchTest : UtValueTestCaseChecker(testClass = BinarySearch::class) { @Test fun testLeftBinarySearch() { val fullSummary = listOf( 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 5f67396996..8f71f0a1f1 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 @@ -6,21 +6,11 @@ import org.utbot.tests.infrastructure.atLeast import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -internal class ArrayOfObjectsTest : UtValueTestCaseChecker( - testClass = ArrayOfObjects::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class ArrayOfObjectsTest : UtValueTestCaseChecker(testClass = ArrayOfObjects::class) { @Test fun testDefaultValues() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArraysOverwriteValueTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArraysOverwriteValueTest.kt index 3f0bab6159..9d6fc11229 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArraysOverwriteValueTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/ArraysOverwriteValueTest.kt @@ -1,20 +1,10 @@ package org.utbot.examples.arrays import org.utbot.tests.infrastructure.UtValueTestCaseChecker -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -class ArraysOverwriteValueTest : UtValueTestCaseChecker( - testClass = ArraysOverwriteValue::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +class ArraysOverwriteValueTest : UtValueTestCaseChecker(testClass = ArraysOverwriteValue::class) { @Test fun testByteArray() { checkParamsMutationsAndResult( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/IntArrayBasicsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/IntArrayBasicsTest.kt index 89cd68e821..d2894fdfa3 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/IntArrayBasicsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/IntArrayBasicsTest.kt @@ -4,21 +4,11 @@ import org.junit.jupiter.api.Disabled import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge -import org.utbot.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation SAT-1332 -internal class IntArrayBasicsTest : UtValueTestCaseChecker( - testClass = IntArrayBasics::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +internal class IntArrayBasicsTest : UtValueTestCaseChecker(testClass = IntArrayBasics::class) { @Test fun testIntArrayWithAssumeOrExecuteConcretely() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/PrimitiveArraysTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/PrimitiveArraysTest.kt index 93353521fe..56c8d339d3 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/PrimitiveArraysTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/arrays/PrimitiveArraysTest.kt @@ -3,20 +3,10 @@ package org.utbot.examples.arrays import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.atLeast import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -internal class PrimitiveArraysTest : UtValueTestCaseChecker( - testClass = PrimitiveArrays::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class PrimitiveArraysTest : UtValueTestCaseChecker(testClass = PrimitiveArrays::class) { @Test fun testDefaultIntValues() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/ArrayCastExampleTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/ArrayCastExampleTest.kt index e57047e56c..91bc0e3b59 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/ArrayCastExampleTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/ArrayCastExampleTest.kt @@ -3,21 +3,11 @@ package org.utbot.examples.casts import org.junit.jupiter.api.Disabled import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation (generics) SAT-1332 //TODO: SAT-1487 calculate coverage for all methods of this test class -internal class ArrayCastExampleTest : UtValueTestCaseChecker( - testClass = ArrayCastExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class ArrayCastExampleTest : UtValueTestCaseChecker(testClass = ArrayCastExample::class) { @Test fun testCastToAncestor() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/CastExampleTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/CastExampleTest.kt index cc6078c0f7..3b5e67da1e 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/CastExampleTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/CastExampleTest.kt @@ -3,20 +3,10 @@ package org.utbot.examples.casts import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -internal class CastExampleTest : UtValueTestCaseChecker( - testClass = CastExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class CastExampleTest : UtValueTestCaseChecker(testClass = CastExample::class) { @Test fun testSimpleCast() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/InstanceOfExampleTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/InstanceOfExampleTest.kt index 2b4561ecf3..e6409eb0e5 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/InstanceOfExampleTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/casts/InstanceOfExampleTest.kt @@ -3,22 +3,12 @@ package org.utbot.examples.casts import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.ignoreExecutionsNumber -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.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation SAT-1332 -internal class InstanceOfExampleTest : UtValueTestCaseChecker( - testClass = InstanceOfExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +internal class InstanceOfExampleTest : UtValueTestCaseChecker(testClass = InstanceOfExample::class) { @Test fun testSimpleInstanceOf() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/codegen/deepequals/DeepEqualsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/codegen/deepequals/DeepEqualsTest.kt index 6fd453ca51..11898fce12 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/codegen/deepequals/DeepEqualsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/codegen/deepequals/DeepEqualsTest.kt @@ -2,21 +2,11 @@ package org.utbot.examples.codegen.deepequals import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate -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.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation (generics) SAT-1332 -class DeepEqualsTest : UtValueTestCaseChecker( - testClass = DeepEqualsTestingClass::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +class DeepEqualsTest : UtValueTestCaseChecker(testClass = DeepEqualsTestingClass::class) { @Test fun testReturnList() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/LinkedListsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/LinkedListsTest.kt index 7bc1497ffe..3fdaabc16c 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/LinkedListsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/LinkedListsTest.kt @@ -3,20 +3,10 @@ package org.utbot.examples.collections import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation (generics) SAT-1332 -internal class LinkedListsTest : UtValueTestCaseChecker( - testClass = LinkedLists::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class LinkedListsTest : UtValueTestCaseChecker(testClass = LinkedLists::class) { @Test fun testSet() { diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListAlgorithmsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListAlgorithmsTest.kt index 714c790228..bff8890a37 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListAlgorithmsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListAlgorithmsTest.kt @@ -1,21 +1,11 @@ package org.utbot.examples.collections import org.utbot.tests.infrastructure.UtValueTestCaseChecker -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.tests.infrastructure.atLeast import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -class ListAlgorithmsTest : UtValueTestCaseChecker( - testClass = ListAlgorithms::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +class ListAlgorithmsTest : UtValueTestCaseChecker(testClass = ListAlgorithms::class) { @Test fun testMergeLists() { diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListIteratorsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListIteratorsTest.kt index 053a1fa1da..de0a9ea516 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListIteratorsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListIteratorsTest.kt @@ -4,21 +4,11 @@ import org.junit.jupiter.api.Disabled import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.ignoreExecutionsNumber -import org.utbot.framework.plugin.api.CodegenLanguage import kotlin.math.min import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation (generics) SAT-1332 -internal class ListIteratorsTest : UtValueTestCaseChecker( - testClass = ListIterators::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class ListIteratorsTest : UtValueTestCaseChecker(testClass = ListIterators::class) { @Test fun testIterate() { diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListWrapperReturnsVoidTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListWrapperReturnsVoidTest.kt index b1356ecb47..fb02ee4337 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListWrapperReturnsVoidTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListWrapperReturnsVoidTest.kt @@ -4,21 +4,11 @@ import org.junit.jupiter.api.Disabled import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation ($ in function names, generics) SAT-1220 SAT-1332 @Disabled("Java 11 transition") -internal class ListWrapperReturnsVoidTest : UtValueTestCaseChecker( - testClass = ListWrapperReturnsVoidExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class ListWrapperReturnsVoidTest : UtValueTestCaseChecker(testClass = ListWrapperReturnsVoidExample::class) { @Test fun testRunForEach() { checkWithException( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListsPart3Test.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListsPart3Test.kt index 5242bc47d3..b09f2a1dc1 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListsPart3Test.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/ListsPart3Test.kt @@ -1,6 +1,5 @@ package org.utbot.examples.collections -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.utbot.tests.infrastructure.UtValueTestCaseChecker @@ -9,17 +8,8 @@ import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.isException import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge -import org.utbot.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation SAT-1332 -internal class ListsPart3Test : UtValueTestCaseChecker( - testClass = Lists::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +internal class ListsTest : UtValueTestCaseChecker(testClass = Lists::class) { @Test fun createTest() { check( 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 0139515e59..c2c7f39e35 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 @@ -4,23 +4,13 @@ import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.between 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 -// TODO failed Kotlin compilation SAT-1332 -class MapEntrySetTest : UtValueTestCaseChecker( - testClass = MapEntrySet::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +class MapEntrySetTest : UtValueTestCaseChecker(testClass = MapEntrySet::class) { @Test @Disabled("JIRA:1443") fun testRemoveFromEntrySet() { diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapKeySetTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapKeySetTest.kt index d82f0a87a7..032d9143ca 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapKeySetTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapKeySetTest.kt @@ -6,23 +6,13 @@ import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage 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.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -class MapKeySetTest : UtValueTestCaseChecker( - testClass = MapKeySet::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +class MapKeySetTest : UtValueTestCaseChecker(testClass = MapKeySet::class) { @Test fun testRemoveFromKeySet() { withoutMinimization { // TODO: JIRA:1506 diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapValuesTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapValuesTest.kt index 3eb88f6594..4f41f126ff 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapValuesTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapValuesTest.kt @@ -6,21 +6,11 @@ import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.ge import org.utbot.testcheckers.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation SAT-1332 -class MapValuesTest : UtValueTestCaseChecker( - testClass = MapValues::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +class MapValuesTest : UtValueTestCaseChecker(testClass = MapValues::class) { @Test fun testRemoveFromValues() { withoutMinimization { // TODO: JIRA:1506 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 22afa44e9d..e33bd9a396 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 @@ -5,23 +5,13 @@ import org.utbot.tests.infrastructure.AtLeast import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber -import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.MockStrategyApi import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq import org.utbot.testcheckers.ge import org.utbot.testcheckers.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation ($ in names, generics) SAT-1220 SAT-1332 -internal class MapsPart1Test : UtValueTestCaseChecker( - testClass = Maps::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class MapsPart1Test : UtValueTestCaseChecker(testClass = Maps::class) { @Test fun testPutElementIfAbsent() { withoutMinimization { // TODO: JIRA:1506 diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetIteratorsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetIteratorsTest.kt index 145a083892..fd9c655c6d 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetIteratorsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetIteratorsTest.kt @@ -4,20 +4,10 @@ import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Test import org.utbot.testcheckers.ge -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -class SetIteratorsTest : UtValueTestCaseChecker( - testClass = SetIterators::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +class SetIteratorsTest : UtValueTestCaseChecker(testClass = SetIterators::class) { @Test fun testIteratorHasNext() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetsTest.kt index add140e79f..a5f6e25d46 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/SetsTest.kt @@ -5,24 +5,14 @@ import org.utbot.tests.infrastructure.AtLeast import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber -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.testcheckers.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration - -// TODO failed Kotlin compilation SAT-1332 -internal class SetsTest : UtValueTestCaseChecker( - testClass = Sets::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +internal class SetsTest : UtValueTestCaseChecker(testClass = Sets::class) { @Test fun createTest() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/LoggerExampleTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/LoggerExampleTest.kt index e9fc3eb935..f741aefa8b 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/LoggerExampleTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/mixed/LoggerExampleTest.kt @@ -2,7 +2,6 @@ package org.utbot.examples.mixed import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate -import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtInstrumentation import org.utbot.framework.plugin.api.UtModel @@ -10,16 +9,8 @@ import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation import org.utbot.framework.plugin.api.isNull import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -internal class LoggerExampleTest : UtValueTestCaseChecker( - testClass = LoggerExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class LoggerExampleTest : UtValueTestCaseChecker(testClass = LoggerExample::class) { @Test fun testExample() { checkMocksAndInstrumentation( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/models/ModelsIdEqualityChecker.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/models/ModelsIdEqualityChecker.kt index 45a9bad8c7..ced67f698b 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/models/ModelsIdEqualityChecker.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/models/ModelsIdEqualityChecker.kt @@ -1,7 +1,6 @@ package org.utbot.examples.models import org.utbot.tests.infrastructure.UtModelTestCaseChecker -import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtDirectSetFieldModel @@ -9,17 +8,8 @@ import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtReferenceModel import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq -import org.utbot.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation SAT-1332 -internal class ModelsIdEqualityChecker : UtModelTestCaseChecker( - testClass = ModelsIdEqualityExample::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class ModelsIdEqualityChecker : UtModelTestCaseChecker(testClass = ModelsIdEqualityExample::class) { @Test fun testObjectItself() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/ClassWithClassRefTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/ClassWithClassRefTest.kt index 474293cf44..49c33654fc 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/ClassWithClassRefTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/ClassWithClassRefTest.kt @@ -10,7 +10,7 @@ import org.utbot.testcheckers.withoutConcrete import org.utbot.tests.infrastructure.CodeGeneration import org.utbot.tests.infrastructure.Compilation -// TODO Kotlin compilation SAT-1332 +// TODO Kotlin compilation because of engine problems with analyzing Class> #281 // Code generation executions fail due we cannot analyze strings properly for now internal class ClassWithClassRefTest : UtValueTestCaseChecker( testClass = ClassWithClassRef::class, diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt index 94b4337230..76db798cb0 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/strings/StringExamplesTest.kt @@ -7,7 +7,6 @@ import org.utbot.tests.infrastructure.between import org.utbot.tests.infrastructure.ignoreExecutionsNumber import org.utbot.tests.infrastructure.isException import org.utbot.tests.infrastructure.keyMatch -import org.utbot.framework.plugin.api.CodegenLanguage import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq @@ -15,16 +14,8 @@ import org.utbot.testcheckers.ge import org.utbot.testcheckers.withPushingStateFromPathSelectorForConcrete import org.utbot.testcheckers.withSolverTimeoutInMillis import org.utbot.testcheckers.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration - -internal class StringExamplesTest : UtValueTestCaseChecker( - testClass = StringExamples::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { + +internal class StringExamplesTest : UtValueTestCaseChecker(testClass = StringExamples::class) { @Test @Disabled("Flaky test: https://github.com/UnitTestBot/UTBotJava/issues/131 (will be enabled in new strings PR)") fun testByteToString() { diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/CharacterWrapperTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/CharacterWrapperTest.kt index e9f4bb5f3a..afe0dbf514 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/CharacterWrapperTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/CharacterWrapperTest.kt @@ -2,21 +2,11 @@ package org.utbot.examples.wrappers import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate -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.tests.infrastructure.CodeGeneration -// TODO failed Kotlin compilation -internal class CharacterWrapperTest : UtValueTestCaseChecker( - testClass = CharacterWrapper::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class CharacterWrapperTest : UtValueTestCaseChecker(testClass = CharacterWrapper::class) { @Test fun primitiveToWrapperTest() { check( diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/LongWrapperTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/LongWrapperTest.kt index 51b4de5557..856d48753a 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/LongWrapperTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/wrappers/LongWrapperTest.kt @@ -2,21 +2,12 @@ package org.utbot.examples.wrappers import org.utbot.tests.infrastructure.UtValueTestCaseChecker import org.utbot.tests.infrastructure.DoNotCalculate -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.withoutMinimization -import org.utbot.tests.infrastructure.CodeGeneration -internal class LongWrapperTest : UtValueTestCaseChecker( - testClass = LongWrapper::class, - testCodeGeneration = true, - languagePipelines = listOf( - CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), - CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration) - ) -) { +internal class LongWrapperTest : UtValueTestCaseChecker(testClass = LongWrapper::class) { @Test fun primitiveToWrapperTest() { check( 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 2a6e3e0139..c0cad4b5bd 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -62,12 +62,10 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConcreteExecutionFailureException import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.Instruction -import org.utbot.framework.plugin.api.MissingState import org.utbot.framework.plugin.api.Step import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtConcreteExecutionFailure import org.utbot.framework.plugin.api.UtError -import org.utbot.framework.plugin.api.UtExecution import org.utbot.framework.plugin.api.UtFailedExecution import org.utbot.framework.plugin.api.UtInstrumentation import org.utbot.framework.plugin.api.UtMethod @@ -154,7 +152,8 @@ private fun pathSelector(graph: InterProceduralUnitGraph, typeRegistry: TypeRegi class UtBotSymbolicEngine( private val controller: EngineController, - private val methodUnderTest: UtMethod<*>, + /** methodUnderTest is internal to use in [org.utbot.framework.plugin.api.processGenerics]. **/ + internal val methodUnderTest: UtMethod<*>, classpath: String, dependencyPaths: String, mockStrategy: MockStrategy = NO_MOCKS, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt index 2e8fe3d200..2824d503a0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt @@ -37,19 +37,26 @@ data class TestClassFile(val packageName: String, val imports: List, val sealed class Import(internal val order: Int) : Comparable { abstract val qualifiedName: String + abstract val classId: ClassId override fun compareTo(other: Import) = importComparator.compare(this, other) } private val importComparator = compareBy { it.order }.thenBy { it.qualifiedName } -data class StaticImport(val qualifierClass: String, val memberName: String) : Import(1) { - override val qualifiedName: String = "$qualifierClass.$memberName" +data class StaticImport(val methodId: MethodId) : Import(1) { + override val qualifiedName: String = "${methodId.classId.canonicalName}.${methodId.name}" + override val classId: ClassId + get() = methodId.classId } -data class RegularImport(val packageName: String, val className: String) : Import(2) { - override val qualifiedName: String - get() = if (packageName.isNotEmpty()) "$packageName.$className" else className +data class RegularImport(override val classId: ClassId) : Import(2) { + override val qualifiedName: String = + if (classId.packageName.isNotEmpty()) { + "${classId.packageName}.${classId.simpleNameWithEnclosings}" + } else { + classId.simpleNameWithEnclosings + } // TODO: check without equals() and hashCode() override fun equals(other: Any?): Boolean { @@ -58,15 +65,14 @@ data class RegularImport(val packageName: String, val className: String) : Impor other as RegularImport - if (packageName != other.packageName) return false - if (className != other.className) return false + if (classId != other.classId) return false return true } override fun hashCode(): Int { - var result = packageName.hashCode() - result = 31 * result + className.hashCode() + var result = classId.hashCode() + result = 31 * result + qualifiedName.hashCode() return result } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/name/CgNameGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/name/CgNameGenerator.kt index 50254afc03..75fc267ce0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/name/CgNameGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/name/CgNameGenerator.kt @@ -148,8 +148,9 @@ internal class CgNameGeneratorImpl(private val context: CgContext) private fun createNameFromKeyword(baseName: String): String = when(codegenLanguage) { CodegenLanguage.JAVA -> nextIndexedVarName(baseName) CodegenLanguage.KOTLIN -> { + val backticksBaseName = "`$baseName`" // use backticks for first variable with keyword name and use indexed names for all next such variables - if (baseName !in existingVariableNames) "`$baseName`" else nextIndexedVarName(baseName) + if (backticksBaseName !in existingVariableNames) backticksBaseName else nextIndexedVarName(baseName) } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt index b70fd7af1d..bc4f4f939e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt @@ -87,8 +87,9 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA override operator fun ConstructorId.invoke(vararg args: Any?): CgExecutableCall { val resolvedArgs = args.resolve() val constructorCall = if (this canBeCalledWith resolvedArgs) { - CgConstructorCall(this, resolvedArgs.guardedForDirectCallOf(this)) + CgConstructorCall(this, resolvedArgs.guardedForDirectCallOf(this), typeParameters) } else { + // TODO typeParameters? callWithReflection(resolvedArgs) } newConstructorCall(this) @@ -98,8 +99,9 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA override operator fun CgIncompleteMethodCall.invoke(vararg args: Any?): CgMethodCall { val resolvedArgs = args.resolve() val methodCall = if (method.canBeCalledWith(caller, resolvedArgs)) { - CgMethodCall(caller, method, resolvedArgs.guardedForDirectCallOf(method)) + CgMethodCall(caller, method, resolvedArgs.guardedForDirectCallOf(method), method.typeParameters) } else { + // TODO typeParams? method.callWithReflection(caller, resolvedArgs) } newMethodCall(method) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt index fee6dc125d..5823e308d4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt @@ -222,7 +222,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c // prevValue is nullable if not accessible because of getStaticFieldValue(..) : Any? val prevValue = newVar( - CgClassId(field.type, isNullable = !fieldAccessible), + CgClassId(field.fixedType, typeParameters = field.fixedType.typeParameters, isNullable = !fieldAccessible), "prev${field.name.capitalize()}" ) { if (fieldAccessible) { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt index d4059833b1..9f29f1b77c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt @@ -47,6 +47,7 @@ import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.WildcardTypeParameter +import org.utbot.framework.plugin.api.TypeParameters import org.utbot.framework.plugin.api.util.arrayLikeName import org.utbot.framework.plugin.api.util.builtinStaticMethodId import org.utbot.framework.plugin.api.util.methodId @@ -136,7 +137,7 @@ internal fun CgContextOwner.isUtil(method: MethodId): Boolean { return method in utilMethodProvider.utilMethodIds } -val classCgClassId = CgClassId(Class::class.id, typeParameters = WildcardTypeParameter(), isNullable = false) +val classCgClassId = CgClassId(Class::class.id, TypeParameters(listOf(WildcardTypeParameter)), isNullable = false) /** * A [MethodId] to add an item into [ArrayList]. @@ -248,7 +249,7 @@ internal fun CgContextOwner.importIfNeeded(method: MethodId) { .takeIf { currentExecutable != method } ?.let { importedStaticMethods += method - collectedImports += StaticImport(method.classId.canonicalName, method.name) + collectedImports += StaticImport(method) } } @@ -407,7 +408,7 @@ internal fun ClassId.utilMethodId( ): MethodId = BuiltinMethodId(this, name, returnType, arguments.toList(), isStatic = isStatic) -fun ClassId.toImport(): RegularImport = RegularImport(packageName, simpleNameWithEnclosings) +fun ClassId.toImport(): RegularImport = RegularImport(this) // Immutable collections utils diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt index 38d5633020..ac4d56dd98 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgAbstractRenderer.kt @@ -731,6 +731,8 @@ internal abstract class CgAbstractRenderer( override fun toString(): String = printer.toString() + // Reorder imports to keep alphabetic and logical order if their names are post-processed by renderer + protected abstract fun reorderImports(imports: List): List protected abstract fun renderRegularImport(regularImport: RegularImport) protected abstract fun renderStaticImport(staticImport: StaticImport) @@ -757,8 +759,8 @@ internal abstract class CgAbstractRenderer( protected abstract fun renderExceptionCatchVariable(exception: CgVariable) - protected fun getEscapedImportRendering(import: Import): String = - import.qualifiedName + protected fun getEscapedImportRendering(importName: String): String = + importName .split(".") .joinToString(".") { it.escapeNamePossibleKeyword() } @@ -848,8 +850,8 @@ internal abstract class CgAbstractRenderer( } private fun renderClassFileImports(element: AbstractCgClassFile<*>) { - val regularImports = element.imports.filterIsInstance() - val staticImports = element.imports.filterIsInstance() + val regularImports = reorderImports(element.imports.filterIsInstance()) + val staticImports = reorderImports(element.imports.filterIsInstance()) for (import in regularImports) { renderRegularImport(import) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgJavaRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgJavaRenderer.kt index 88bbba9ffa..6e1fb0c643 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgJavaRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgJavaRenderer.kt @@ -1,6 +1,7 @@ package org.utbot.framework.codegen.model.visitor import org.apache.commons.text.StringEscapeUtils +import org.utbot.framework.codegen.Import import org.utbot.framework.codegen.RegularImport import org.utbot.framework.codegen.StaticImport import org.utbot.framework.codegen.model.tree.AbstractCgClass @@ -214,13 +215,15 @@ internal class CgJavaRenderer(context: CgRendererContext, printer: CgPrinter = C renderExecutableCallArguments(element) } + override fun reorderImports(imports: List): List = imports + override fun renderRegularImport(regularImport: RegularImport) { - val escapedImport = getEscapedImportRendering(regularImport) + val escapedImport = getEscapedImportRendering(regularImport.qualifiedName) println("import $escapedImport$statementEnding") } override fun renderStaticImport(staticImport: StaticImport) { - val escapedImport = getEscapedImportRendering(staticImport) + val escapedImport = getEscapedImportRendering(staticImport.qualifiedName) println("import static $escapedImport$statementEnding") } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgKotlinRenderer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgKotlinRenderer.kt index 1e5a107218..de25fc14cf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgKotlinRenderer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgKotlinRenderer.kt @@ -3,6 +3,7 @@ package org.utbot.framework.codegen.model.visitor import org.apache.commons.text.StringEscapeUtils import org.utbot.common.WorkaroundReason import org.utbot.common.workaround +import org.utbot.framework.codegen.Import import org.utbot.framework.codegen.RegularImport import org.utbot.framework.codegen.StaticImport import org.utbot.framework.codegen.isLanguageKeyword @@ -55,6 +56,7 @@ import org.utbot.framework.plugin.api.util.isPrimitive import org.utbot.framework.plugin.api.util.isPrimitiveWrapper import org.utbot.framework.plugin.api.util.kClass import org.utbot.framework.plugin.api.util.voidClassId +import kotlin.reflect.KClass //TODO rewrite using KtPsiFactory? internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = CgPrinterImpl()) : CgAbstractRenderer(context, printer) { @@ -246,7 +248,6 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = if (element.isSafetyCast) print(" as? ") else print(" as ") print(getKotlinClassString(element.targetType)) - renderTypeParameters(element.targetType.typeParameters) val initNullable = element.type.isNullable if (element.targetType.isNullable || initNullable) print("?") } @@ -259,13 +260,13 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = override fun visit(element: CgGetJavaClass) { // TODO: check how it works on ref types, primitives, ref arrays, primitive arrays, etc. - print(getKotlinClassString(element.classId)) + print(getKotlinClassString(element.classId, false)) print("::class.java") } override fun visit(element: CgGetKotlinClass) { // TODO: check how it works on ref types, primitives, ref arrays, primitive arrays, etc. - print(getKotlinClassString(element.classId)) + print(getKotlinClassString(element.classId, false)) print("::class") } @@ -313,19 +314,27 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = } override fun visit(element: CgConstructorCall) { - print(getKotlinClassString(element.executableId.classId)) + print(getKotlinClassString(element.executableId.classId, false)) + renderTypeParameters(element.executableId.typeParameters) print("(") element.arguments.renderSeparated() print(")") } + private fun builtInNameOrNull(classId: ClassId): String? = kotlinBuiltins[classId]?.qualifiedName + + private fun Import.kotlinName() = builtInNameOrNull(classId) ?: qualifiedName + + override fun reorderImports(imports: List): List { + return imports.sortedBy { it.kotlinName() } + } override fun renderRegularImport(regularImport: RegularImport) { - val escapedImport = getEscapedImportRendering(regularImport) + val escapedImport = getEscapedImportRendering(regularImport.kotlinName()) println("import $escapedImport$statementEnding") } override fun renderStaticImport(staticImport: StaticImport) { - val escapedImport = getEscapedImportRendering(staticImport) + val escapedImport = getEscapedImportRendering(staticImport.kotlinName()) println("import $escapedImport$statementEnding") } @@ -385,7 +394,6 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = // TODO consider moving to getKotlinClassString print(": ") print(getKotlinClassString(element.variableType)) - renderTypeParameters(element.variableType.typeParameters) val initNullable = element.initializer?.run { type.isNullable } ?: false if (element.variableType.isNullable || initNullable) print("?") } @@ -475,7 +483,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = } override fun renderExceptionCatchVariable(exception: CgVariable) { - print("${exception.name.escapeNamePossibleKeyword()}: ${exception.type.kClass.simpleName}") + print("${exception.name.escapeNamePossibleKeyword()}: ${exception.type.kClass.qualifiedName}") } override fun isAccessibleBySimpleNameImpl(classId: ClassId): Boolean { @@ -502,29 +510,60 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = } } - private fun getKotlinClassString(id: ClassId): String = + private val kotlinBuiltins: Map> = mapOf( + Pair(java.util.List::class.id, List::class), + Pair(java.util.Set::class.id, Set::class), + Pair(java.util.Map::class.id, Map::class), + Pair(java.util.Collection::class.id, Collection::class), + Pair(java.lang.Iterable::class.id, Iterable::class), + ) + + private fun getKotlinClassString(id: ClassId, printTypeParameters: Boolean = true, depth: Int = 0): String { + if (id is WildcardTypeParameter) return "*" if (id.isArray) { - getKotlinArrayClassOfString(id) - } else { + return getKotlinArrayClassOfString(id) + } + val classString = when (id.jvmName) { - "Ljava/lang/Object;" -> Any::class.simpleName!! - "B", "Ljava/lang/Byte;" -> Byte::class.simpleName!! - "S", "Ljava/lang/Short;" -> Short::class.simpleName!! - "C", "Ljava/lang/Character;" -> Char::class.simpleName!! - "I", "Ljava/lang/Integer;" -> Int::class.simpleName!! - "J", "Ljava/lang/Long;" -> Long::class.simpleName!! - "F", "Ljava/lang/Float;" -> Float::class.simpleName!! - "D", "Ljava/lang/Double;" -> Double::class.simpleName!! - "Z", "Ljava/lang/Boolean;" -> Boolean::class.simpleName!! - "Ljava/lang/CharSequence;" -> CharSequence::class.simpleName!! - "Ljava/lang/String;" -> String::class.simpleName!! + // TODO some kotlin names might be wrong + "Ljava/lang/Object;", "Lkotlin/Any;" -> Any::class.simpleName!! + "B", "Ljava/lang/Byte;", "Lkotlin/Byte;" -> Byte::class.simpleName!! + "S", "Ljava/lang/Short;", "Lkotlin/Short;" -> Short::class.simpleName!! + "C", "Ljava/lang/Character;", "Lkotlin/Char;" -> Char::class.simpleName!! + "I", "Ljava/lang/Integer;", "Lkotlin/Int;" -> Int::class.simpleName!! + "J", "Ljava/lang/Long;", "Lkotlin/Long;" -> Long::class.simpleName!! + "F", "Ljava/lang/Float;", "Lkotlin/Float;" -> Float::class.simpleName!! + "D", "Ljava/lang/Double;", "Lkotlin/Double;" -> Double::class.simpleName!! + "Z", "Ljava/lang/Boolean;", "Lkotlin/Boolean;" -> Boolean::class.simpleName!! + "Ljava/lang/CharSequence;", "Lkotlin/CharSequence;" -> CharSequence::class.simpleName!! + "Ljava/lang/Number;", "Lkotlin/Number;" -> Number::class.simpleName!! + "Ljava/lang/String;", "Lkotlin/String;" -> String::class.simpleName!! else -> { // we cannot access kClass for BuiltinClassId // we cannot use simple name here because this class can be not imported - if (id is BuiltinClassId) id.name else id.kClass.id.asString() + buildString { + append(builtInNameOrNull(id) ?: if (id is BuiltinClassId) id.name else id.kClass.id.asString()) + if (printTypeParameters) { + if (id.typeParameters.parameters.isNotEmpty()) { + append( + "<" + + id.typeParameters.parameters.joinToString(separator = ",") + { getKotlinClassString(it, depth = depth + 1) } + + ">" + ) + } + } + } } } + + // for now all kotlin generic types are nullable + return if (depth > 0) { + "$classString?" + } else { + classString } + } private fun getKotlinArrayClassOfString(classId: ClassId): String = if (!classId.elementClassId!!.isPrimitive) { @@ -555,11 +594,7 @@ internal class CgKotlinRenderer(context: CgRendererContext, printer: CgPrinter = override fun renderTypeParameters(typeParameters: TypeParameters) { if (typeParameters.parameters.isNotEmpty()) { print("<") - if (typeParameters is WildcardTypeParameter) { - print("*") - } else { - print(typeParameters.parameters.joinToString { getKotlinClassString(it)}) - } + print(typeParameters.parameters.joinToString { getKotlinClassString(it, depth = 1)}) print(">") } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/UtilMethods.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/UtilMethods.kt index 4634590e6e..e691138948 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/UtilMethods.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/UtilMethods.kt @@ -840,7 +840,7 @@ internal fun CgContextOwner.importUtilMethodDependencies(id: MethodId) { importIfNeeded(classId) } for (methodId in utilMethodProvider.staticImportsByUtilMethod(id)) { - collectedImports += StaticImport(methodId.classId.canonicalName, methodId.name) + collectedImports += StaticImport(methodId) } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt index d8e15a20b2..ed446a6c63 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt @@ -38,7 +38,7 @@ internal sealed class OptionalConstructorBase : UtAssembleModelConstructorBase() "Can't cast $valueToConstructFrom to ${classId.jClass} in $this assemble constructor." } - modificationChain += if (!isPresent.call(valueToConstructFrom)) { + instantiationChain += if (!isPresent.call(valueToConstructFrom)) { UtExecutableCallModel( instance = null, emptyMethodId, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/GenericsProcessing.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/GenericsProcessing.kt new file mode 100644 index 0000000000..95969c83c8 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/GenericsProcessing.kt @@ -0,0 +1,315 @@ +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") +package org.utbot.framework.plugin.api + +import org.utbot.common.WorkaroundReason +import org.utbot.common.heuristic +import org.utbot.common.unreachableBranch +import org.utbot.common.withAccessibility +import org.utbot.framework.plugin.api.util.executable +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.isSubtypeOf +import org.utbot.framework.plugin.api.util.kClass +import org.utbot.framework.plugin.api.util.objectClassId +import sun.reflect.generics.parser.SignatureParser +import sun.reflect.generics.tree.ArrayTypeSignature +import sun.reflect.generics.tree.ClassTypeSignature +import sun.reflect.generics.tree.SimpleClassTypeSignature +import sun.reflect.generics.tree.TypeArgument +import sun.reflect.generics.tree.TypeTree +import sun.reflect.generics.tree.TypeVariableSignature +import java.lang.reflect.Constructor +import java.lang.reflect.GenericSignatureFormatError +import java.lang.reflect.Method +import kotlin.reflect.KCallable +import kotlin.reflect.KType +import kotlin.reflect.full.instanceParameter +import kotlin.reflect.jvm.kotlinFunction + + +fun processGenerics(result: UtResult, callable: KCallable<*>): UtResult { + return when (result) { + is UtExecution -> { + result.copy( + processGenericsForEnvironmentModels(result.stateBefore, callable), + processGenericsForEnvironmentModels(result.stateAfter, callable), + (result.result as? UtExecutionSuccess)?.let { execRes -> + UtExecutionSuccess( + processGenericsForModel(execRes.model, callable.returnType) + ) + } ?: result.result, + ) + } + else -> result + } +} + +fun processGenericsForEnvironmentModels(models: EnvironmentModels, callable: KCallable<*>): EnvironmentModels { + if (models is MissingState) return models + + // If MUT is static, no instance parameter is used + val paramOffset = if (callable.instanceParameter != null) 1 else 0 + + require(models.parameters.size + paramOffset == callable.parameters.size) + + val newParameters = emptyList().toMutableList() + for (i in models.parameters.indices) { + newParameters += processGenericsForModel(models.parameters[i], (callable.parameters[i + paramOffset].type)) + } + + val newStatics = emptyMap().toMutableMap() + // set Any? for all statics + for ((field, model) in models.statics) { + val newModel = fillGenericsAsObjectsForModel(model) + + val newFixedType = field.fixedType.copy( + typeParameters = TypeParameters(List(field.fixedType.kClass.typeParameters.size) { WildcardTypeParameter }) + ) + + val newFieldId = field.copy( + hiddenFixedType = newFixedType + ) + + newStatics[newFieldId] = newModel + } + + return EnvironmentModels( + models.thisInstance, + newParameters, + newStatics, + ) +} + +fun processGenericsForModel(model: UtModel, type: KType): UtModel = + when (model) { + is UtAssembleModel -> model.processGenerics(type) + is UtCompositeModel -> model.processGenerics(type) + else -> model + } + +fun fillGenericsAsObjectsForModel(model: UtModel): UtModel = + when (model) { + is UtAssembleModel -> model.fillGenericsAsObjects() + else -> model + } + +fun UtAssembleModel.processGenerics(type: KType): UtAssembleModel { + val newClassId = classId.copyTypeParametersFromKType(type) + + val newInstantiationChain = instantiationChain.toMutableList() + + // TODO might cause problems with type params when program synthesis comes + // assume that last statement is constructor call + instantiationChain.lastOrNull()?.let inst@ { lastStatement -> + (lastStatement as? UtExecutableCallModel)?.let { executableModel -> + val newExecutableId = when (val executable = executableModel.executable) { + is ConstructorId -> executable.copy( + typeParameters = newClassId.typeParameters + ) + is MethodId -> executable.copy( + typeParameters = newClassId.typeParameters + ) + } + + val newParams = try { + val function = when (val executable = executableModel.executable.executable) { + is Constructor<*> -> executable.kotlinFunction + is Method -> executable.kotlinFunction + else -> unreachableBranch("this executable does not exist $executable") + } + + executableModel.params.mapIndexed { i, param -> + function?.parameters?.getOrNull(i)?.type?.let { it -> processGenericsForModel(param, it) } + ?: param + } + } catch (e: Error) { + // KotlinReflectionInternalError can't be imported, but it is assumed here + // it can be thrown here because, i.e., Int(Int) constructor does not exist in Kotlin + executableModel.params + }.toMutableList() + + heuristic(WorkaroundReason.COLLECTION_CONSTRUCTOR_FROM_COLLECTION) { + val propagateFromReturnTypeToParameter = { id: Int -> + (newParams[id] as? UtAssembleModel)?.let { model -> + val newParamInstantiationChain = (model.instantiationChain.getOrNull(0) as? UtExecutableCallModel)?.run { + listOf( + copy( + executable = executable.copy( + typeParameters = newClassId.typeParameters + ) + ) + ) + } ?: model.instantiationChain + + newParams[id] = model.copy( + instantiationChain = newParamInstantiationChain + ) + } + } + + when (val executable = executableModel.executable.executable) { + is Constructor<*> -> { + // Can't parse signature here, since constructors return void + // This part only works for cases like Collection(collection: Collection) + if (executableModel.executable is ConstructorId) { + if (executableModel.executable.classId.isSubtypeOf(Collection::class.id)) { + if (executableModel.executable.parameters.size == 1 && + executableModel.executable.parameters[0].isSubtypeOf(Collection::class.id)) { + propagateFromReturnTypeToParameter(0) + } + } + } + } + is Method -> { + try { + val f = Method::class.java.getDeclaredField("signature") + val signature = f.withAccessibility { + f.get(executable) as? String ?: return@inst + } + val parsedSignature = SignatureParser.make().parseMethodSig(signature) + + // check if parameter types are equal to return types + // e.g. (Ljava/util/List;)Ljava/util/List; + parsedSignature.parameterTypes.forEachIndexed { paramId, param -> + parsedSignature.returnType as? TypeArgument ?: error("Only TypeArgument is expected") + if (param.cmp(parsedSignature.returnType)) { + propagateFromReturnTypeToParameter(paramId) + } + } + } catch (e: GenericSignatureFormatError) { + // TODO log + } + } + else -> unreachableBranch("this executable does not exist $executable") + } + } + + newInstantiationChain[0] = executableModel.copy( + executable = newExecutableId, + params = newParams, + ) + } + } + + val newModificationsChain = emptyList().toMutableList() + + for (model in modificationsChain) { + if (model is UtExecutableCallModel) { + heuristic(WorkaroundReason.MODIFICATION_CHAIN_GENERICS_FROM_CLASS) { + newModificationsChain += model.copy( + params = model.params.mapIndexed { i, param -> + type.arguments.getOrNull(i)?.type?.let { it -> processGenericsForModel(param, it) } + ?: param + } + ) + } + } else { + newModificationsChain += model + } + } + + return copy( + classId = newClassId, + instantiationChain = newInstantiationChain, + modificationsChain = newModificationsChain, + ) +} + +fun UtAssembleModel.fillGenericsAsObjects(): UtAssembleModel { + var newClassId = classId + + val newInstantiationChain = instantiationChain.toMutableList() + + // TODO might cause problems with type params when program synthesis comes + // assume that last statement is constructor call + instantiationChain.lastOrNull()?.let { lastStatement -> + (lastStatement as? UtExecutableCallModel)?.let { executableModel -> + try { + val function = when (val executable = executableModel.executable.executable) { + is Constructor<*> -> executable.kotlinFunction + is Method -> executable.kotlinFunction + else -> unreachableBranch("this executable does not exist $executable") + } + function?.let { f -> + newClassId = newClassId.copy( + typeParameters = TypeParameters(List(f.typeParameters.size) { objectClassId }) + ) + } + + val newParams = executableModel.params.map { param -> fillGenericsAsObjectsForModel(param) } + + newInstantiationChain[0] = executableModel.copy( + params = newParams, + ) + } catch (e: Error) { + // KotlinReflectionInternalError can't be imported, but it is assumed here + // it can be thrown here because, i.e., Int(Int) constructor does not exist in Kotlin + } + } + } + + val newModificationsChain = emptyList().toMutableList() + + for (model in modificationsChain) { + if (model is UtExecutableCallModel) { + val function = when (val executable = model.executable.executable) { + is Constructor<*> -> executable.kotlinFunction + is Method -> executable.kotlinFunction + else -> unreachableBranch("this executable does not exist $executable") + } + + val newExecutableId = function?.let { f -> + model.executable.copy( + classId = model.executable.classId.copy( + typeParameters = TypeParameters(List(f.typeParameters.size) { objectClassId }) + ) + ) + } ?: model.executable + + val newParams = model.params.map { param -> fillGenericsAsObjectsForModel(param) } + + newModificationsChain += model.copy( + executable = newExecutableId, + params = newParams + ) + } else { + newModificationsChain += model + } + } + + return copy( + classId = newClassId, + instantiationChain = newInstantiationChain, + modificationsChain = newModificationsChain, + ) +} + +fun UtCompositeModel.processGenerics(type: KType): UtCompositeModel { + return copy( + classId = classId.copyTypeParametersFromKType(type) + ) + + // TODO propagate generics into fields and mocks if required +} + +private fun TypeTree.cmp(other: TypeTree): Boolean { + if (this::class != other::class) return false + + when (this) { + is TypeVariableSignature -> return identifier == (other as TypeVariableSignature).identifier + is ClassTypeSignature -> { + val otherPath = (other as ClassTypeSignature).path + return path.foldIndexed(true) { i, prev, it -> + prev && (otherPath.getOrNull(i)?.cmp(it) ?: false) + } + } + is SimpleClassTypeSignature -> { + val otherTypeArgs = (other as SimpleClassTypeSignature).typeArguments + return typeArguments.foldIndexed(true) { i, prev, it -> + prev && (otherTypeArgs.getOrNull(i)?.cmp(it) ?: false) + } + } + is ArrayTypeSignature -> return componentType.cmp((other as ArrayTypeSignature).componentType) + // other cases are trivial and handled by class comparison + else -> return true + } +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestFlow.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestFlow.kt index 2407407acd..b1555e9612 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestFlow.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestFlow.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flattenConcat import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import org.utbot.engine.UtBotSymbolicEngine import org.utbot.framework.UtSettings @@ -71,6 +72,6 @@ class TestFlow internal constructor(block: TestFlow.() -> Unit) { } isSymbolicEngineEnabled -> engine.traverse() else -> emptyFlow() - } + }.map { processGenerics(it, engine.methodUnderTest.callable) } } } \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt index 211ec0fcfb..75a19eef9c 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt @@ -55,4 +55,26 @@ class UtFuzzedExecution( append(result) append(")") } + + override fun copy( + stateBefore: EnvironmentModels, + stateAfter: EnvironmentModels, + result: UtExecutionResult, + coverage: Coverage?, + summary: List?, + testMethodName: String?, + displayName: String?, + ): UtFuzzedExecution { + return UtFuzzedExecution( + stateBefore, + stateAfter, + result, + coverage, + summary, + testMethodName, + displayName, + fuzzingValues, + fuzzedMethodDescription, + ) + } } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt index 8d3eac68bd..09fe701700 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt @@ -846,7 +846,7 @@ object CodeGenerationController { FqName(import.qualifiedName) ) } else { - ImportUtils.addStaticImport(import.qualifierClass, import.memberName, testClass) + ImportUtils.addStaticImport(import.methodId.classId.canonicalName, import.methodId.name, testClass) } } is RegularImport -> { }