diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt index 2ea9dd8ada..e12d0b7d47 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt @@ -22,7 +22,6 @@ import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.context.CgContextOwner import org.utbot.framework.codegen.domain.models.CgAnonymousFunction import org.utbot.framework.codegen.domain.models.CgAssignment -import org.utbot.framework.codegen.domain.models.CgBreakStatement import org.utbot.framework.codegen.domain.models.CgConstructorCall import org.utbot.framework.codegen.domain.models.CgDeclaration import org.utbot.framework.codegen.domain.models.CgExecutableCall @@ -232,7 +231,12 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object .instances .filterIsInstance() .filter { it.isMock } - .map { it.mocks } + .map { + // If there are no expected answers for the particular executable + // (this executable is never invoked during the execution, for example), + // we do not need to consider this executable at all. + it.mocks.filterTo(mutableMapOf()) { executableAnswers -> executableAnswers.value.isNotEmpty() } + } val modelClass = getClassOf(classId) @@ -248,6 +252,8 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object +mockClassCounter } + // TODO this behavior diverges with expected by the symbolic engine, + // see https://github.com/UnitTestBot/UTBotJava/issues/1953 for more details val mockedConstructionDeclaration = CgDeclaration( MockitoStaticMocking.mockedConstructionClassId, nameGenerator.variableName(MOCKED_CONSTRUCTION_NAME), @@ -276,10 +282,10 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object listOf( CgStatementExecutableCall( CgMethodCall( - caller = null, - methodId, - matchers.toList() - ) + caller = null, + methodId, + matchers.toList() + ) ) ) ) @@ -328,14 +334,18 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object ): MockConstructionBlock { val mockParameter = variableConstructor.declareParameter( classId, - nameGenerator.variableName(classId.simpleName, isMock = true) + nameGenerator.variableName( + classId, + isMock = true + ) ) val contextParameter = variableConstructor.declareParameter( mockedConstructionContextClassId, nameGenerator.variableName("context") ) - val caseLabels = mutableListOf() + val mockAnswerStatements = mutableMapOf>() + for ((index, mockWhenAnswers) in mocksWhenAnswers.withIndex()) { val statements = mutableListOf() for ((executable, values) in mockWhenAnswers) { @@ -343,6 +353,10 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object // for better constructors testing. if (executable.returnType == voidClassId) continue + require(values.isNotEmpty()) { + "Expected at least one mocked answer for $executable but got 0" + } + when (executable) { is MethodId -> { val matchers = mockitoArgumentMatchersFor(executable) @@ -355,16 +369,21 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object } } - caseLabels += CgSwitchCaseLabel(CgLiteral(intClassId, index), statements) + mockAnswerStatements[index] = statements } - val switchCase = CgSwitchCase(mockClassCounter[atomicIntegerGet](), caseLabels) - - // If all switch-case labels are empty, + val answerValues = mockAnswerStatements.values + // If we have no more than one branch or all branches are empty, // it means we do not need this switch and mock counter itself at all. - val mockConstructionBody = if (caseLabels.map { it.statements }.all { it.isEmpty() }) { - emptyList() + val atMostOneBranchOrAllEmpty = answerValues.size <= 1 || answerValues.all { statements -> statements.isEmpty() } + val mockConstructionBody = if (atMostOneBranchOrAllEmpty) { + answerValues.singleOrNull() ?: emptyList() } else { + val caseLabels = mockAnswerStatements.map { (index, statements) -> + CgSwitchCaseLabel(CgLiteral(intClassId, index), statements) + } + val switchCase = CgSwitchCase(mockClassCounter[atomicIntegerGet](), caseLabels) + listOf(switchCase, CgStatementExecutableCall(mockClassCounter[atomicIntegerGetAndIncrement]())) } @@ -376,7 +395,7 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object return MockConstructionBlock( mockitoClassId[MockitoStaticMocking.mockConstructionMethodId](clazz, answersBlock), - mockConstructionBody.isNotEmpty() + !atMostOneBranchOrAllEmpty ) }