diff --git a/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt b/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt index 7c8572d0d5..1f6bb848a5 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt @@ -28,4 +28,4 @@ fun Method.invokeCatching(obj: Any?, args: List) = try { Result.success(invoke(obj, *args.toTypedArray())) } catch (e: InvocationTargetException) { Result.failure(e.targetException) -} \ No newline at end of file +} diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt index b97d534627..38ed305156 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt @@ -31,7 +31,7 @@ internal class SettingDelegate(val initializer: () -> T) { /** * Default concrete execution timeout (in milliseconds). */ -const val DEFAULT_CONCRETE_EXECUTION_TIMEOUT_IN_CHILD_PROCESS_MS = 100L +const val DEFAULT_CONCRETE_EXECUTION_TIMEOUT_IN_CHILD_PROCESS_MS = 1000L object UtSettings { private val properties = Properties().also { props -> diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt index a67d675cb0..4fca4b478d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt @@ -25,6 +25,7 @@ import org.utbot.engine.pc.mkLong import org.utbot.engine.pc.mkShort import org.utbot.engine.pc.select import org.utbot.engine.pc.store +import org.utbot.engine.util.statics.concrete.isEnumValuesFieldName import org.utbot.engine.symbolic.asHardConstraint import org.utbot.engine.z3.intValue import org.utbot.engine.z3.value @@ -82,6 +83,7 @@ import soot.PrimType import soot.RefType import soot.Scene import soot.ShortType +import soot.SootClass import soot.SootField import soot.Type import soot.VoidType @@ -1068,7 +1070,7 @@ fun UtBotSymbolicEngine.toMethodResult(value: Any?, sootType: Type): MethodResul arrayToMethodResult(value.size, elementType) { if (value[it] == null) return@arrayToMethodResult nullObjectAddr - val addr = UtAddrExpression(mkBVConst("staticVariable${value.hashCode()}", UtInt32Sort)) + val addr = UtAddrExpression(mkBVConst("staticVariable${value.hashCode()}_$it", UtInt32Sort)) val createdElement = if (elementType is RefType) { val className = value[it]!!.javaClass.id.name @@ -1141,6 +1143,30 @@ private fun UtBotSymbolicEngine.arrayToMethodResult( ) } +fun UtBotSymbolicEngine.constructEnumStaticFieldResult( + fieldName: String, + fieldType: Type, + declaringClass: SootClass, + enumConstantSymbolicResultsByName: Map, + staticFieldConcreteValue: Any?, + enumConstantSymbolicValues: List +): MethodResult = + if (isEnumValuesFieldName(fieldName)) { + // special case to fill $VALUES array with already created symbolic values for enum constants runtime values + arrayToMethodResult(enumConstantSymbolicValues.size, declaringClass.type) { i -> + enumConstantSymbolicValues[i].addr + } + } else { + if (fieldName in enumConstantSymbolicResultsByName) { + // it is field to store enum constant so we use already created symbolic value from runtime enum constant + enumConstantSymbolicResultsByName.getValue(fieldName) + } else { + // otherwise, it is a common static field, + // and we have to create new symbolic value for it using its concrete value + toMethodResult(staticFieldConcreteValue, fieldType) + } + } + private val Type.unsigned: Boolean get() = this is CharType 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 054bf26cde..486499a5bc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt @@ -18,7 +18,6 @@ import soot.Scene import soot.SootField import soot.Type import soot.VoidType -import sun.reflect.Reflection class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy: Hierarchy) { 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 12c4ef9bd5..bfb5f5de90 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -75,6 +75,12 @@ import org.utbot.engine.symbolic.SymbolicStateUpdate import org.utbot.engine.symbolic.asHardConstraint import org.utbot.engine.symbolic.asSoftConstraint import org.utbot.engine.symbolic.asUpdate +import org.utbot.engine.util.statics.concrete.associateEnumSootFieldsWithConcreteValues +import org.utbot.engine.util.statics.concrete.isEnumAffectingExternalStatics +import org.utbot.engine.util.statics.concrete.isEnumValuesFieldName +import org.utbot.engine.util.statics.concrete.makeEnumNonStaticFieldsUpdates +import org.utbot.engine.util.statics.concrete.makeEnumStaticFieldsUpdates +import org.utbot.engine.util.statics.concrete.makeSymbolicValuesFromEnumConcreteValues import org.utbot.framework.PathSelectorType import org.utbot.framework.UtSettings import org.utbot.framework.UtSettings.checkSolverTimeoutMillis @@ -152,6 +158,7 @@ import kotlinx.collections.immutable.persistentHashMapOf import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toPersistentList +import kotlinx.collections.immutable.toPersistentMap import kotlinx.collections.immutable.toPersistentSet import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job @@ -196,7 +203,6 @@ import soot.jimple.Expr import soot.jimple.FieldRef import soot.jimple.FloatConstant import soot.jimple.IdentityRef -import soot.jimple.InstanceFieldRef import soot.jimple.IntConstant import soot.jimple.InvokeExpr import soot.jimple.LongConstant @@ -876,7 +882,7 @@ class UtBotSymbolicEngine( stmt: Stmt ): Boolean { if (shouldProcessStaticFieldConcretely(fieldRef)) { - return processStaticFieldConcretely(fieldRef) + return processStaticFieldConcretely(fieldRef, stmt) } val field = fieldRef.field @@ -922,7 +928,9 @@ class UtBotSymbolicEngine( // Note that this list is not exhaustive, so it may be supplemented in the future. val packagesToProcessConcretely = javaPackagesToProcessConcretely + sunPackagesToProcessConcretely - return packagesToProcessConcretely.any { className.startsWith(it) } + val declaringClass = fieldRef.field.declaringClass + + val isFromPackageToProcessConcretely = packagesToProcessConcretely.any { className.startsWith(it) } // it is required to remove classes we override, since // we could accidentally initialize their final fields // with values that will later affect our overridden classes @@ -933,6 +941,13 @@ class UtBotSymbolicEngine( //hardcoded string for class name is used cause class is not public //this is a hack to avoid crashing on code with Math.random() && !className.endsWith("RandomNumberGeneratorHolder") + + // we can process concretely only enums that does not affect the external system + val isEnumNotAffectingExternalStatics = declaringClass.let { + it.isEnum && !it.isEnumAffectingExternalStatics(typeResolver) + } + + return isEnumNotAffectingExternalStatics || isFromPackageToProcessConcretely } } @@ -954,7 +969,7 @@ class UtBotSymbolicEngine( * * Returns true if processing takes place and Engine should end traversal of current statement. */ - private fun processStaticFieldConcretely(fieldRef: StaticFieldRef): Boolean { + private fun processStaticFieldConcretely(fieldRef: StaticFieldRef, stmt: Stmt): Boolean { val field = fieldRef.field val fieldId = field.fieldId if (memory.isInitialized(fieldId)) { @@ -963,6 +978,107 @@ class UtBotSymbolicEngine( // Gets concrete value, converts to symbolic value val declaringClass = field.declaringClass + + val (edge, updates) = if (declaringClass.isEnum) { + makeConcreteUpdatesForEnums(fieldId, declaringClass, stmt) + } else { + makeConcreteUpdatesForNonEnumStaticField(field, fieldId, declaringClass) + } + + val newState = environment.state.updateQueued(edge, updates) + pathSelector.offer(newState) + + return true + } + + private fun makeConcreteUpdatesForEnums( + fieldId: FieldId, + declaringClass: SootClass, + stmt: Stmt + ): Pair { + val type = declaringClass.type + val jClass = type.id.jClass + + // symbolic value for enum class itself + val enumClassValue = findOrCreateStaticObject(type) + + // values for enum constants + val enumConstantConcreteValues = jClass.enumConstants.filterIsInstance>() + + val (enumConstantSymbolicValues, enumConstantSymbolicResultsByName) = + makeSymbolicValuesFromEnumConcreteValues(type, enumConstantConcreteValues) + + val enumFields = typeResolver.findFields(type) + + val sootFieldsWithRuntimeValues = + associateEnumSootFieldsWithConcreteValues(enumFields, enumConstantConcreteValues) + + val (staticFields, nonStaticFields) = sootFieldsWithRuntimeValues.partition { it.first.isStatic } + + val (staticFieldUpdates, curFieldSymbolicValueForLocalVariable) = makeEnumStaticFieldsUpdates( + staticFields, + declaringClass, + enumConstantSymbolicResultsByName, + enumConstantSymbolicValues, + enumClassValue, + fieldId + ) + + val nonStaticFieldsUpdates = makeEnumNonStaticFieldsUpdates(enumConstantSymbolicValues, nonStaticFields) + + // we do not mark static fields for enum constants and $VALUES as meaningful + // because we should not set them in generated code + val meaningfulStaticFields = staticFields.filterNot { + val name = it.first.name + + name in enumConstantSymbolicResultsByName.keys || isEnumValuesFieldName(name) + } + + val initializedStaticFieldsMemoryUpdate = MemoryUpdate( + initializedStaticFields = staticFields.associate { it.first.fieldId to it.second.single() }.toPersistentMap(), + meaningfulStaticFields = meaningfulStaticFields.map { it.first.fieldId }.toPersistentSet() + ) + + var allUpdates = staticFieldUpdates + nonStaticFieldsUpdates + initializedStaticFieldsMemoryUpdate + + // we need to make locals update if it is an assignment statement + // for enums we have only two types for assignment with enums — enum constant or $VALUES field + // for example, a jimple body for Enum::values method starts with the following lines: + // public static ClassWithEnum$StatusEnum[] values() + // { + // ClassWithEnum$StatusEnum[] $r0, $r2; + // java.lang.Object $r1; + // $r0 = ; + // $r1 = virtualinvoke $r0.(); + + // so, we have to make an update for the local $r0 + if (stmt is JAssignStmt) { + val local = stmt.leftOp as JimpleLocal + val localUpdate = localMemoryUpdate( + local.variable to curFieldSymbolicValueForLocalVariable + ) + + allUpdates += localUpdate + } + + // enum static initializer can be the first statement in method so there will be no last edge + // for example, as it is during Enum::values method analysis: + // public static ClassWithEnum$StatusEnum[] values() + // { + // ClassWithEnum$StatusEnum[] $r0, $r2; + // java.lang.Object $r1; + + // $r0 = ; + val edge = environment.state.lastEdge ?: globalGraph.succ(stmt) + + return edge to allUpdates + } + + private fun makeConcreteUpdatesForNonEnumStaticField( + field: SootField, + fieldId: FieldId, + declaringClass: SootClass + ): Pair { val concreteValue = extractConcreteValue(field, declaringClass) val (symbolicResult, symbolicStateUpdate) = toMethodResult(concreteValue, field.type) val symbolicValue = (symbolicResult as SymbolicSuccess).value @@ -970,19 +1086,15 @@ class UtBotSymbolicEngine( // Collects memory updates val initializedFieldUpdate = MemoryUpdate(initializedStaticFields = persistentHashMapOf(fieldId to concreteValue)) + val objectUpdate = objectUpdate( instance = findOrCreateStaticObject(declaringClass.type), field = field, value = valueToExpression(symbolicValue, field.type) ) val allUpdates = symbolicStateUpdate + initializedFieldUpdate + objectUpdate - pathSelector.offer( - environment.state.updateQueued( - edge = environment.state.lastEdge!!, - allUpdates - ) - ) - return true + + return environment.state.lastEdge!! to allUpdates } // Some fields are inaccessible with reflection, so we have to instantiate it by ourselves. @@ -1200,7 +1312,7 @@ class UtBotSymbolicEngine( /** * Converts value to expression with cast to target type for primitives. */ - private fun valueToExpression(value: SymbolicValue, type: Type): UtExpression = when (value) { + fun valueToExpression(value: SymbolicValue, type: Type): UtExpression = when (value) { is ReferenceValue -> value.addr // TODO: shall we add additional constraint that aligned expression still equals original? // BitVector can lose valuable bites during extraction @@ -2028,6 +2140,7 @@ class UtBotSymbolicEngine( val touchedStaticFields = persistentListOf(staticFieldMemoryUpdate) queuedSymbolicStateUpdates += MemoryUpdate(staticFieldsUpdates = touchedStaticFields) + // TODO filter enum constant static fields JIRA:1681 if (!environment.method.isStaticInitializer && !fieldId.isSynthetic) { queuedSymbolicStateUpdates += MemoryUpdate(meaningfulStaticFields = persistentSetOf(fieldId)) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt new file mode 100644 index 0000000000..84deca8af5 --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt @@ -0,0 +1,245 @@ +package org.utbot.engine.util.statics.concrete + +import org.utbot.common.withAccessibility +import org.utbot.engine.* +import org.utbot.engine.nullObjectAddr +import org.utbot.engine.pc.addrEq +import org.utbot.engine.pc.mkEq +import org.utbot.engine.pc.mkNot +import org.utbot.engine.pc.select +import org.utbot.engine.symbolic.SymbolicStateUpdate +import org.utbot.engine.symbolic.asHardConstraint +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.util.field +import soot.SootClass +import soot.SootField +import soot.SootMethod +import soot.Type +import soot.Value +import soot.jimple.StaticFieldRef +import soot.jimple.Stmt +import soot.jimple.internal.JAssignStmt + +fun UtBotSymbolicEngine.makeSymbolicValuesFromEnumConcreteValues( + type: Type, + enumConstantRuntimeValues: List> +): Pair, Map> { + val enumConstantResultsWithNames = enumConstantRuntimeValues.map { + it.name to toMethodResult(it, type) + } + val enumConstantSymbolicValuesWithNames = enumConstantResultsWithNames.map { + it.first to (it.second.symbolicResult as SymbolicSuccess).value as ObjectValue + } + + val enumConstantSymbolicValues = enumConstantSymbolicValuesWithNames.map { it.second } + + val enumConstantSymbolicResultsByName = enumConstantResultsWithNames.toMap() + + return enumConstantSymbolicValues to enumConstantSymbolicResultsByName +} + +fun associateEnumSootFieldsWithConcreteValues( + enumFields: List, + enumConstants: List> +): List>> = + enumFields.map { enumSootField -> + val enumField = enumSootField.fieldId.field + + val fieldValues = if (enumSootField.isStatic) { + val staticFieldValue = enumField.withAccessibility { enumField.get(null) } + + listOf(staticFieldValue) + } else { + // extract ordinal, name and other non static fields for every enum constant + enumConstants.map { concreteValue -> + enumField.withAccessibility { enumField.get(concreteValue) } + } + } + + enumSootField to fieldValues + } + +/** + * Construct symbolic updates for enum static fields and a symbolic value for a local in the left part of the assignment. + */ +fun UtBotSymbolicEngine.makeEnumStaticFieldsUpdates( + staticFields: List>>, + declaringClass: SootClass, + enumConstantSymbolicResultsByName: Map, + enumConstantSymbolicValues: List, + enumClassValue: ObjectValue, + fieldId: FieldId +): Pair { + var staticFieldsUpdates = SymbolicStateUpdate() + var symbolicValueForLocal: SymbolicValue? = null + + staticFields.forEach { (sootStaticField, staticFieldRuntimeValue) -> + val fieldName = sootStaticField.name + val fieldType = sootStaticField.type + val (fieldSymbolicResult, fieldSymbolicStateUpdate) = constructEnumStaticFieldResult( + fieldName, + fieldType, + declaringClass, + enumConstantSymbolicResultsByName, + staticFieldRuntimeValue.single(), + enumConstantSymbolicValues + ) + + val fieldSymbolicValue = (fieldSymbolicResult as SymbolicSuccess).value + val fieldValue = valueToExpression(fieldSymbolicValue, fieldType) + + val fieldUpdate = objectUpdate(enumClassValue, sootStaticField, fieldValue) + + staticFieldsUpdates += fieldSymbolicStateUpdate + fieldUpdate + + // enum constant could not be null + if (fieldName in enumConstantSymbolicResultsByName) { + val canBeNull = addrEq(fieldSymbolicValue.addr, nullObjectAddr) + val canNotBeNull = mkNot(canBeNull) + + staticFieldsUpdates += canNotBeNull.asHardConstraint() + } + + // save value to associate it with local if required + if (sootStaticField.name == fieldId.name) { + symbolicValueForLocal = fieldSymbolicValue + } + } + + return staticFieldsUpdates to symbolicValueForLocal +} + +fun UtBotSymbolicEngine.makeEnumNonStaticFieldsUpdates( + enumConstantSymbolicValues: List, + nonStaticFields: List>> +): SymbolicStateUpdate { + var nonStaticFieldsUpdates = SymbolicStateUpdate() + + for ((i, enumConstantSymbolicValue) in enumConstantSymbolicValues.withIndex()) { + nonStaticFields.forEach { (sootNonStaticField, nonStaticFieldRuntimeValues) -> + val nonStaticFieldRuntimeValue = nonStaticFieldRuntimeValues[i] + + val fieldType = sootNonStaticField.type + val (fieldSymbolicResult, fieldSymbolicStateUpdate) = toMethodResult( + nonStaticFieldRuntimeValue, + fieldType + ) + + nonStaticFieldsUpdates += fieldSymbolicStateUpdate + + val fieldSymbolicValue = (fieldSymbolicResult as SymbolicSuccess).value + val fieldValue = valueToExpression(fieldSymbolicValue, fieldType) + + val chunkId = hierarchy.chunkIdForField(enumConstantSymbolicValue.type, sootNonStaticField) + val descriptor = MemoryChunkDescriptor(chunkId, enumConstantSymbolicValue.type, fieldType) + val array = memory.findArray(descriptor) + val arraySelectEqualsValue = mkEq(array.select(enumConstantSymbolicValue.addr), fieldValue) + + nonStaticFieldsUpdates += arraySelectEqualsValue.asHardConstraint() + } + } + + return nonStaticFieldsUpdates +} + +fun isEnumValuesFieldName(fieldName: String): Boolean = fieldName == "\$VALUES" + +/** + * Checks that [this] is enum which affects any external static fields in its / sections. + */ +fun SootClass.isEnumAffectingExternalStatics(typeResolver: TypeResolver): Boolean { + if (!isEnum) { + return false + } + + // enum active body contains invocations so we can check only + val staticInitializer = staticInitializerOrNull() ?: return false + + val implementedInterfaces = typeResolver + .findOrConstructAncestorsIncludingTypes(type) + .filter { type -> type.sootClass.isInterface } + + return staticInitializer.isTouchingExternalStatics(this, mutableSetOf(), implementedInterfaces) +} + +/** + * Returns whether [this] method touches any statics from any types + * except [currentClass] and its interfaces in [currentClassImplementedInterfaces]. + * + * NOTE: see org.utbot.examples.enums.ClassWithEnum.{EnumWithStaticAffectingInit, OuterStaticUsageEnum} for examples. + */ +fun SootMethod.isTouchingExternalStatics( + currentClass: SootClass, + alreadyProcessed: MutableSet, + currentClassImplementedInterfaces: List +): Boolean { + if (this in alreadyProcessed) { + return false + } + + alreadyProcessed += this + + // active body could be missing ((java.lang.String,int)>, for example) + // so consider it as not affecting external statics + if (!canRetrieveBody()) { + return false + } + + return jimpleBody().units.any { + if (it !is Stmt) { + return@any false + } + + when (it) { + is JAssignStmt -> { + val leftOp = it.leftOp + val rightOp = it.rightOp + + val assigningOuterStatics = isExternalStaticField( + leftOp, + currentClassImplementedInterfaces, + currentClass + ) + + val assignmentFromOuterStatics = isExternalStaticField( + rightOp, + currentClassImplementedInterfaces, + currentClass + ) + + assigningOuterStatics || assignmentFromOuterStatics + } + else -> { + if (it.containsInvokeExpr()) { + it.invokeExpr.method.isTouchingExternalStatics( + currentClass, + alreadyProcessed, + currentClassImplementedInterfaces + ) + } else { + false + } + } + } + } +} + +/** + * Determines whether [fieldRef] is static field not from [currentClass] + * (except static fields from all interfaces implemented by [currentClass], stored in [currentClassImplementedInterfaces]). + */ +private fun isExternalStaticField( + fieldRef: Value, + currentClassImplementedInterfaces: List, + currentClass: SootClass +): Boolean { + if (fieldRef !is StaticFieldRef) { + return false + } + + val declaringClass = fieldRef.field.declaringClass + + val classInImplementedInterfaces = declaringClass.type in currentClassImplementedInterfaces + + return !classInImplementedInterfaces && declaringClass != currentClass +} 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 40e751b6c0..af566de628 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 @@ -505,7 +505,7 @@ data class HangingTestsTimeout(val timeoutMs: Long) { companion object { const val DEFAULT_TIMEOUT_MS = DEFAULT_CONCRETE_EXECUTION_TIMEOUT_IN_CHILD_PROCESS_MS - const val MIN_TIMEOUT_MS = DEFAULT_CONCRETE_EXECUTION_TIMEOUT_IN_CHILD_PROCESS_MS + const val MIN_TIMEOUT_MS = 100L const val MAX_TIMEOUT_MS = 1_000_000L } } 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 0a877aefff..3c28c799f0 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 @@ -70,8 +70,8 @@ fun getEnumConstantByName(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun getEnumConstantByName(enumClass: Class<*>, name: String): Any? { - val fields: Array = enumClass.declaredFields + private fun getEnumConstantByName(enumClass: Class<*>, name: String): kotlin.Any? { + val fields: kotlin.Array = enumClass.declaredFields for (field in fields) { val fieldName = field.name if (field.isEnumConstant && fieldName == name) { @@ -114,7 +114,7 @@ fun getStaticFieldValue(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun getStaticFieldValue(clazz: Class<*>, fieldName: String): Any? { + private fun getStaticFieldValue(clazz: Class<*>, fieldName: String): kotlin.Any? { var currentClass: Class<*>? = clazz var field: java.lang.reflect.Field do { @@ -164,7 +164,7 @@ fun getFieldValue(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun getFieldValue(any: Any, fieldName: String): Any? { + private fun getFieldValue(any: kotlin.Any, fieldName: String): kotlin.Any? { var clazz: Class<*>? = any.javaClass var field: java.lang.reflect.Field do { @@ -214,7 +214,7 @@ fun setStaticField(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun setStaticField(defaultClass: Class<*>, fieldName: String, fieldValue: Any?) { + private fun setStaticField(defaultClass: Class<*>, fieldName: String, fieldValue: kotlin.Any?) { var field: java.lang.reflect.Field? var clazz = defaultClass @@ -266,7 +266,7 @@ fun setField(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun setField(any: Any, fieldName: String, fieldValue: Any?) { + private fun setField(any: kotlin.Any, fieldName: String, fieldValue: kotlin.Any?) { var clazz: Class<*> = any.javaClass var field: java.lang.reflect.Field? do { @@ -306,14 +306,18 @@ fun createArray(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun createArray(className: String, length: Int, vararg values: Any): Array { - val array: Any = java.lang.reflect.Array.newInstance(Class.forName(className), length) + private fun createArray( + className: String, + length: Int, + vararg values: kotlin.Any + ): kotlin.Array { + val array: kotlin.Any = java.lang.reflect.Array.newInstance(Class.forName(className), length) for (i in values.indices) { java.lang.reflect.Array.set(array, i, values[i]) } - return array as Array + return array as kotlin.Array } """ } @@ -332,7 +336,7 @@ fun createInstance(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun createInstance(className: String): Any? { + private fun createInstance(className: String): kotlin.Any? { val clazz: Class<*> = Class.forName(className) return Class.forName("sun.misc.Unsafe").getDeclaredMethod("allocateInstance", Class::class.java) .invoke(getUnsafeInstance(), clazz) @@ -354,7 +358,7 @@ fun getUnsafeInstance(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun getUnsafeInstance(): Any? { + private fun getUnsafeInstance(): kotlin.Any? { val f: java.lang.reflect.Field = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe") f.isAccessible = true return f[null] @@ -403,10 +407,10 @@ fun deepEquals(language: CodegenLanguage, mockFrameworkUsed: Boolean, mockFramew } private boolean deepEquals(Object o1, Object o2) { - return deepEquals(o1, o2, new HashSet<>()); + return deepEquals(o1, o2, new java.util.HashSet<>()); } - private boolean deepEquals(Object o1, Object o2, Set visited) { + private boolean deepEquals(Object o1, Object o2, java.util.Set visited) { visited.add(new FieldsPair(o1, o2)); if (o1 == o2) { @@ -429,15 +433,15 @@ fun deepEquals(language: CodegenLanguage, mockFrameworkUsed: Boolean, mockFramew return false; } - if (o1 instanceof Map) { - if (!(o2 instanceof Map)) { + if (o1 instanceof java.util.Map) { + if (!(o2 instanceof java.util.Map)) { return false; } - return mapsDeepEquals((Map) o1, (Map) o2, visited); + return mapsDeepEquals((java.util.Map) o1, (java.util.Map) o2, visited); } - if (o2 instanceof Map) { + if (o2 instanceof java.util.Map) { return false; } @@ -461,9 +465,9 @@ fun deepEquals(language: CodegenLanguage, mockFrameworkUsed: Boolean, mockFramew } // common classes without custom equals, use comparison by fields - final List fields = new ArrayList<>(); + final java.util.List fields = new java.util.ArrayList<>(); while (firstClass != Object.class) { - fields.addAll(Arrays.asList(firstClass.getDeclaredFields())); + fields.addAll(java.util.Arrays.asList(firstClass.getDeclaredFields())); // Interface should not appear here firstClass = firstClass.getSuperclass(); } @@ -490,26 +494,30 @@ fun deepEquals(language: CodegenLanguage, mockFrameworkUsed: Boolean, mockFramew } CodegenLanguage.KOTLIN -> { """ - private fun deepEquals(o1: Any?, o2: Any?): Boolean = deepEquals(o1, o2, hashSetOf()) + private fun deepEquals(o1: kotlin.Any?, o2: kotlin.Any?): Boolean = deepEquals(o1, o2, hashSetOf()) - private fun deepEquals(o1: Any?, o2: Any?, visited: MutableSet>): Boolean { + private fun deepEquals( + o1: kotlin.Any?, + o2: kotlin.Any?, + visited: kotlin.collections.MutableSet> + ): Boolean { visited += o1 to o2 if (o1 === o2) return true if (o1 == null || o2 == null) return false - if (o1 is Iterable<*>) { - return if (o2 !is Iterable<*>) false else iterablesDeepEquals(o1, o2, visited) + if (o1 is kotlin.collections.Iterable<*>) { + return if (o2 !is kotlin.collections.Iterable<*>) false else iterablesDeepEquals(o1, o2, visited) } - if (o2 is Iterable<*>) return false + if (o2 is kotlin.collections.Iterable<*>) return false - if (o1 is Map<*, *>) { - return if (o2 !is Map<*, *>) false else mapsDeepEquals(o1, o2, visited) + if (o1 is kotlin.collections.Map<*, *>) { + return if (o2 !is kotlin.collections.Map<*, *>) false else mapsDeepEquals(o1, o2, visited) } - if (o2 is Map<*, *>) return false + if (o2 is kotlin.collections.Map<*, *>) return false var firstClass: Class<*> = o1.javaClass if (firstClass.isArray) { @@ -528,8 +536,8 @@ fun deepEquals(language: CodegenLanguage, mockFrameworkUsed: Boolean, mockFramew } // common classes without custom equals, use comparison by fields - val fields: MutableList = mutableListOf() - while (firstClass != Any::class.java) { + val fields: kotlin.collections.MutableList = mutableListOf() + while (firstClass != kotlin.Any::class.java) { fields += listOf(*firstClass.declaredFields) // Interface should not appear here firstClass = firstClass.superclass @@ -559,14 +567,14 @@ fun arraysDeepEquals(language: CodegenLanguage): String = when (language) { CodegenLanguage.JAVA -> { """ - private boolean arraysDeepEquals(Object arr1, Object arr2, Set visited) { - final int length = Array.getLength(arr1); - if (length != Array.getLength(arr2)) { + private boolean arraysDeepEquals(Object arr1, Object arr2, java.util.Set visited) { + final int length = java.lang.reflect.Array.getLength(arr1); + if (length != java.lang.reflect.Array.getLength(arr2)) { return false; } for (int i = 0; i < length; i++) { - if (!deepEquals(Array.get(arr1, i), Array.get(arr2, i), visited)) { + if (!deepEquals(java.lang.reflect.Array.get(arr1, i), java.lang.reflect.Array.get(arr2, i), visited)) { return false; } } @@ -577,7 +585,11 @@ fun arraysDeepEquals(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun arraysDeepEquals(arr1: Any?, arr2: Any?, visited: MutableSet>): Boolean { + private fun arraysDeepEquals( + arr1: kotlin.Any?, + arr2: kotlin.Any?, + visited: kotlin.collections.MutableSet> + ): Boolean { val size = java.lang.reflect.Array.getLength(arr1) if (size != java.lang.reflect.Array.getLength(arr2)) return false @@ -597,9 +609,9 @@ fun iterablesDeepEquals(language: CodegenLanguage): String = when (language) { CodegenLanguage.JAVA -> { """ - private boolean iterablesDeepEquals(Iterable i1, Iterable i2, Set visited) { - final Iterator firstIterator = i1.iterator(); - final Iterator secondIterator = i2.iterator(); + private boolean iterablesDeepEquals(Iterable i1, Iterable i2, java.util.Set visited) { + final java.util.Iterator firstIterator = i1.iterator(); + final java.util.Iterator secondIterator = i2.iterator(); while (firstIterator.hasNext() && secondIterator.hasNext()) { if (!deepEquals(firstIterator.next(), secondIterator.next(), visited)) { return false; @@ -616,7 +628,11 @@ fun iterablesDeepEquals(language: CodegenLanguage): String = } CodegenLanguage.KOTLIN -> { """ - private fun iterablesDeepEquals(i1: Iterable<*>, i2: Iterable<*>, visited: MutableSet>): Boolean { + private fun iterablesDeepEquals( + i1: Iterable<*>, + i2: Iterable<*>, + visited: kotlin.collections.MutableSet> + ): Boolean { val firstIterator = i1.iterator() val secondIterator = i2.iterator() while (firstIterator.hasNext() && secondIterator.hasNext()) { @@ -633,12 +649,16 @@ fun mapsDeepEquals(language: CodegenLanguage): String = when (language) { CodegenLanguage.JAVA -> { """ - private boolean mapsDeepEquals(Map m1, Map m2, Set visited) { - final Iterator> firstIterator = m1.entrySet().iterator(); - final Iterator> secondIterator = m2.entrySet().iterator(); + private boolean mapsDeepEquals( + java.util.Map m1, + java.util.Map m2, + java.util.Set visited + ) { + final java.util.Iterator> firstIterator = m1.entrySet().iterator(); + final java.util.Iterator> secondIterator = m2.entrySet().iterator(); while (firstIterator.hasNext() && secondIterator.hasNext()) { - final Map.Entry firstEntry = firstIterator.next(); - final Map.Entry secondEntry = secondIterator.next(); + final java.util.Map.Entry firstEntry = firstIterator.next(); + final java.util.Map.Entry secondEntry = secondIterator.next(); if (!deepEquals(firstEntry.getKey(), secondEntry.getKey(), visited)) { return false; @@ -662,7 +682,7 @@ fun mapsDeepEquals(language: CodegenLanguage): String = private fun mapsDeepEquals( m1: kotlin.collections.Map<*, *>, m2: kotlin.collections.Map<*, *>, - visited: MutableSet> + visited: kotlin.collections.MutableSet> ): Boolean { val firstIterator = m1.entries.iterator() val secondIterator = m2.entries.iterator() @@ -704,9 +724,9 @@ fun hasCustomEquals(language: CodegenLanguage): String = """ private fun hasCustomEquals(clazz: Class<*>): Boolean { var c = clazz - while (Any::class.java != c) { + while (kotlin.Any::class.java != c) { try { - c.getDeclaredMethod("equals", Any::class.java) + c.getDeclaredMethod("equals", kotlin.Any::class.java) return true } catch (e: Exception) { // Interface should not appear here @@ -724,12 +744,12 @@ fun getArrayLength(codegenLanguage: CodegenLanguage) = CodegenLanguage.JAVA -> """ private static int getArrayLength(Object arr) { - return Array.getLength(arr); + return java.lang.reflect.Array.getLength(arr); } """.trimIndent() CodegenLanguage.KOTLIN -> """ - private fun getArrayLength(arr: Any?): Int = java.lang.reflect.Array.getLength(arr) + private fun getArrayLength(arr: kotlin.Any?): Int = java.lang.reflect.Array.getLength(arr) """.trimIndent() } diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/AbstractTestCaseGeneratorTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/AbstractTestCaseGeneratorTest.kt index 61ce16c4c2..1587b5661e 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/AbstractTestCaseGeneratorTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/AbstractTestCaseGeneratorTest.kt @@ -1233,6 +1233,101 @@ abstract class AbstractTestCaseGeneratorTest( summaryDisplayNameChecks = summaryDisplayNameChecks ) + protected inline fun checkThisAndStaticsAfter( + method: KFunction1, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, StaticsType, R?) -> 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 = ::withThisAndStaticsAfter, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkThisAndStaticsAfter( + method: KFunction2, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, T1, StaticsType, R?) -> 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, T1::class, + arguments = ::withThisAndStaticsAfter, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkThisAndStaticsAfter( + method: KFunction3, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, T1, T2, StaticsType, R?) -> 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, T1::class, T2::class, + arguments = ::withThisAndStaticsAfter, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkThisAndStaticsAfter( + method: KFunction4, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, T1, T2, T3, StaticsType, R?) -> 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, T1::class, T2::class, T3::class, + arguments = ::withThisAndStaticsAfter, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + + protected inline fun checkThisAndStaticsAfter( + method: KFunction5, + branches: ExecutionsNumberMatcher, + vararg matchers: (T, T1, T2, T3, T4, StaticsType, R?) -> 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, T1::class, T2::class, T3::class, T4::class, + arguments = ::withThisAndStaticsAfter, + additionalDependencies = additionalDependencies, + summaryTextChecks = summaryTextChecks, + summaryNameChecks = summaryNameChecks, + summaryDisplayNameChecks = summaryDisplayNameChecks + ) + // checks paramsBefore, staticsBefore and return value for static methods protected inline fun checkStaticsInStaticMethod( method: KFunction0, @@ -2528,6 +2623,7 @@ 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 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 fun withThisStaticsBeforeAndResult(ex: UtValueExecution<*>) = listOf(ex.callerBefore) + ex.paramsBefore + ex.staticsBefore + ex.evaluatedResult fun withThisAndException(ex: UtValueExecution<*>) = listOf(ex.callerBefore) + ex.paramsBefore + ex.returnValue @@ -2669,3 +2765,13 @@ inline fun withPushingStateFromPathSelectorForConcrete(block: () -> UtSettings.saveRemainingStatesForConcreteExecution = prev } } + +inline fun withTreatingOverflowAsError(block: () -> T): T { + val prev = UtSettings.treatOverflowAsError + UtSettings.treatOverflowAsError = true + try { + return block() + } finally { + UtSettings.treatOverflowAsError = prev + } +} diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/CodeTestCaseGeneratorTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/CodeTestCaseGeneratorTest.kt index 60a9d55d34..900aa0d896 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/CodeTestCaseGeneratorTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/CodeTestCaseGeneratorTest.kt @@ -35,7 +35,7 @@ import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor @ExtendWith(CodeTestCaseGeneratorTest.Companion.ReadRunningTestsNumberBeforeAllTestsCallback::class) abstract class CodeTestCaseGeneratorTest( private val testClass: KClass<*>, - private val testCodeGeneration: Boolean = true, + private var testCodeGeneration: Boolean = true, private val languagesLastStages: List = listOf( CodeGenerationLanguageLastStage(CodegenLanguage.JAVA), CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN) @@ -49,6 +49,17 @@ abstract class CodeTestCaseGeneratorTest( if (testCodeGeneration) testCases += testCase } + protected fun withEnabledTestingCodeGeneration(testCodeGeneration: Boolean, block: () -> Unit) { + val prev = this.testCodeGeneration + + try { + this.testCodeGeneration = testCodeGeneration + block() + } finally { + this.testCodeGeneration = prev + } + } + // save all generated test cases from current class to test code generation private fun addTestCase(pkg: Package) { if (testCodeGeneration) { diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranchesTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranchesTest.kt deleted file mode 100644 index ec12cd5440..0000000000 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranchesTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.utbot.examples.enums - -import org.utbot.examples.AbstractTestCaseGeneratorTest -import org.utbot.examples.eq -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -class ClassWithEnumInsideDifficultBranchesTest : AbstractTestCaseGeneratorTest(testClass = ClassWithEnumInsideDifficultBranches::class) { - @Test - @Disabled("TODO JIRA:1612") - fun testDifficultIfBranch() { - check( - ClassWithEnumInsideDifficultBranches::useEnumInDifficultIf, - eq(2), - { s, r -> s.equals("TRYIF", ignoreCase = true) && r == 1 }, - { s, r -> !s.equals("TRYIF", ignoreCase = true) && r == 2 } - ) - } -} \ No newline at end of file diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt index c264da89ea..079bf1d01c 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt @@ -1,16 +1,197 @@ package org.utbot.examples.enums +import org.utbot.common.findField import org.utbot.examples.AbstractTestCaseGeneratorTest +import org.utbot.examples.DoNotCalculate +import org.utbot.examples.enums.ClassWithEnum.StatusEnum.ERROR +import org.utbot.examples.enums.ClassWithEnum.StatusEnum.READY +import org.utbot.examples.eq +import org.utbot.examples.isException +import org.utbot.examples.withPushingStateFromPathSelectorForConcrete import org.utbot.examples.withoutConcrete +import org.utbot.framework.plugin.api.FieldId +import org.utbot.framework.plugin.api.util.id import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test class ClassWithEnumTest : AbstractTestCaseGeneratorTest(testClass = ClassWithEnum::class) { @Test - @Disabled("TODO JIRA:1611") fun testOrdinal() { withoutConcrete { checkAllCombinations(ClassWithEnum::useOrdinal) } } + + @Test + fun testGetter() { + check( + ClassWithEnum::useGetter, + eq(2), + { s, r -> s == null && r == -1 }, + { s, r -> s != null && r == 0 }, + ) + } + + @Test + fun testDifficultIfBranch() { + check( + ClassWithEnum::useEnumInDifficultIf, + eq(2), + { s, r -> s.equals("TRYIF", ignoreCase = true) && r == 1 }, + { s, r -> !s.equals("TRYIF", ignoreCase = true) && r == 2 }, + ) + } + + @Test + @Disabled("TODO JIRA:1686") + fun testNullParameter() { + check( + ClassWithEnum::nullEnumAsParameter, + eq(3), + { e, _ -> e == null }, + { e, r -> e == READY && r == 0 }, + { e, r -> e == ERROR && r == -1 }, + ) + } + + @Test + @Disabled("TODO JIRA:1686") + fun testNullField() { + checkWithException( + ClassWithEnum::nullField, + eq(3), + { e, r -> e == null && r.isException() }, + { e, r -> e == ERROR && r.isException() }, + { e, r -> e == READY && r.getOrNull()!! == 3 && READY.s.length == 3 }, + ) + } + + @Test + @Disabled("TODO JIRA:1686") + fun testChangeEnum() { + checkWithException( + ClassWithEnum::changeEnum, + eq(3), + { e, r -> e == null && r.isException() }, + { e, r -> e == READY && r.getOrNull()!! == ERROR.ordinal }, + { e, r -> e == ERROR && r.getOrNull()!! == READY.ordinal }, + ) + } + + @Test + fun testChangeMutableField() { + // TODO testing code generation for this method is disabled because we need to restore original field state + // should be enabled after solving JIRA:1648 + withEnabledTestingCodeGeneration(testCodeGeneration = false) { + checkWithException( + ClassWithEnum::changeMutableField, + eq(2), + { e, r -> e == READY && r.getOrNull()!! == 2 }, + { e, r -> (e == null || e == ERROR) && r.getOrNull()!! == -2 }, + ) + } + } + + @Test + @Disabled("TODO JIRA:1686") + fun testCheckName() { + check( + ClassWithEnum::checkName, + eq(3), + { s, _ -> s == null }, + { s, r -> s == READY.name && r == ERROR.name }, + { s, r -> s != READY.name && r == READY.name }, + ) + } + + @Test + fun testChangingStaticWithEnumInit() { + checkThisAndStaticsAfter( + ClassWithEnum::changingStaticWithEnumInit, + eq(1), + { t, staticsAfter, r -> + // for some reasons x is inaccessible + val x = t.javaClass.findField("x").get(t) as Int + + val y = staticsAfter[FieldId(ClassWithEnum.ClassWithStaticField::class.id, "y")]!!.value as Int + + val areStaticsCorrect = x == 1 && y == 11 + areStaticsCorrect && r == true + } + ) + } + + @Test + fun testEnumValues() { + checkStaticMethod( + ClassWithEnum.StatusEnum::values, + eq(1), + { r -> r.contentEquals(arrayOf(READY, ERROR)) }, + ) + } + + @Test + fun testFromCode() { + checkStaticMethod( + ClassWithEnum.StatusEnum::fromCode, + eq(3), + { code, r -> code == 10 && r == READY }, + { code, r -> code == -10 && r == ERROR }, + { code, r -> code !in setOf(10, -10) && r == null }, // IllegalArgumentException + ) + } + + @Test + fun testFromIsReady() { + checkStaticMethod( + ClassWithEnum.StatusEnum::fromIsReady, + eq(2), + { isFirst, r -> isFirst && r == READY }, + { isFirst, r -> !isFirst && r == ERROR }, + ) + } + + @Test + @Disabled("TODO JIRA:1450") + fun testPublicGetCodeMethod() { + checkWithThis( + ClassWithEnum.StatusEnum::publicGetCode, + eq(2), + { enumInstance, r -> enumInstance == READY && r == 10 }, + { enumInstance, r -> enumInstance == ERROR && r == -10 }, + coverage = DoNotCalculate + ) + } + + @Test + fun testImplementingInterfaceEnumInDifficultBranch() { + withPushingStateFromPathSelectorForConcrete { + check( + ClassWithEnum::implementingInterfaceEnumInDifficultBranch, + eq(2), + { s, r -> s.equals("SUCCESS", ignoreCase = true) && r == 0 }, + { s, r -> !s.equals("SUCCESS", ignoreCase = true) && r == 2 }, + ) + } + } + + @Test + fun testAffectSystemStaticAndUseInitEnumFromIt() { + check( + ClassWithEnum::affectSystemStaticAndInitEnumFromItAndReturnField, + eq(1), + { r -> r == true }, + coverage = DoNotCalculate + ) + } + + @Test + fun testAffectSystemStaticAndInitEnumFromItAndGetItFromEnumFun() { + check( + ClassWithEnum::affectSystemStaticAndInitEnumFromItAndGetItFromEnumFun, + eq(1), + { r -> r == true }, + coverage = DoNotCalculate + ) + } } \ No newline at end of file diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/math/OverflowAsErrorTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/math/OverflowAsErrorTest.kt index ba76a60f40..a14c592c1f 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/math/OverflowAsErrorTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/math/OverflowAsErrorTest.kt @@ -1,5 +1,7 @@ package org.utbot.examples.math +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test import org.utbot.examples.AbstractTestCaseGeneratorTest import org.utbot.examples.AtLeast import org.utbot.examples.algorithms.Sort @@ -7,15 +9,11 @@ import org.utbot.examples.eq import org.utbot.examples.ignoreExecutionsNumber import org.utbot.examples.isException import org.utbot.examples.withSolverTimeoutInMillis -import org.utbot.framework.UtSettings +import org.utbot.examples.withTreatingOverflowAsError import org.utbot.framework.codegen.Compilation import org.utbot.framework.plugin.api.CodegenLanguage import kotlin.math.floor import kotlin.math.sqrt -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test internal class OverflowAsErrorTest : AbstractTestCaseGeneratorTest( testClass = OverflowExamples::class, @@ -27,133 +25,140 @@ internal class OverflowAsErrorTest : AbstractTestCaseGeneratorTest( CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, Compilation), ) ) { - private val treatOverflowAsError = UtSettings.treatOverflowAsError - - @BeforeAll - fun beforeAll() { - UtSettings.treatOverflowAsError = true - } - - @AfterAll - fun afterAll() { - UtSettings.treatOverflowAsError = treatOverflowAsError - } - @Test fun testIntOverflow() { - checkWithException( - OverflowExamples::intOverflow, - eq(5), - { x, _, r -> x * x * x <= 0 && x > 0 && r.isException() }, // through overflow - { x, _, r -> x * x * x <= 0 && x > 0 && r.isException() }, // through overflow (2nd '*') - { x, _, r -> x * x * x >= 0 && x >= 0 && r.getOrNull() == 0 }, - { x, y, r -> x * x * x > 0 && x > 0 && y == 10 && r.getOrNull() == 1 }, - { x, y, r -> x * x * x > 0 && x > 0 && y != 10 && r.getOrNull() == 0 }, - coverage = AtLeast(90), - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::intOverflow, + eq(5), + { x, _, r -> x * x * x <= 0 && x > 0 && r.isException() }, // through overflow + { x, _, r -> x * x * x <= 0 && x > 0 && r.isException() }, // through overflow (2nd '*') + { x, _, r -> x * x * x >= 0 && x >= 0 && r.getOrNull() == 0 }, + { x, y, r -> x * x * x > 0 && x > 0 && y == 10 && r.getOrNull() == 1 }, + { x, y, r -> x * x * x > 0 && x > 0 && y != 10 && r.getOrNull() == 0 }, + coverage = AtLeast(90), + ) + } } @Test fun testByteAddOverflow() { - checkWithException( - OverflowExamples::byteAddOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { x, y, r -> - val negOverflow = ((x + y).toByte() >= 0 && x < 0 && y < 0) - val posOverflow = ((x + y).toByte() <= 0 && x > 0 && y > 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::byteAddOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x + y).toByte() >= 0 && x < 0 && y < 0) + val posOverflow = ((x + y).toByte() <= 0 && x > 0 && y > 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testByteSubOverflow() { - checkWithException( - OverflowExamples::byteSubOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { x, y, r -> - val negOverflow = ((x - y).toByte() >= 0 && x < 0 && y > 0) - val posOverflow = ((x - y).toByte() <= 0 && x > 0 && y < 0) - (negOverflow || posOverflow) && r.isException()}, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::byteSubOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x - y).toByte() >= 0 && x < 0 && y > 0) + val posOverflow = ((x - y).toByte() <= 0 && x > 0 && y < 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testByteMulOverflow() { - checkWithException( - OverflowExamples::byteMulOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { _, _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::byteMulOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { _, _, r -> r.isException() }, // through overflow + ) + } } @Test fun testShortAddOverflow() { - checkWithException( - OverflowExamples::shortAddOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { x, y, r -> - val negOverflow = ((x + y).toShort() >= 0 && x < 0 && y < 0) - val posOverflow = ((x + y).toShort() <= 0 && x > 0 && y > 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::shortAddOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x + y).toShort() >= 0 && x < 0 && y < 0) + val posOverflow = ((x + y).toShort() <= 0 && x > 0 && y > 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testShortSubOverflow() { - checkWithException( - OverflowExamples::shortSubOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { x, y, r -> - val negOverflow = ((x - y).toShort() >= 0 && x < 0 && y > 0) - val posOverflow = ((x - y).toShort() <= 0 && x > 0 && y < 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::shortSubOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x - y).toShort() >= 0 && x < 0 && y > 0) + val posOverflow = ((x - y).toShort() <= 0 && x > 0 && y < 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testShortMulOverflow() { - checkWithException( - OverflowExamples::shortMulOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { _, _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::shortMulOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { _, _, r -> r.isException() }, // through overflow + ) + } } @Test fun testIntAddOverflow() { - checkWithException( - OverflowExamples::intAddOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { x, y, r -> - val negOverflow = ((x + y) >= 0 && x < 0 && y < 0) - val posOverflow = ((x + y) <= 0 && x > 0 && y > 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::intAddOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x + y) >= 0 && x < 0 && y < 0) + val posOverflow = ((x + y) <= 0 && x > 0 && y > 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testIntSubOverflow() { - checkWithException( - OverflowExamples::intSubOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { x, y, r -> - val negOverflow = ((x - y) >= 0 && x < 0 && y > 0) - val posOverflow = ((x - y) <= 0 && x > 0 && y < 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::intSubOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x - y) >= 0 && x < 0 && y > 0) + val posOverflow = ((x - y) <= 0 && x > 0 && y < 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test @@ -162,41 +167,47 @@ internal class OverflowAsErrorTest : AbstractTestCaseGeneratorTest( // Reason: softConstraints, containing limits for Int values, hang solver. // With solver timeout softConstraints are dropped and hard constraints are SAT for overflow. withSolverTimeoutInMillis(timeoutInMillis = 1000) { - checkWithException( - OverflowExamples::intMulOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { _, _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::intMulOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { _, _, r -> r.isException() }, // through overflow + ) + } } } @Test fun testLongAddOverflow() { - checkWithException( - OverflowExamples::longAddOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { x, y, r -> - val negOverflow = ((x + y) >= 0 && x < 0 && y < 0) - val posOverflow = ((x + y) <= 0 && x > 0 && y > 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::longAddOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x + y) >= 0 && x < 0 && y < 0) + val posOverflow = ((x + y) <= 0 && x > 0 && y > 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test fun testLongSubOverflow() { - checkWithException( - OverflowExamples::longSubOverflow, - eq(2), - { _, _, r -> !r.isException()}, - { x, y, r -> - val negOverflow = ((x - y) >= 0 && x < 0 && y > 0) - val posOverflow = ((x - y) <= 0 && x > 0 && y < 0) - (negOverflow || posOverflow) && r.isException() - }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::longSubOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { x, y, r -> + val negOverflow = ((x - y) >= 0 && x < 0 && y > 0) + val posOverflow = ((x - y) <= 0 && x > 0 && y < 0) + (negOverflow || posOverflow) && r.isException() + }, // through overflow + ) + } } @Test @@ -205,49 +216,57 @@ internal class OverflowAsErrorTest : AbstractTestCaseGeneratorTest( // Reason: softConstraints, containing limits for Int values, hang solver. // With solver timeout softConstraints are dropped and hard constraints are SAT for overflow. withSolverTimeoutInMillis(timeoutInMillis = 2000) { - checkWithException( - OverflowExamples::longMulOverflow, - eq(2), - { _, _, r -> !r.isException() }, - { _, _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::longMulOverflow, + eq(2), + { _, _, r -> !r.isException() }, + { _, _, r -> r.isException() }, // through overflow + ) + } } } @Test fun testIncOverflow() { - checkWithException( - OverflowExamples::incOverflow, - eq(2), - { _, r -> !r.isException()}, - { _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::incOverflow, + eq(2), + { _, r -> !r.isException() }, + { _, r -> r.isException() }, // through overflow + ) + } } @Test fun testIntCubeOverflow() { val sqrtIntMax = floor(sqrt(Int.MAX_VALUE.toDouble())).toInt() - checkWithException( - OverflowExamples::intCubeOverflow, - eq(3), - { _, r -> !r.isException()}, - // Can't use abs(x) below, because abs(Int.MIN_VALUE) == Int.MIN_VALUE. - // (Int.MAX_VALUE shr 16) is the border of square overflow and cube overflow. - // Int.MAX_VALUE.toDouble().pow(1/3.toDouble()) - { x, r -> (x > -sqrtIntMax && x < sqrtIntMax ) && r.isException() }, // through overflow - { x, r -> (x <= -sqrtIntMax || x >= sqrtIntMax) && r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + OverflowExamples::intCubeOverflow, + eq(3), + { _, r -> !r.isException() }, + // Can't use abs(x) below, because abs(Int.MIN_VALUE) == Int.MIN_VALUE. + // (Int.MAX_VALUE shr 16) is the border of square overflow and cube overflow. + // Int.MAX_VALUE.toDouble().pow(1/3.toDouble()) + { x, r -> (x > -sqrtIntMax && x < sqrtIntMax) && r.isException() }, // through overflow + { x, r -> (x <= -sqrtIntMax || x >= sqrtIntMax) && r.isException() }, // through overflow + ) + } } // Generated Kotlin code does not compile, so disabled for now @Test @Disabled fun testQuickSort() { - checkWithException( - Sort::quickSort, - ignoreExecutionsNumber, - { _, _, _, r -> !r.isException()}, - { _, _, _, r -> r.isException() }, // through overflow - ) + withTreatingOverflowAsError { + checkWithException( + Sort::quickSort, + ignoreExecutionsNumber, + { _, _, _, r -> !r.isException() }, + { _, _, _, r -> r.isException() }, // through overflow + ) + } } } diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/objects/EnumsTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/objects/EnumsTest.kt deleted file mode 100644 index 09f10a080a..0000000000 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/objects/EnumsTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.utbot.examples.objects - -import org.utbot.examples.AbstractTestCaseGeneratorTest -import org.utbot.examples.DoNotCalculate -import org.utbot.examples.eq -import org.utbot.examples.objects.SimpleEnum.FIRST -import org.utbot.examples.objects.SimpleEnum.SECOND -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -internal class EnumsTest : AbstractTestCaseGeneratorTest(testClass = SimpleEnum::class) { - @Test - fun testEnumValues() { - checkStaticMethod( - SimpleEnum::values, - eq(1), - { r -> r.contentEquals(arrayOf(FIRST, SECOND)) }, - // TODO: loader MemoryClassLoader attempted duplicate class definition - coverage = DoNotCalculate - ) - } - - @Test - fun testFromCode() { - checkStaticMethod( - SimpleEnum::fromCode, - eq(3), - { code, r -> code == 1 && r == FIRST }, - { code, r -> code == 2 && r == SECOND }, - { code, r -> code !in 1..2 && r == null }, // IllegalArgumentException - // TODO: CallerImpl$Method cannot access a member of class SimpleEnum with modifiers "static" - coverage = DoNotCalculate - ) - } - - @Test - fun testFromIsFirst() { - checkStaticMethod( - SimpleEnum::fromIsFirst, - eq(2), - { isFirst, r -> isFirst && r == FIRST }, - { isFirst, r -> !isFirst && r == SECOND }, - // TODO: CallerImpl$Method cannot access a member of class SimpleEnum with modifiers "static" - coverage = DoNotCalculate - ) - } - - @Test - @Disabled("JIRA:1450") - fun testPublicGetCodeMethod() { - checkWithThis( - SimpleEnum::publicGetCode, - eq(2), - { enumInstance, r -> enumInstance == FIRST && r == 1 }, - { enumInstance, r -> enumInstance == SECOND && r == 2 }, - coverage = DoNotCalculate - ) - } -} \ No newline at end of file diff --git a/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnum.java b/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnum.java index 4c3fe80aa5..14a0ded3fc 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnum.java +++ b/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnum.java @@ -1,37 +1,241 @@ package org.utbot.examples.enums; -import static org.utbot.examples.enums.ClassWithEnum.StatusEnum.*; +import static org.utbot.examples.enums.ClassWithEnum.ManyConstantsEnum.A; +import static org.utbot.examples.enums.ClassWithEnum.ManyConstantsEnum.B; +import static org.utbot.examples.enums.ClassWithEnum.StatusEnum.ERROR; +import static org.utbot.examples.enums.ClassWithEnum.StatusEnum.READY; +@SuppressWarnings({"UnnecessaryLocalVariable", "IfStatementWithIdenticalBranches"}) public class ClassWithEnum { public int useOrdinal(String s) { if (s != null) { - return READY.ordinal(); + final int ordinal = READY.ordinal(); + return ordinal; } else { - return ERROR.ordinal(); + final int ordinal = ERROR.ordinal(); + return ordinal; } } - @SuppressWarnings("unused") public int useGetter(String s) { if (s != null) { - return READY.getX(); + final int mutableInt = READY.getMutableInt(); + return mutableInt; + } else { + final int mutableInt = ERROR.getMutableInt(); + return mutableInt; + } + } + + @SuppressWarnings("UnnecessaryLocalVariable") + public int useEnumInDifficultIf(String s) { + if ("TRYIF".equalsIgnoreCase(s)) { + final ManyConstantsEnum[] values = ManyConstantsEnum.values(); + return foo(values[0]); } else { - return ERROR.getX(); + final ManyConstantsEnum b = B; + return foo(b); + } + } + + private int foo(ManyConstantsEnum e) { + if (e.equals(A)) { + return 1; + } else { + return 2; + } + } + + public int nullEnumAsParameter(StatusEnum statusEnum) { + final int ordinal = statusEnum.ordinal(); + return ordinal; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + public int nullField(StatusEnum statusEnum) { + // catch NPE + statusEnum.s.length(); + + statusEnum.s = "404"; + return statusEnum.s.length(); + } + + public int changeEnum(StatusEnum statusEnum) { + if (statusEnum == READY) { + statusEnum = ERROR; + } else { + statusEnum = READY; + } + + return statusEnum.ordinal(); + } + + public String checkName(String s) { + final String name = READY.name(); + if (s.equals(name)) { + return ERROR.name(); + } + + return READY.name(); + } + + public int changeMutableField(StatusEnum statusEnum) { + if (statusEnum == READY) { + READY.mutableInt = 2; + + return READY.mutableInt; } + + ERROR.mutableInt = -2; + return ERROR.mutableInt; + } + + @SuppressWarnings("unused") + public boolean changingStaticWithEnumInit() { + // run and sections + final EnumWithStaticAffectingInit[] values = EnumWithStaticAffectingInit.values(); + + return true; } enum StatusEnum { - READY(0), - ERROR(-1); + READY(0, 10, "200"), + ERROR(-1, -10, null); + + int mutableInt; + final int code; + String s; + + StatusEnum(int mutableInt, final int code, String s) { + this.mutableInt = mutableInt; + this.code = code; + this.s = s; + } + + public int getMutableInt() { + return mutableInt; + } + + public int getCode() { + return code; + } + + static StatusEnum fromCode(int code) { + for (StatusEnum value : values()) { + if (value.getCode() == code) { + return value; + } + } + + throw new IllegalArgumentException("No enum corresponding to given code: " + code); + } + + static StatusEnum fromIsReady(boolean isReady) { + return isReady ? READY : ERROR; + } + + int publicGetCode() { + return this == READY ? 10 : -10; + } + } + + enum ManyConstantsEnum { + A, B, C, D, E, F, G, H, I, J, K + } + + static int x = 0; + + static class ClassWithStaticField { + static int y = 0; + + static void increment() { + y++; + } + } + + enum EnumWithStaticAffectingInit { + A, B; + + EnumWithStaticAffectingInit() { + ClassWithStaticField.y++; + ClassWithStaticField.increment(); + invokeIncrement(); + invokeIncrementStatic(); + + // changes after all init sections: + // y = y + 4 * 2 = y + 8 + } + + static { + x++; + ClassWithStaticField.y++; + ClassWithStaticField.increment(); + invokeIncrementStatic(); + + // changes after clinit section: + // y = y + 3 + // x = x + 1 + } + + void invokeIncrement() { + ClassWithStaticField.increment(); + } + + static void invokeIncrementStatic() { + ClassWithStaticField.increment(); + } + } + + public int implementingInterfaceEnumInDifficultBranch(String s) { + if ("SUCCESS".equalsIgnoreCase(s)) { + return EnumImplementingInterface.x + EnumImplementingInterface.A_INHERITOR.ordinal(); + } else { + return EnumImplementingInterface.y + EnumImplementingInterface.B_INHERITOR.ordinal(); + } + } + + interface AncestorInterface { + int y = 1; + } + + interface InterfaceWithField extends AncestorInterface { + int x = 0; + } + + enum EnumImplementingInterface implements InterfaceWithField { + A_INHERITOR, B_INHERITOR, C_INHERITOR, D_INHERITOR, + E_INHERITOR, F_INHERITOR, G_INHERITOR, H_INHERITOR, + I_INHERITOR, J_INHERITOR, K_INHERITOR, L_INHERITOR, + M_INHERITOR, N_INHERITOR, O_INHERITOR, P_INHERITOR, + } + + boolean affectSystemStaticAndInitEnumFromItAndReturnField() { + int prevStaticValue = ClassWithEnum.staticInt; + staticInt++; + + return OuterStaticUsageEnum.A.y != prevStaticValue; + } + + boolean affectSystemStaticAndInitEnumFromItAndGetItFromEnumFun() { + int prevStaticValue = ClassWithEnum.staticInt; + staticInt++; + + return OuterStaticUsageEnum.A.getOuterStatic() != prevStaticValue; + } + + static int staticInt = 0; + + enum OuterStaticUsageEnum { + A; - int x; + int y; - StatusEnum(int x) { - this.x = x; + OuterStaticUsageEnum() { + y = staticInt; } - public int getX() { - return x; + int getOuterStatic() { + return staticInt; } } } diff --git a/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranches.java b/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranches.java deleted file mode 100644 index 76bfaeb37e..0000000000 --- a/utbot-sample/src/main/java/org/utbot/examples/enums/ClassWithEnumInsideDifficultBranches.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.utbot.examples.enums; - -public class ClassWithEnumInsideDifficultBranches { - public int useEnumInDifficultIf(String s) { - if ("TRYIF".equalsIgnoreCase(s)) { - return foo(ManyConstantsEnum.A); - } else { - return foo(ManyConstantsEnum.B); - } - } - - private int foo(ManyConstantsEnum e) { - if (e.equals(ManyConstantsEnum.A)) { - return 1; - } else { - return 2; - } - } - - @SuppressWarnings("unused") - enum ManyConstantsEnum { - A, B, C, D, E, F, G, H, I, J, K - } -} diff --git a/utbot-sample/src/main/java/org/utbot/examples/exceptions/ExceptionClusteringExamples.java b/utbot-sample/src/main/java/org/utbot/examples/exceptions/ExceptionClusteringExamples.java index 0f8dea29c4..1142a9a685 100644 --- a/utbot-sample/src/main/java/org/utbot/examples/exceptions/ExceptionClusteringExamples.java +++ b/utbot-sample/src/main/java/org/utbot/examples/exceptions/ExceptionClusteringExamples.java @@ -20,7 +20,7 @@ public int differentExceptionsInNestedCall(int i) throws MyCheckedException { } public int sleepingMoreThanDefaultTimeout(int i) throws InterruptedException { - Thread.sleep(500L); + Thread.sleep(1500L); if (i < 0) { throw new RuntimeException(); diff --git a/utbot-sample/src/main/java/org/utbot/examples/objects/SimpleEnum.java b/utbot-sample/src/main/java/org/utbot/examples/objects/SimpleEnum.java deleted file mode 100644 index f8b3ca4163..0000000000 --- a/utbot-sample/src/main/java/org/utbot/examples/objects/SimpleEnum.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.utbot.examples.objects; - -public enum SimpleEnum { - FIRST(1), - SECOND(2); - - private final int code; - - SimpleEnum(int code) { - this.code = code; - } - - static SimpleEnum fromCode(int code) { - for (SimpleEnum value : values()) { - if (value.getCode() == code) { - return value; - } - } - throw new IllegalArgumentException("No enum corresponding to given code: " + code); - } - - private int getCode() { - return code; - } - - static SimpleEnum fromIsFirst(boolean isFirst) { - return isFirst ? FIRST : SECOND; - } - - int publicGetCode() { - return this == FIRST ? 1 : 2; - } -} \ No newline at end of file