Skip to content

Commit 1d930d9

Browse files
committed
Generate parametrized tests when there is no force mocking
1 parent da29a64 commit 1d930d9

File tree

13 files changed

+155
-75
lines changed

13 files changed

+155
-75
lines changed

utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class UtBotSymbolicEngine(
180180

181181
fun attachMockListener(mockListener: MockListener) = mocker.mockListenerController?.attach(mockListener)
182182

183+
fun detachMockListener(mockListener: MockListener) = mocker.mockListenerController?.detach(mockListener)
184+
183185
private val statesForConcreteExecution: MutableList<ExecutionState> = mutableListOf()
184186

185187
private val traverser = Traverser(

utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceMockListener.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.utbot.engine.util.mockListeners
22
import org.utbot.engine.EngineController
33
import org.utbot.engine.MockStrategy
44
import org.utbot.engine.UtMockInfo
5+
import org.utbot.framework.plugin.api.TestCaseGenerator
56
import org.utbot.framework.util.Conflict
67
import org.utbot.framework.util.ConflictTriggers
78

@@ -18,4 +19,13 @@ class ForceMockListener(triggers: ConflictTriggers): MockListener(triggers) {
1819

1920
triggers[Conflict.ForceMockHappened] = true
2021
}
22+
23+
companion object {
24+
fun create(testCaseGenerator: TestCaseGenerator, conflictTriggers: ConflictTriggers) : ForceMockListener {
25+
val listener = ForceMockListener(conflictTriggers)
26+
testCaseGenerator.engineActions.add { engine -> engine.attachMockListener(listener) }
27+
28+
return listener
29+
}
30+
}
2131
}

utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/ForceStaticMockListener.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.utbot.engine.UtMockInfo
66
import org.utbot.engine.UtNewInstanceMockInfo
77
import org.utbot.engine.UtStaticMethodMockInfo
88
import org.utbot.engine.UtStaticObjectMockInfo
9+
import org.utbot.framework.plugin.api.TestCaseGenerator
910
import org.utbot.framework.util.Conflict
1011
import org.utbot.framework.util.ConflictTriggers
1112

@@ -26,4 +27,13 @@ class ForceStaticMockListener(triggers: ConflictTriggers): MockListener(triggers
2627
triggers[Conflict.ForceStaticMockHappened] = true
2728
}
2829
}
30+
31+
companion object {
32+
fun create(testCaseGenerator: TestCaseGenerator, conflictTriggers: ConflictTriggers) : ForceStaticMockListener {
33+
val listener = ForceStaticMockListener(conflictTriggers)
34+
testCaseGenerator.engineActions.add { engine -> engine.attachMockListener(listener) }
35+
36+
return listener
37+
}
38+
}
2939
}

utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListener.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.utbot.engine.util.mockListeners
33
import org.utbot.engine.EngineController
44
import org.utbot.engine.MockStrategy
55
import org.utbot.engine.UtMockInfo
6+
import org.utbot.framework.plugin.api.TestCaseGenerator
67
import org.utbot.framework.util.ConflictTriggers
78

89
/**
@@ -12,4 +13,8 @@ abstract class MockListener(
1213
val triggers: ConflictTriggers
1314
) {
1415
abstract fun onShouldMock(controller: EngineController, strategy: MockStrategy, mockInfo: UtMockInfo)
16+
17+
fun detach(testCaseGenerator: TestCaseGenerator, listener: MockListener) {
18+
testCaseGenerator.engineActions.add { engine -> engine.detachMockListener(listener) }
19+
}
1520
}

utbot-framework/src/main/kotlin/org/utbot/engine/util/mockListeners/MockListenerController.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class MockListenerController(private val controller: EngineController) {
1414
listeners += listener
1515
}
1616

17+
fun detach(listener: MockListener) {
18+
listeners -= listener
19+
}
20+
1721
fun onShouldMock(strategy: MockStrategy, mockInfo: UtMockInfo) {
1822
listeners.map { it.onShouldMock(controller, strategy, mockInfo) }
1923
}

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,11 +1217,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12171217
private val expectedResultVarName = "expectedResult"
12181218
private val expectedErrorVarName = "expectedError"
12191219

1220-
fun createParameterizedTestMethod(testSet: UtMethodTestSet, dataProviderMethodName: String): CgTestMethod? {
1221-
if (testSet.executions.isEmpty()) {
1222-
return null
1223-
}
1224-
1220+
fun createParameterizedTestMethod(testSet: UtMethodTestSet, dataProviderMethodName: String): CgTestMethod {
12251221
//TODO: orientation on generic execution may be misleading, but what is the alternative?
12261222
//may be a heuristic to select a model with minimal number of internal nulls should be used
12271223
val genericExecution = testSet.executions

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal class CgTestClassConstructor(val context: CgContext) :
5252
cgDataProviderMethods.clear()
5353
for (testSet in testSets) {
5454
updateCurrentExecutable(testSet.method)
55-
val currentMethodUnderTestRegions = construct(testSet)
55+
val currentMethodUnderTestRegions = construct(testSet) ?: continue
5656
val executableUnderTestCluster = CgExecutableUnderTestCluster(
5757
"Test suites for executable $currentExecutable",
5858
currentMethodUnderTestRegions
@@ -76,7 +76,11 @@ internal class CgTestClassConstructor(val context: CgContext) :
7676
}
7777
}
7878

79-
private fun construct(testSet: UtMethodTestSet): List<CgRegion<CgMethod>> {
79+
private fun construct(testSet: UtMethodTestSet): List<CgRegion<CgMethod>>? {
80+
if (testSet.executions.isEmpty()) {
81+
return null
82+
}
83+
8084
val (methodUnderTest, executions, _, _, clustersInfo) = testSet
8185
val regions = mutableListOf<CgRegion<CgMethod>>()
8286
val requiredFields = mutableListOf<CgParameterDeclaration>()
@@ -107,17 +111,15 @@ internal class CgTestClassConstructor(val context: CgContext) :
107111
val parameterizedTestMethod =
108112
methodConstructor.createParameterizedTestMethod(testSet, dataProviderMethodName)
109113

110-
if (parameterizedTestMethod != null) {
111-
requiredFields += parameterizedTestMethod.requiredFields
114+
requiredFields += parameterizedTestMethod.requiredFields
112115

113-
cgDataProviderMethods +=
114-
methodConstructor.createParameterizedTestDataProvider(testSet, dataProviderMethodName)
116+
cgDataProviderMethods +=
117+
methodConstructor.createParameterizedTestDataProvider(testSet, dataProviderMethodName)
115118

116-
regions += CgSimpleRegion(
117-
"Parameterized test for method ${methodUnderTest.displayName}",
118-
listOf(parameterizedTestMethod),
119-
)
120-
}
119+
regions += CgSimpleRegion(
120+
"Parameterized test for method ${methodUnderTest.displayName}",
121+
listOf(parameterizedTestMethod),
122+
)
121123
}.onFailure { error -> processFailure(testSet, error) }
122124
}
123125
}

utbot-framework/src/main/kotlin/org/utbot/framework/plugin/api/TestCaseGenerator.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ open class TestCaseGenerator(
117117
executionTimeEstimator: ExecutionTimeEstimator = ExecutionTimeEstimator(utBotGenerationTimeoutInMillis, 1)
118118
): Flow<UtResult> {
119119
val engine = createSymbolicEngine(controller, method, mockStrategy, chosenClassesToMockAlways, executionTimeEstimator)
120+
engineActions.map { engine.apply(it) }
121+
engineActions.clear()
120122
return defaultTestFlow(engine, executionTimeEstimator.userTimeout)
121123
}
122124

utbot-framework/src/test/kotlin/org/utbot/examples/TestSpecificTestCaseGenerator.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import org.utbot.common.runIgnoringCancellationException
77
import org.utbot.engine.EngineController
88
import org.utbot.engine.Mocker
99
import org.utbot.engine.UtBotSymbolicEngine
10+
import org.utbot.engine.util.mockListeners.ForceMockListener
11+
import org.utbot.engine.util.mockListeners.ForceStaticMockListener
1012
import org.utbot.framework.UtSettings
1113
import org.utbot.framework.plugin.api.MockStrategyApi
1214
import org.utbot.framework.plugin.api.TestCaseGenerator
@@ -45,6 +47,10 @@ class TestSpecificTestCaseGenerator(
4547
val mockAlwaysDefaults = Mocker.javaDefaultClasses.mapTo(mutableSetOf()) { it.id }
4648
val defaultTimeEstimator = ExecutionTimeEstimator(UtSettings.utBotGenerationTimeoutInMillis, 1)
4749

50+
val conflictTriggers = TestFrameworkConfiguration.conflictTriggers
51+
val forceMockListener = ForceMockListener.create(this, conflictTriggers)
52+
val forceStaticMockListener = ForceStaticMockListener.create(this, conflictTriggers)
53+
4854
runIgnoringCancellationException {
4955
runBlockingWithCancellationPredicate(isCanceled) {
5056
super
@@ -58,6 +64,9 @@ class TestSpecificTestCaseGenerator(
5864
}
5965
}
6066

67+
forceMockListener.detach(this, forceMockListener)
68+
forceStaticMockListener.detach(this, forceStaticMockListener)
69+
6170
val minimizedExecutions = super.minimizeExecutions(executions)
6271
return UtMethodTestSet(method, minimizedExecutions, jimpleBody(method), errors)
6372
}

utbot-framework/src/test/kotlin/org/utbot/examples/TestUtil.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import org.utbot.framework.plugin.api.MockFramework
1414
import org.utbot.framework.plugin.api.MockStrategyApi
1515
import org.utbot.framework.plugin.api.MockStrategyApi.NO_MOCKS
1616
import org.utbot.framework.plugin.api.MockStrategyApi.OTHER_CLASSES
17+
import org.utbot.framework.util.Conflict
18+
import org.utbot.framework.util.ConflictTriggers
1719

1820

1921
data class TestFrameworkConfiguration(
@@ -28,6 +30,11 @@ data class TestFrameworkConfiguration(
2830
val runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.PASS,
2931
val enableTestsTimeout: Boolean = false // our tests should not fail due to timeout
3032
) {
33+
val isParametrizedAndMocked: Boolean
34+
get() = parametrizedTestSource == ParametrizedTestSource.PARAMETRIZE &&
35+
(mockStrategy != NO_MOCKS ||
36+
conflictTriggers[Conflict.ForceMockHappened] ?: false || conflictTriggers[Conflict.ForceStaticMockHappened] ?: false)
37+
3138
val isDisabled: Boolean
3239
get() = run {
3340
// TODO Any? JIRA:1366
@@ -42,9 +49,6 @@ data class TestFrameworkConfiguration(
4249
// because otherwise the code generator will not create mocks even for mandatory to mock classes
4350
if (forceStaticMocking == ForceStaticMocking.FORCE && staticsMocking == NoStaticMocking) return true
4451

45-
// TODO find if mocks are used during the analysis JIRA:1418
46-
if (parametrizedTestSource == ParametrizedTestSource.PARAMETRIZE) return true
47-
4852
// junit4 doesn't support parametrized tests
4953
if (testFramework == Junit4 && parametrizedTestSource == ParametrizedTestSource.PARAMETRIZE) return true
5054

@@ -53,6 +57,10 @@ data class TestFrameworkConfiguration(
5357

5458
return false
5559
}
60+
61+
companion object Triggers {
62+
val conflictTriggers: ConflictTriggers = ConflictTriggers()
63+
}
5664
}
5765

5866
val allTestFrameworkConfigurations: List<TestFrameworkConfiguration> = run {

0 commit comments

Comments
 (0)