Skip to content

Commit 11dfe2f

Browse files
Damtevdenis-fokin
authored andcommitted
Removed redundant switch-case in mocks in case of only one branch (#1954)
(cherry picked from commit 7230073)
1 parent 147a33e commit 11dfe2f

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/framework/MockFrameworkManager.kt

+34-15
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import org.utbot.framework.codegen.domain.context.CgContext
2222
import org.utbot.framework.codegen.domain.context.CgContextOwner
2323
import org.utbot.framework.codegen.domain.models.CgAnonymousFunction
2424
import org.utbot.framework.codegen.domain.models.CgAssignment
25-
import org.utbot.framework.codegen.domain.models.CgBreakStatement
2625
import org.utbot.framework.codegen.domain.models.CgConstructorCall
2726
import org.utbot.framework.codegen.domain.models.CgDeclaration
2827
import org.utbot.framework.codegen.domain.models.CgExecutableCall
@@ -232,7 +231,12 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
232231
.instances
233232
.filterIsInstance<UtCompositeModel>()
234233
.filter { it.isMock }
235-
.map { it.mocks }
234+
.map {
235+
// If there are no expected answers for the particular executable
236+
// (this executable is never invoked during the execution, for example),
237+
// we do not need to consider this executable at all.
238+
it.mocks.filterTo(mutableMapOf()) { executableAnswers -> executableAnswers.value.isNotEmpty() }
239+
}
236240

237241
val modelClass = getClassOf(classId)
238242

@@ -248,6 +252,8 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
248252
+mockClassCounter
249253
}
250254

255+
// TODO this behavior diverges with expected by the symbolic engine,
256+
// see https://github.com/UnitTestBot/UTBotJava/issues/1953 for more details
251257
val mockedConstructionDeclaration = CgDeclaration(
252258
MockitoStaticMocking.mockedConstructionClassId,
253259
nameGenerator.variableName(MOCKED_CONSTRUCTION_NAME),
@@ -276,10 +282,10 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
276282
listOf(
277283
CgStatementExecutableCall(
278284
CgMethodCall(
279-
caller = null,
280-
methodId,
281-
matchers.toList()
282-
)
285+
caller = null,
286+
methodId,
287+
matchers.toList()
288+
)
283289
)
284290
)
285291
)
@@ -328,21 +334,29 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
328334
): MockConstructionBlock {
329335
val mockParameter = variableConstructor.declareParameter(
330336
classId,
331-
nameGenerator.variableName(classId.simpleName, isMock = true)
337+
nameGenerator.variableName(
338+
classId,
339+
isMock = true
340+
)
332341
)
333342
val contextParameter = variableConstructor.declareParameter(
334343
mockedConstructionContextClassId,
335344
nameGenerator.variableName("context")
336345
)
337346

338-
val caseLabels = mutableListOf<CgSwitchCaseLabel>()
347+
val mockAnswerStatements = mutableMapOf<Int, List<CgStatement>>()
348+
339349
for ((index, mockWhenAnswers) in mocksWhenAnswers.withIndex()) {
340350
val statements = mutableListOf<CgStatement>()
341351
for ((executable, values) in mockWhenAnswers) {
342352
// For now, all constructors are considered like void methods, but it is proposed to be changed
343353
// for better constructors testing.
344354
if (executable.returnType == voidClassId) continue
345355

356+
require(values.isNotEmpty()) {
357+
"Expected at least one mocked answer for $executable but got 0"
358+
}
359+
346360
when (executable) {
347361
is MethodId -> {
348362
val matchers = mockitoArgumentMatchersFor(executable)
@@ -355,16 +369,21 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
355369
}
356370
}
357371

358-
caseLabels += CgSwitchCaseLabel(CgLiteral(intClassId, index), statements)
372+
mockAnswerStatements[index] = statements
359373
}
360374

361-
val switchCase = CgSwitchCase(mockClassCounter[atomicIntegerGet](), caseLabels)
362-
363-
// If all switch-case labels are empty,
375+
val answerValues = mockAnswerStatements.values
376+
// If we have no more than one branch or all branches are empty,
364377
// it means we do not need this switch and mock counter itself at all.
365-
val mockConstructionBody = if (caseLabels.map { it.statements }.all { it.isEmpty() }) {
366-
emptyList()
378+
val atMostOneBranchOrAllEmpty = answerValues.size <= 1 || answerValues.all { statements -> statements.isEmpty() }
379+
val mockConstructionBody = if (atMostOneBranchOrAllEmpty) {
380+
answerValues.singleOrNull() ?: emptyList()
367381
} else {
382+
val caseLabels = mockAnswerStatements.map { (index, statements) ->
383+
CgSwitchCaseLabel(CgLiteral(intClassId, index), statements)
384+
}
385+
val switchCase = CgSwitchCase(mockClassCounter[atomicIntegerGet](), caseLabels)
386+
368387
listOf(switchCase, CgStatementExecutableCall(mockClassCounter[atomicIntegerGetAndIncrement]()))
369388
}
370389

@@ -376,7 +395,7 @@ private class MockitoStaticMocker(context: CgContext, private val mocker: Object
376395

377396
return MockConstructionBlock(
378397
mockitoClassId[MockitoStaticMocking.mockConstructionMethodId](clazz, answersBlock),
379-
mockConstructionBody.isNotEmpty()
398+
!atMostOneBranchOrAllEmpty
380399
)
381400
}
382401

0 commit comments

Comments
 (0)