@@ -37,7 +37,6 @@ import org.utbot.framework.codegen.model.tree.CgExecutableCall
3737import org.utbot.framework.codegen.model.tree.CgExpression
3838import org.utbot.framework.codegen.model.tree.CgFieldAccess
3939import org.utbot.framework.codegen.model.tree.CgGetJavaClass
40- import org.utbot.framework.codegen.model.tree.CgIsInstance
4140import org.utbot.framework.codegen.model.tree.CgLiteral
4241import org.utbot.framework.codegen.model.tree.CgMethod
4342import org.utbot.framework.codegen.model.tree.CgMethodCall
@@ -111,9 +110,10 @@ import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation
111110import org.utbot.framework.plugin.api.UtSymbolicExecution
112111import org.utbot.framework.plugin.api.UtTimeoutException
113112import org.utbot.framework.plugin.api.UtVoidModel
113+ import org.utbot.framework.plugin.api.isNotNull
114+ import org.utbot.framework.plugin.api.isNull
114115import org.utbot.framework.plugin.api.onFailure
115116import org.utbot.framework.plugin.api.onSuccess
116- import org.utbot.framework.plugin.api.util.booleanClassId
117117import org.utbot.framework.plugin.api.util.doubleArrayClassId
118118import org.utbot.framework.plugin.api.util.doubleClassId
119119import org.utbot.framework.plugin.api.util.doubleWrapperClassId
@@ -144,7 +144,6 @@ import org.utbot.summary.SummarySentenceConstants.TAB
144144import java.lang.reflect.InvocationTargetException
145145import java.security.AccessControlException
146146import java.lang.reflect.ParameterizedType
147- import kotlin.reflect.jvm.javaType
148147
149148private const val DEEP_EQUALS_MAX_DEPTH = 5 // TODO move it to plugin settings?
150149
@@ -168,6 +167,8 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
168167
169168 private lateinit var methodType: CgTestMethodType
170169
170+ private val fieldsOfExecutionResults = mutableMapOf<Pair <FieldId , Int >, MutableList <UtModel >>()
171+
171172 private fun setupInstrumentation () {
172173 if (currentExecution is UtSymbolicExecution ) {
173174 val execution = currentExecution as UtSymbolicExecution
@@ -445,7 +446,6 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
445446 val expectedExpression = CgNotNullAssertion (expectedVariable)
446447
447448 assertEquality(expectedExpression, actual)
448- println ()
449449 }
450450 }
451451 .onFailure { thisInstance[method](* methodArguments.toTypedArray()).intercepted() }
@@ -537,7 +537,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
537537 doubleDelta
538538 )
539539 expectedModel.value is Boolean -> {
540- when (parameterizedTestSource ) {
540+ when (parametrizedTestSource ) {
541541 ParametrizedTestSource .DO_NOT_PARAMETRIZE ->
542542 if (expectedModel.value as Boolean ) {
543543 assertions[assertTrue](actual)
@@ -842,6 +842,25 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
842842 return
843843 }
844844
845+ when (parametrizedTestSource) {
846+ ParametrizedTestSource .DO_NOT_PARAMETRIZE -> {
847+ traverseField(fieldId, fieldModel, expected, actual, depth, visitedModels)
848+ }
849+
850+ ParametrizedTestSource .PARAMETRIZE -> {
851+ traverseFieldForParametrizedTest(fieldId, fieldModel, expected, actual, depth, visitedModels)
852+ }
853+ }
854+ }
855+
856+ private fun traverseField (
857+ fieldId : FieldId ,
858+ fieldModel : UtModel ,
859+ expected : CgVariable ,
860+ actual : CgVariable ,
861+ depth : Int ,
862+ visitedModels : MutableSet <UtModel >
863+ ) {
845864 // fieldModel is not visited and will be marked in assertDeepEquals call
846865 val fieldName = fieldId.name
847866 var expectedVariable: CgVariable ? = null
@@ -866,6 +885,140 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
866885 emptyLineIfNeeded()
867886 }
868887
888+ private fun traverseFieldForParametrizedTest (
889+ fieldId : FieldId ,
890+ fieldModel : UtModel ,
891+ expected : CgVariable ,
892+ actual : CgVariable ,
893+ depth : Int ,
894+ visitedModels : MutableSet <UtModel >
895+ ) {
896+ val fieldResultModels = fieldsOfExecutionResults[fieldId to depth]
897+ val nullResultModelInExecutions = fieldResultModels?.find { it.isNull() }
898+ val notNullResultModelInExecutions = fieldResultModels?.find { it.isNotNull() }
899+
900+ val hasNullResultModel = nullResultModelInExecutions != null
901+ val hasNotNullResultModel = notNullResultModelInExecutions != null
902+
903+ val needToSubstituteFieldModel = fieldModel is UtNullModel && hasNotNullResultModel
904+
905+ val fieldModelForAssert = if (needToSubstituteFieldModel) notNullResultModelInExecutions!! else fieldModel
906+
907+ // fieldModel is not visited and will be marked in assertDeepEquals call
908+ val fieldName = fieldId.name
909+ var expectedVariable: CgVariable ? = null
910+
911+ val needExpectedDeclaration = needExpectedDeclaration(fieldModelForAssert)
912+ if (needExpectedDeclaration) {
913+ val expectedFieldDeclaration = createDeclarationForFieldFromVariable(fieldId, expected, fieldName)
914+
915+ currentBlock + = expectedFieldDeclaration
916+ expectedVariable = expectedFieldDeclaration.variable
917+ }
918+
919+ val actualFieldDeclaration = createDeclarationForFieldFromVariable(fieldId, actual, fieldName)
920+ currentBlock + = actualFieldDeclaration
921+
922+ if (needExpectedDeclaration && hasNullResultModel) {
923+ ifStatement(
924+ CgEqualTo (expectedVariable!! , nullLiteral()),
925+ trueBranch = { + testFrameworkManager.assertions[testFramework.assertNull](actualFieldDeclaration.variable).toStatement() },
926+ falseBranch = {
927+ assertDeepEquals(
928+ fieldModelForAssert,
929+ expectedVariable,
930+ actualFieldDeclaration.variable,
931+ depth + 1 ,
932+ visitedModels,
933+ )
934+ }
935+ )
936+ } else {
937+ assertDeepEquals(
938+ fieldModelForAssert,
939+ expectedVariable,
940+ actualFieldDeclaration.variable,
941+ depth + 1 ,
942+ visitedModels,
943+ )
944+ }
945+ emptyLineIfNeeded()
946+ }
947+
948+ private fun collectExecutionsResultFields () {
949+ val successfulExecutionsModels = allExecutions
950+ .filter {
951+ it.result is UtExecutionSuccess
952+ }.map {
953+ (it.result as UtExecutionSuccess ).model
954+ }
955+
956+ for (model in successfulExecutionsModels) {
957+ when (model) {
958+ is UtCompositeModel -> {
959+ for ((fieldId, fieldModel) in model.fields) {
960+ collectExecutionsResultFieldsRecursively(fieldId, fieldModel, 0 )
961+ }
962+ }
963+
964+ is UtAssembleModel -> {
965+ model.origin?.let {
966+ for ((fieldId, fieldModel) in it.fields) {
967+ collectExecutionsResultFieldsRecursively(fieldId, fieldModel, 0 )
968+ }
969+ }
970+ }
971+
972+ is UtNullModel ,
973+ is UtPrimitiveModel ,
974+ is UtArrayModel ,
975+ is UtClassRefModel ,
976+ is UtEnumConstantModel ,
977+ is UtVoidModel -> {
978+ // only [UtCompositeModel] and [UtAssembleModel] have fields to traverse
979+ }
980+ }
981+ }
982+ }
983+
984+ private fun collectExecutionsResultFieldsRecursively (
985+ fieldId : FieldId ,
986+ fieldModel : UtModel ,
987+ depth : Int ,
988+ ) {
989+ if (depth >= DEEP_EQUALS_MAX_DEPTH ) {
990+ return
991+ }
992+
993+ val fieldKey = fieldId to depth
994+ fieldsOfExecutionResults.getOrPut(fieldKey) { mutableListOf () } + = fieldModel
995+
996+ when (fieldModel) {
997+ is UtCompositeModel -> {
998+ for ((id, model) in fieldModel.fields) {
999+ collectExecutionsResultFieldsRecursively(id, model, depth + 1 )
1000+ }
1001+ }
1002+
1003+ is UtAssembleModel -> {
1004+ fieldModel.origin?.let {
1005+ for ((id, model) in it.fields) {
1006+ collectExecutionsResultFieldsRecursively(id, model, depth + 1 )
1007+ }
1008+ }
1009+ }
1010+
1011+ is UtNullModel ,
1012+ is UtPrimitiveModel ,
1013+ is UtArrayModel ,
1014+ is UtClassRefModel ,
1015+ is UtEnumConstantModel ,
1016+ is UtVoidModel -> {
1017+ // only [UtCompositeModel] and [UtAssembleModel] have fields to traverse
1018+ }
1019+ }
1020+ }
1021+
8691022 @Suppress(" UNUSED_ANONYMOUS_PARAMETER" )
8701023 private fun createDeclarationForFieldFromVariable (
8711024 fieldId : FieldId ,
@@ -999,7 +1152,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
9991152 }
10001153 expected == nullLiteral() -> testFrameworkManager.assertNull(actual)
10011154 expected is CgLiteral && expected.value is Boolean -> {
1002- when (parameterizedTestSource ) {
1155+ when (parametrizedTestSource ) {
10031156 ParametrizedTestSource .DO_NOT_PARAMETRIZE ->
10041157 testFrameworkManager.assertBoolean(expected.value, actual)
10051158 ParametrizedTestSource .PARAMETRIZE ->
@@ -1054,15 +1207,19 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
10541207 expected : CgValue ,
10551208 actual : CgVariable ,
10561209 ) {
1057- when (parameterizedTestSource ) {
1210+ when (parametrizedTestSource ) {
10581211 ParametrizedTestSource .DO_NOT_PARAMETRIZE -> generateDeepEqualsAssertion(expected, actual)
1059- ParametrizedTestSource .PARAMETRIZE -> when {
1060- actual.type.isPrimitive -> generateDeepEqualsAssertion(expected, actual)
1061- else -> ifStatement(
1062- CgEqualTo (expected, nullLiteral()),
1063- trueBranch = { + testFrameworkManager.assertions[testFramework.assertNull](actual).toStatement() },
1064- falseBranch = { generateDeepEqualsAssertion(expected, actual) }
1065- )
1212+ ParametrizedTestSource .PARAMETRIZE -> {
1213+ collectExecutionsResultFields()
1214+
1215+ when {
1216+ actual.type.isPrimitive -> generateDeepEqualsAssertion(expected, actual)
1217+ else -> ifStatement(
1218+ CgEqualTo (expected, nullLiteral()),
1219+ trueBranch = { + testFrameworkManager.assertions[testFramework.assertNull](actual).toStatement() },
1220+ falseBranch = { generateDeepEqualsAssertion(expected, actual) }
1221+ )
1222+ }
10661223 }
10671224 }
10681225 }
0 commit comments