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 879dfc1037..11c0cf26cb 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 @@ -31,6 +31,7 @@ import org.utbot.framework.plugin.api.util.method import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull import org.utbot.framework.plugin.api.util.safeJField import org.utbot.framework.plugin.api.util.shortClassId +import org.utbot.framework.plugin.api.util.supertypeOfAnonymousClass import org.utbot.framework.plugin.api.util.toReferenceTypeBytecodeSignature import org.utbot.framework.plugin.api.util.voidClassId import soot.ArrayType @@ -679,8 +680,14 @@ open class ClassId @JvmOverloads constructor( */ val prettifiedName: String get() { - val className = jClass.canonicalName ?: name // Explicit jClass reference to get null instead of exception - return className + val baseName = when { + // anonymous classes have empty simpleName and their canonicalName is null, + // so we create a specific name for them + isAnonymous -> "Anonymous${supertypeOfAnonymousClass.prettifiedName}" + // in other cases where canonical name is still null, we use ClassId.name instead + else -> jClass.canonicalName ?: name // Explicit jClass reference to get null instead of exception + } + return baseName .substringAfterLast(".") .replace(Regex("[^a-zA-Z0-9]"), "") .let { if (this.isArray) it + "Array" else it } diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt index b7ac0130b8..45e52fad96 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt @@ -31,6 +31,28 @@ import kotlin.reflect.jvm.javaMethod // ClassId utils +/** + * A type is called **non-denotable** if its name cannot be used in the source code. + * For example, anonymous classes **are** non-denotable types. + * On the other hand, [java.lang.Integer], for example, **is** denotable. + * + * This property returns the same type for denotable types, + * and it returns the supertype when given an anonymous class. + * + * **NOTE** that in Java there are non-denotable types other than anonymous classes. + * For example, null-type, intersection types, capture types. + * But [ClassId] cannot contain any of these (at least at the moment). + * So we only consider the case of anonymous classes. + */ +val ClassId.denotableType: ClassId + get() { + return when { + this.isAnonymous -> this.supertypeOfAnonymousClass + else -> this + } + } + + @Suppress("unused") val ClassId.enclosingClass: ClassId? get() = jClass.enclosingClass?.id @@ -111,6 +133,37 @@ infix fun ClassId.isSubtypeOf(type: ClassId): Boolean { infix fun ClassId.isNotSubtypeOf(type: ClassId): Boolean = !(this isSubtypeOf type) +/** + * - Anonymous class that extends a class will have this class as its superclass and no interfaces. + * - Anonymous class that implements an interface, will have the only interface + * and [java.lang.Object] as its superclass. + * + * @return [ClassId] of a type that the given anonymous class inherits + */ +val ClassId.supertypeOfAnonymousClass: ClassId + get() { + if (this is BuiltinClassId) error("Cannot obtain info about supertypes of BuiltinClassId $canonicalName") + require(isAnonymous) { "An anonymous class expected, but got $canonicalName" } + + val clazz = jClass + val superclass = clazz.superclass.id + val interfaces = clazz.interfaces.map { it.id } + + return when (superclass) { + objectClassId -> { + // anonymous class actually inherits from Object, e.g. Object obj = new Object() { ... }; + if (interfaces.isEmpty()) { + objectClassId + } else { + // anonymous class implements some interface + interfaces.singleOrNull() ?: error("Anonymous class can have no more than one interface") + } + } + // anonymous class inherits from some class other than java.lang.Object + else -> superclass + } + } + val ClassId.kClass: KClass<*> get() = jClass.kotlin diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/AnonymousClassesExampleTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/AnonymousClassesExampleTest.kt index df8a29b463..11e152f510 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/AnonymousClassesExampleTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/examples/objects/AnonymousClassesExampleTest.kt @@ -1,7 +1,7 @@ package org.utbot.examples.objects +import org.utbot.tests.infrastructure.Full import org.utbot.tests.infrastructure.UtValueTestCaseChecker -import org.utbot.tests.infrastructure.DoNotCalculate import org.utbot.tests.infrastructure.isException import org.junit.jupiter.api.Test import org.utbot.testcheckers.eq @@ -11,19 +11,23 @@ class AnonymousClassesExampleTest : UtValueTestCaseChecker(testClass = Anonymous fun testAnonymousClassAsParam() { checkWithException( AnonymousClassesExample::anonymousClassAsParam, - eq(2), + eq(3), { abstractAnonymousClass, r -> abstractAnonymousClass == null && r.isException() }, { abstractAnonymousClass, r -> abstractAnonymousClass != null && r.getOrNull() == 0 }, - coverage = DoNotCalculate + { abstractAnonymousClass, r -> abstractAnonymousClass != null && abstractAnonymousClass::class.java.isAnonymousClass && r.getOrNull() == 42 }, + coverage = Full ) } @Test fun testNonFinalAnonymousStatic() { - check( + checkStaticsAndException( AnonymousClassesExample::nonFinalAnonymousStatic, - eq(0), // we remove all anonymous classes in statics - coverage = DoNotCalculate + eq(3), + { statics, r -> statics.values.single().value == null && r.isException() }, + { _, r -> r.getOrNull() == 0 }, + { _, r -> r.getOrNull() == 42 }, + coverage = Full ) } @@ -31,8 +35,9 @@ class AnonymousClassesExampleTest : UtValueTestCaseChecker(testClass = Anonymous fun testAnonymousClassAsStatic() { check( AnonymousClassesExample::anonymousClassAsStatic, - eq(0), // we remove all anonymous classes in statics - coverage = DoNotCalculate + eq(1), + { r -> r == 42 }, + coverage = Full ) } @@ -40,8 +45,9 @@ class AnonymousClassesExampleTest : UtValueTestCaseChecker(testClass = Anonymous fun testAnonymousClassAsResult() { check( AnonymousClassesExample::anonymousClassAsResult, - eq(0), // we remove anonymous classes from the params and the result - coverage = DoNotCalculate + eq(1), + { abstractAnonymousClass -> abstractAnonymousClass != null && abstractAnonymousClass::class.java.isAnonymousClass }, + coverage = Full ) } } \ No newline at end of file diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt b/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt index 7ca5a772ea..0108faad44 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt @@ -58,6 +58,8 @@ import org.utbot.framework.util.SootUtils import org.utbot.framework.util.instanceCounter import org.utbot.framework.util.modelIdCounter import kotlin.reflect.full.functions +import org.utbot.examples.assemble.* +import org.utbot.framework.codegen.model.constructor.util.arrayTypeOf /** * Test classes must be located in the same folder as [AssembleTestUtils] class. @@ -1117,7 +1119,7 @@ class AssembleModelGeneratorTests { testClassId, "array" to UtArrayModel( modelIdCounter.incrementAndGet(), - ClassId("[L${innerClassId.canonicalName}", innerClassId), + arrayTypeOf(innerClassId), length = 3, UtNullModel(innerClassId), mutableMapOf( @@ -1187,11 +1189,11 @@ class AssembleModelGeneratorTests { val testClassId = ArrayOfComplexArrays::class.id val innerClassId = PrimitiveFields::class.id - val innerArrayClassId = ClassId("[L${innerClassId.canonicalName}", innerClassId) + val innerArrayClassId = arrayTypeOf(innerClassId) val arrayOfArraysModel = UtArrayModel( modelIdCounter.incrementAndGet(), - ClassId("[Lorg.utbot.examples.assemble.ComplexArray", testClassId), + arrayTypeOf(testClassId), length = 2, UtNullModel(innerArrayClassId), mutableMapOf( diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index 330d2b0894..8c9673c439 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -3405,9 +3405,18 @@ class Traverser( if (returnValue != null) { queuedSymbolicStateUpdates += constructConstraintForType(returnValue, returnValue.possibleConcreteTypes).asSoftConstraint() + // We only remove anonymous classes if there are regular classes available. + // If there are no other options, then we do use anonymous classes. workaround(REMOVE_ANONYMOUS_CLASSES) { val sootClass = returnValue.type.sootClass - if (!environment.state.isInNestedMethod() && (sootClass.isAnonymous || sootClass.isArtificialEntity)) { + val isInNestedMethod = environment.state.isInNestedMethod() + + if (!isInNestedMethod && sootClass.isArtificialEntity) { + return + } + + val onlyAnonymousTypesAvailable = returnValue.typeStorage.possibleConcreteTypes.all { (it as? RefType)?.sootClass?.isAnonymous == true } + if (!isInNestedMethod && sootClass.isAnonymous && !onlyAnonymousTypesAvailable) { return } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt index 323dd552e6..6b889a3969 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt @@ -1,7 +1,6 @@ package org.utbot.engine import org.utbot.common.WorkaroundReason -import org.utbot.common.heuristic import org.utbot.common.workaround import org.utbot.engine.pc.UtAddrExpression import org.utbot.engine.pc.UtBoolExpression @@ -187,11 +186,9 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy } /** - * Remove anonymous and artificial types from the [TypeStorage] if [TypeStorage.possibleConcreteTypes] - * contains non-anonymous and non-artificial types. - * However, if the typeStorage contains only artificial and anonymous types, it becomes much more complicated. - * If leastCommonType of the typeStorage is an artificialEntity, result will contain both artificial and anonymous - * types, otherwise only anonymous types. It is required for some classes, e.g., `forEach__145`. + * Where possible, remove types that are not currently supported by code generation. + * For example, we filter out artificial entities (lambdas are an example of them) + * if the least common type is **not** artificial itself. */ private fun TypeStorage.filterInappropriateClassesForCodeGeneration(): TypeStorage { val unwantedTypes = mutableSetOf() @@ -200,19 +197,17 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy val leastCommonSootClass = (leastCommonType as? RefType)?.sootClass val keepArtificialEntities = leastCommonSootClass?.isArtificialEntity == true - heuristic(WorkaroundReason.REMOVE_ANONYMOUS_CLASSES) { - possibleConcreteTypes.forEach { - val sootClass = (it.baseType as? RefType)?.sootClass ?: run { - // All not RefType should be included in the concreteTypes, e.g., arrays - concreteTypes += it - return@forEach - } - when { - sootClass.isAnonymous || sootClass.isUtMock -> unwantedTypes += it - sootClass.isArtificialEntity -> if (keepArtificialEntities) concreteTypes += it else Unit - workaround(WorkaroundReason.HACK) { leastCommonSootClass == OBJECT_TYPE && sootClass.isOverridden } -> Unit - else -> concreteTypes += it - } + possibleConcreteTypes.forEach { + val sootClass = (it.baseType as? RefType)?.sootClass ?: run { + // All not RefType should be included in the concreteTypes, e.g., arrays + concreteTypes += it + return@forEach + } + when { + sootClass.isUtMock -> unwantedTypes += it + sootClass.isArtificialEntity -> if (keepArtificialEntities) concreteTypes += it else Unit + workaround(WorkaroundReason.HACK) { leastCommonSootClass == OBJECT_TYPE && sootClass.isOverridden } -> Unit + else -> concreteTypes += it } } 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 d91c86b721..eda8fb3f4e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -4,10 +4,8 @@ import mu.KotlinLogging import org.utbot.analytics.EngineAnalyticsContext import org.utbot.analytics.FeatureProcessor import org.utbot.analytics.Predictors -import org.utbot.common.WorkaroundReason.REMOVE_ANONYMOUS_CLASSES import org.utbot.common.bracket import org.utbot.common.debug -import org.utbot.common.workaround import org.utbot.engine.MockStrategy.NO_MOCKS import org.utbot.engine.pc.UtArraySelectExpression import org.utbot.engine.pc.UtBoolExpression @@ -60,6 +58,8 @@ import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtOverflowFailure import org.utbot.framework.plugin.api.UtResult import org.utbot.framework.plugin.api.UtSymbolicExecution +import org.utbot.framework.util.graph +import org.utbot.framework.plugin.api.util.executableId import org.utbot.framework.plugin.api.util.isStatic import org.utbot.framework.plugin.api.onSuccess import org.utbot.framework.plugin.api.util.description @@ -469,15 +469,6 @@ class UtBotSymbolicEngine( // in case an exception occurred from the concrete execution concreteExecutionResult ?: return@forEach - workaround(REMOVE_ANONYMOUS_CLASSES) { - concreteExecutionResult.result.onSuccess { - if (it.classId.isAnonymous) { - logger.debug("Anonymous class found as a concrete result, symbolic one will be returned") - return@flow - } - } - } - val coveredInstructions = concreteExecutionResult.coverage.coveredInstructions if (coveredInstructions.isNotEmpty()) { val coverageKey = coveredInstructionTracker.add(coveredInstructions) @@ -586,16 +577,6 @@ class UtBotSymbolicEngine( instrumentation ) - workaround(REMOVE_ANONYMOUS_CLASSES) { - concreteExecutionResult.result.onSuccess { - if (it.classId.isAnonymous) { - logger.debug("Anonymous class found as a concrete result, symbolic one will be returned") - emit(symbolicUtExecution) - return - } - } - } - val concolicUtExecution = symbolicUtExecution.copy( stateAfter = concreteExecutionResult.stateAfter, result = concreteExecutionResult.result, diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt index 5bd0c06009..473a2aa1b8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt @@ -171,6 +171,11 @@ class AssembleModelGenerator(private val methodPackageName: String) { private fun assembleModel(utModel: UtModel): UtModel { val collectedCallChain = callChain.toMutableList() + // we cannot create an assemble model for an anonymous class instance + if (utModel.classId.isAnonymous) { + return utModel + } + val assembledModel = withCleanState { try { when (utModel) { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt index 9fcb084b38..8d216f98f6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt @@ -55,6 +55,7 @@ import org.utbot.framework.plugin.api.util.intClassId import org.utbot.framework.plugin.api.util.isArray import org.utbot.framework.plugin.api.util.isPrimitiveWrapperOrString import org.utbot.framework.plugin.api.util.stringClassId +import org.utbot.framework.plugin.api.util.supertypeOfAnonymousClass import org.utbot.framework.plugin.api.util.wrapperByPrimitive import java.lang.reflect.Field import java.lang.reflect.Modifier @@ -119,7 +120,9 @@ internal class CgVariableConstructor(val context: CgContext) : val obj = if (model.isMock) { mockFrameworkManager.createMockFor(model, baseName) } else { - newVar(model.classId, baseName) { utilsClassId[createInstance](model.classId.name) } + val modelType = model.classId + val variableType = if (modelType.isAnonymous) modelType.supertypeOfAnonymousClass else modelType + newVar(variableType, baseName) { utilsClassId[createInstance](model.classId.name) } } valueByModelId[model.id] = obj diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt index 5bdaabe09e..fcc21ff275 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt @@ -70,6 +70,7 @@ import org.utbot.framework.plugin.api.util.constructorClassId import org.utbot.framework.plugin.api.util.fieldClassId import org.utbot.framework.plugin.api.util.isPrimitive import org.utbot.framework.plugin.api.util.methodClassId +import org.utbot.framework.plugin.api.util.denotableType import java.lang.reflect.Constructor import java.lang.reflect.Method import kotlin.reflect.KFunction @@ -244,9 +245,12 @@ internal class CgStatementConstructorImpl(context: CgContext) : isMutable: Boolean, init: () -> CgExpression ): CgVariable { + // it is important that we use a denotable type for declaration, because that allows + // us to avoid creating `Object` variables for instances of anonymous classes, + // where we can instead use the supertype of the anonymous class val declarationOrVar: Either = createDeclarationForNewVarAndUpdateVariableScopeOrGetExistingVariable( - baseType, + baseType.denotableType, model, baseName, isMock, @@ -558,8 +562,8 @@ internal class CgStatementConstructorImpl(context: CgContext) : val isGetFieldUtilMethod = (expression is CgMethodCall && expression.executableId.isGetFieldUtilMethod) val shouldCastBeSafety = expression == nullLiteral() || isGetFieldUtilMethod - type = baseType expr = typeCast(baseType, expression, shouldCastBeSafety) + type = expr.type } expression.type isNotSubtypeOf baseType && !typeAccessible -> { type = if (expression.type.isArray) objectArrayClassId else objectClassId 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 1a512e571f..31f77c23e3 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 @@ -50,6 +50,7 @@ import org.utbot.framework.plugin.api.WildcardTypeParameter import org.utbot.framework.plugin.api.util.isStatic import org.utbot.framework.plugin.api.util.arrayLikeName import org.utbot.framework.plugin.api.util.builtinStaticMethodId +import org.utbot.framework.plugin.api.util.denotableType import org.utbot.framework.plugin.api.util.methodId import org.utbot.framework.plugin.api.util.objectArrayClassId import org.utbot.framework.plugin.api.util.objectClassId @@ -256,18 +257,24 @@ internal fun CgContextOwner.importIfNeeded(method: MethodId) { /** * Casts [expression] to [targetType]. * + * This method uses [denotableType] of the given [targetType] to ensure + * that we are using a denotable type in the type cast. + * + * Specifically, if we attempt to do a type cast to an anonymous class, + * then we will actually perform a type cast to its supertype. + * + * @see denotableType + * * @param isSafetyCast shows if we should render "as?" instead of "as" in Kotlin */ internal fun CgContextOwner.typeCast( targetType: ClassId, expression: CgExpression, isSafetyCast: Boolean = false -): CgTypeCast { - if (targetType.simpleName.isEmpty()) { - error("Cannot cast an expression to the anonymous type $targetType") - } - importIfNeeded(targetType) - return CgTypeCast(targetType, expression, isSafetyCast) +): CgExpression { + val denotableTargetType = targetType.denotableType + importIfNeeded(denotableTargetType) + return CgTypeCast(denotableTargetType, expression, isSafetyCast) } /** @@ -305,7 +312,7 @@ internal fun arrayInitializer(arrayType: ClassId, elementType: ClassId, values: * @param elementType the element type of the returned array class id * @param isNullable a flag whether returned array is nullable or not */ -internal fun arrayTypeOf(elementType: ClassId, isNullable: Boolean = false): ClassId { +fun arrayTypeOf(elementType: ClassId, isNullable: Boolean = false): ClassId { val arrayIdName = "[${elementType.arrayLikeName}" return when (elementType) { is BuiltinClassId -> BuiltinClassId( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/ClassIdUtil.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/ClassIdUtil.kt index 54bbbf53f1..13eab73607 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/ClassIdUtil.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/ClassIdUtil.kt @@ -14,8 +14,7 @@ import org.utbot.framework.plugin.api.util.isArray * @param packageName name of the package we check accessibility from */ infix fun ClassId.isAccessibleFrom(packageName: String): Boolean { - - if (this.isLocal || this.isSynthetic) { + if (this.isLocal || this.isAnonymous || this.isSynthetic) { return false } diff --git a/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/UtValueTestCaseChecker.kt b/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/UtValueTestCaseChecker.kt index 57054b20b8..c993a3aad0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/UtValueTestCaseChecker.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/UtValueTestCaseChecker.kt @@ -1134,6 +1134,102 @@ abstract class UtValueTestCaseChecker( summaryDisplayNameChecks = summaryDisplayNameChecks ) + // check arguments, statics and Result for exceptions check + protected inline fun checkStaticsAndException( + method: KFunction1<*, R>, + branches: ExecutionsNumberMatcher, + vararg matchers: (StaticsType, Result) -> Boolean, + coverage: CoverageMatcher = Full, + mockStrategy: MockStrategyApi = NO_MOCKS, + additionalDependencies: Array> = emptyArray(), + summaryTextChecks: List<(List?) -> Boolean> = listOf(), + summaryNameChecks: List<(String?) -> Boolean> = listOf(), + summaryDisplayNameChecks: List<(String?) -> Boolean> = listOf() + ) = internalCheck( + method, mockStrategy, branches, matchers, coverage, + arguments = ::withStaticsBeforeAndExceptions, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkStaticsAndException( + method: KFunction2<*, T, R>, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, StaticsType, Result) -> Boolean, + coverage: CoverageMatcher = Full, + mockStrategy: MockStrategyApi = NO_MOCKS, + additionalDependencies: Array> = emptyArray(), + summaryTextChecks: List<(List?) -> Boolean> = listOf(), + summaryNameChecks: List<(String?) -> Boolean> = listOf(), + summaryDisplayNameChecks: List<(String?) -> Boolean> = listOf() + ) = internalCheck( + method, mockStrategy, branches, matchers, coverage, T::class, + arguments = ::withStaticsBeforeAndExceptions, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkStaticsAndException( + method: KFunction3<*, T1, T2, R>, + branches: ExecutionsNumberMatcher, + vararg matchers: (T1, T2, StaticsType, Result) -> Boolean, + coverage: CoverageMatcher = Full, + mockStrategy: MockStrategyApi = NO_MOCKS, + additionalDependencies: Array> = emptyArray(), + summaryTextChecks: List<(List?) -> Boolean> = listOf(), + summaryNameChecks: List<(String?) -> Boolean> = listOf(), + summaryDisplayNameChecks: List<(String?) -> Boolean> = listOf() + ) = internalCheck( + method, mockStrategy, branches, matchers, coverage, T1::class, T2::class, + arguments = ::withStaticsBeforeAndExceptions, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkStaticsAndException( + method: KFunction4<*, T1, T2, T3, R>, + branches: ExecutionsNumberMatcher, + vararg matchers: (T1, T2, T3, StaticsType, Result) -> Boolean, + coverage: CoverageMatcher = Full, + mockStrategy: MockStrategyApi = NO_MOCKS, + additionalDependencies: Array> = emptyArray(), + summaryTextChecks: List<(List?) -> Boolean> = listOf(), + summaryNameChecks: List<(String?) -> Boolean> = listOf(), + summaryDisplayNameChecks: List<(String?) -> Boolean> = listOf() + ) = internalCheck( + method, mockStrategy, branches, matchers, coverage, T1::class, T2::class, T3::class, + arguments = ::withStaticsBeforeAndExceptions, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkStaticsAndException( + method: KFunction5<*, T1, T2, T3, T4, R>, + branches: ExecutionsNumberMatcher, + vararg matchers: (T1, T2, T3, T4, StaticsType, Result) -> Boolean, + coverage: CoverageMatcher = Full, + mockStrategy: MockStrategyApi = NO_MOCKS, + additionalDependencies: Array> = emptyArray(), + summaryTextChecks: List<(List?) -> Boolean> = listOf(), + summaryNameChecks: List<(String?) -> Boolean> = listOf(), + summaryDisplayNameChecks: List<(String?) -> Boolean> = listOf() + ) = internalCheck( + method, mockStrategy, branches, matchers, coverage, T1::class, T2::class, T3::class, T4::class, + arguments = ::withStaticsBeforeAndExceptions, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + protected inline fun checkStaticsAfter( method: KFunction1<*, R>, branches: ExecutionsNumberMatcher, @@ -2667,6 +2763,7 @@ class FullWithAssumptions(assumeCallsNumber: Int) : CoverageMatcher( fun withResult(ex: UtValueExecution<*>) = ex.paramsBefore + ex.evaluatedResult fun withException(ex: UtValueExecution<*>) = ex.paramsBefore + ex.returnValue fun withStaticsBefore(ex: UtValueExecution<*>) = ex.paramsBefore + ex.staticsBefore + ex.evaluatedResult +fun withStaticsBeforeAndExceptions(ex: UtValueExecution<*>) = ex.paramsBefore + ex.staticsBefore + ex.returnValue fun withStaticsAfter(ex: UtValueExecution<*>) = ex.paramsBefore + ex.staticsAfter + ex.evaluatedResult fun withThisAndStaticsAfter(ex: UtValueExecution<*>) = listOf(ex.callerBefore) + ex.paramsBefore + ex.staticsAfter + ex.evaluatedResult fun withThisAndResult(ex: UtValueExecution<*>) = listOf(ex.callerBefore) + ex.paramsBefore + ex.evaluatedResult diff --git a/utbot-sample/src/main/java/org/utbot/examples/objects/AnonymousClassesExample.java b/utbot-sample/src/main/java/org/utbot/examples/objects/AnonymousClassesExample.java index 36e705bc01..8128872408 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/objects/AnonymousClassesExample.java +++ b/utbot-sample/src/main/java/org/utbot/examples/objects/AnonymousClassesExample.java @@ -1,9 +1,9 @@ package org.utbot.examples.objects; public class AnonymousClassesExample { - private static final AbstractAnonymousClass staticAnonymousClass = AbstractAnonymousClass.getInstance(1); + static final AbstractAnonymousClass staticAnonymousClass = AbstractAnonymousClass.getInstance(1); @SuppressWarnings("FieldMayBeFinal") - private static AbstractAnonymousClass nonFinalAnonymousStatic = AbstractAnonymousClass.getInstance(1); + static AbstractAnonymousClass nonFinalAnonymousStatic = AbstractAnonymousClass.getInstance(1); public int anonymousClassAsParam(AbstractAnonymousClass abstractAnonymousClass) { return abstractAnonymousClass.constValue();