Skip to content

Commit c512981

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

File tree

12 files changed

+104
-31
lines changed

12 files changed

+104
-31
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/TestUtil.kt

Lines changed: 8 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,12 @@ 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 conflictTriggers: ConflictTriggers = ConflictTriggers()
34+
val isParametrizedAndMocked: Boolean
35+
get() = parametrizedTestSource == ParametrizedTestSource.PARAMETRIZE &&
36+
(mockStrategy != NO_MOCKS ||
37+
conflictTriggers[Conflict.ForceMockHappened] ?: false || conflictTriggers[Conflict.ForceStaticMockHappened] ?: false)
38+
3139
val isDisabled: Boolean
3240
get() = run {
3341
// TODO Any? JIRA:1366
@@ -42,9 +50,6 @@ data class TestFrameworkConfiguration(
4250
// because otherwise the code generator will not create mocks even for mandatory to mock classes
4351
if (forceStaticMocking == ForceStaticMocking.FORCE && staticsMocking == NoStaticMocking) return true
4452

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

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import org.utbot.common.FileUtil.clearTempDirectory
99
import org.utbot.common.FileUtil.findPathToClassFiles
1010
import org.utbot.common.FileUtil.locateClass
1111
import org.utbot.engine.prettify
12+
import org.utbot.engine.util.mockListeners.ForceMockListener
13+
import org.utbot.engine.util.mockListeners.ForceStaticMockListener
1214
import org.utbot.framework.PathSelectorType
1315
import org.utbot.framework.TestSelectionStrategyType
1416
import org.utbot.framework.UtSettings
@@ -80,6 +82,7 @@ abstract class UtValueTestCaseChecker(
8082
) : CodeGenerationIntegrationTest(testClass, testCodeGeneration, languagePipelines) {
8183
// contains already analyzed by the engine methods
8284
private val analyzedMethods: MutableMap<MethodWithMockStrategy, MethodResult> = mutableMapOf()
85+
private var currentTestFrameworkConfiguration: TestFrameworkConfiguration? = null
8386

8487
val searchDirectory: Path = Paths.get("../utbot-sample/src/main/java")
8588

@@ -2293,6 +2296,7 @@ abstract class UtValueTestCaseChecker(
22932296
MethodWithMockStrategy(utMethod, mockStrategy, resetNonFinalFieldsAfterClinit)
22942297

22952298
val (testSet, coverage) = analyzedMethods.getOrPut(methodWithStrategy) {
2299+
currentTestFrameworkConfiguration = testFrameworkConfiguration
22962300
walk(utMethod, mockStrategy)
22972301
}
22982302

@@ -2500,6 +2504,20 @@ abstract class UtValueTestCaseChecker(
25002504
System.getProperty("java.class.path")
25012505
)
25022506
}
2507+
2508+
val conflictTriggers = currentTestFrameworkConfiguration?.conflictTriggers
2509+
if (conflictTriggers != null) {
2510+
val forceMockListener = ForceMockListener.create(testCaseGenerator, conflictTriggers)
2511+
val forceStaticMockListener = ForceStaticMockListener.create(testCaseGenerator, conflictTriggers)
2512+
2513+
val testSet = testCaseGenerator.generate(method, mockStrategy)
2514+
2515+
forceMockListener.detach(testCaseGenerator, forceMockListener)
2516+
forceStaticMockListener.detach(testCaseGenerator, forceStaticMockListener)
2517+
2518+
return testSet
2519+
}
2520+
25032521
return testCaseGenerator.generate(method, mockStrategy)
25042522
}
25052523

0 commit comments

Comments
 (0)