Skip to content

Commit f8e75b7

Browse files
authored
Add parametrized test generation for methods without force mocking #591 #596 (#608)
1 parent af1b2b3 commit f8e75b7

File tree

7 files changed

+78
-42
lines changed

7 files changed

+78
-42
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12771277
// this instance
12781278
val thisInstanceModel = genericExecution.stateBefore.thisInstance
12791279
if (thisInstanceModel != null) {
1280-
val type = thisInstanceModel.classId
1280+
val type = wrapTypeIfRequired(thisInstanceModel.classId)
12811281
val thisInstance = CgParameterDeclaration(
12821282
parameter = declareParameter(
12831283
type = type,

utbot-framework/src/main/kotlin/org/utbot/framework/util/TestUtils.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,16 @@ enum class Conflict {
149149
}
150150

151151
class ConflictTriggers(
152-
private val triggers: MutableMap<Conflict, Boolean> = EnumMap<Conflict, Boolean>(Conflict::class.java).withDefault { false }
153-
): MutableMap<Conflict, Boolean> by triggers {
152+
private val triggers: MutableMap<Conflict, Boolean> = EnumMap<Conflict, Boolean>(Conflict::class.java).also { map ->
153+
Conflict.values().forEach { conflict -> map[conflict] = false }
154+
}
155+
) : MutableMap<Conflict, Boolean> by triggers {
154156
val triggered: Boolean
155157
get() = triggers.values.any { it }
158+
159+
fun reset(vararg conflicts: Conflict) {
160+
for (conflict in conflicts) {
161+
triggers[conflict] = false
162+
}
163+
}
156164
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import org.utbot.common.FileUtil
44
import org.utbot.common.packageName
55
import org.utbot.common.withAccessibility
66
import org.utbot.framework.UtSettings
7-
import org.utbot.framework.codegen.TestCodeGeneratorPipeline.Companion.defaultCodegenPipeline
87
import org.utbot.framework.codegen.ClassStages
98
import org.utbot.framework.codegen.CodeGeneration
109
import org.utbot.framework.codegen.ExecutionStatus
@@ -29,6 +28,7 @@ import org.junit.jupiter.api.extension.ExtensionContext
2928
import org.junit.jupiter.api.fail
3029
import org.junit.jupiter.engine.descriptor.ClassTestDescriptor
3130
import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor
31+
import org.utbot.framework.codegen.TestCodeGeneratorPipeline
3232
import java.nio.file.Path
3333

3434
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@@ -119,7 +119,8 @@ abstract class CodeGenerationIntegrationTest(
119119
)
120120
}
121121

122-
language.defaultCodegenPipeline.runClassesCodeGenerationTests(classStages)
122+
val config = TestCodeGeneratorPipeline.defaultTestFrameworkConfiguration(language)
123+
TestCodeGeneratorPipeline(config).runClassesCodeGenerationTests(classStages)
123124
} catch (e: RuntimeException) {
124125
pipelineErrors.add(e.message)
125126
}

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.examples
22

33
import kotlinx.coroutines.flow.collect
4+
import kotlinx.coroutines.launch
45
import mu.KotlinLogging
56
import org.utbot.common.runBlockingWithCancellationPredicate
67
import org.utbot.common.runIgnoringCancellationException
@@ -10,6 +11,8 @@ import org.utbot.engine.UtBotSymbolicEngine
1011
import org.utbot.engine.util.mockListeners.ForceMockListener
1112
import org.utbot.engine.util.mockListeners.ForceStaticMockListener
1213
import org.utbot.framework.UtSettings
14+
import org.utbot.framework.codegen.ParametrizedTestSource
15+
import org.utbot.framework.codegen.TestCodeGeneratorPipeline
1316
import org.utbot.framework.plugin.api.MockStrategyApi
1417
import org.utbot.framework.plugin.api.TestCaseGenerator
1518
import org.utbot.framework.plugin.api.UtError
@@ -47,24 +50,33 @@ class TestSpecificTestCaseGenerator(
4750
val mockAlwaysDefaults = Mocker.javaDefaultClasses.mapTo(mutableSetOf()) { it.id }
4851
val defaultTimeEstimator = ExecutionTimeEstimator(UtSettings.utBotGenerationTimeoutInMillis, 1)
4952

50-
val forceMockListener = ForceMockListener.create(this, conflictTriggers)
51-
val forceStaticMockListener = ForceStaticMockListener.create(this, conflictTriggers)
53+
val config = TestCodeGeneratorPipeline.currentTestFrameworkConfiguration
54+
var forceMockListener: ForceMockListener? = null
55+
var forceStaticMockListener: ForceStaticMockListener? = null
56+
57+
if (config.parametrizedTestSource == ParametrizedTestSource.PARAMETRIZE) {
58+
forceMockListener = ForceMockListener.create(this, conflictTriggers)
59+
forceStaticMockListener = ForceStaticMockListener.create(this, conflictTriggers)
60+
}
5261

5362
runIgnoringCancellationException {
5463
runBlockingWithCancellationPredicate(isCanceled) {
55-
super
56-
.generateAsync(EngineController(), method, mockStrategy, mockAlwaysDefaults, defaultTimeEstimator)
57-
.collect {
58-
when (it) {
59-
is UtExecution -> executions += it
60-
is UtError -> errors.merge(it.description, 1, Int::plus)
64+
val controller = EngineController()
65+
controller.job = launch {
66+
super
67+
.generateAsync(controller, method, mockStrategy, mockAlwaysDefaults, defaultTimeEstimator)
68+
.collect {
69+
when (it) {
70+
is UtExecution -> executions += it
71+
is UtError -> errors.merge(it.description, 1, Int::plus)
72+
}
6173
}
62-
}
74+
}
6375
}
6476
}
6577

66-
forceMockListener.detach(this, forceMockListener)
67-
forceStaticMockListener.detach(this, forceStaticMockListener)
78+
forceMockListener?.detach(this, forceMockListener)
79+
forceStaticMockListener?.detach(this, forceStaticMockListener)
6880

6981
val minimizedExecutions = super.minimizeExecutions(executions)
7082
return UtMethodTestSet(method, minimizedExecutions, jimpleBody(method), errors)

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import kotlin.reflect.KFunction2
3838
import kotlin.reflect.KFunction3
3939
import org.junit.jupiter.api.Assertions.assertTrue
4040
import org.utbot.framework.UtSettings.useFuzzing
41+
import org.utbot.framework.codegen.TestCodeGeneratorPipeline
42+
import org.utbot.framework.util.Conflict
4143

4244
internal abstract class UtModelTestCaseChecker(
4345
testClass: KClass<*>,
@@ -99,6 +101,13 @@ internal abstract class UtModelTestCaseChecker(
99101
"We have errors: ${testSet.errors.entries.map { "${it.value}: ${it.key}" }.prettify()}"
100102
}
101103

104+
// if force mocking took place in parametrized test generation,
105+
// we do not need to process this [testSet]
106+
if (TestCodeGeneratorPipeline.currentTestFrameworkConfiguration.isParametrizedAndMocked) {
107+
conflictTriggers.reset(Conflict.ForceMockHappened, Conflict.ForceStaticMockHappened)
108+
return
109+
}
110+
102111
val executions = testSet.executions
103112
assertTrue(branches(executions.size)) {
104113
"Branch count matcher '$branches' fails for #executions=${executions.size}: ${executions.prettify()}"

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import org.utbot.framework.plugin.api.UtValueExecution
5454
import org.utbot.framework.plugin.api.util.UtContext
5555
import org.utbot.framework.plugin.api.util.executableId
5656
import org.utbot.framework.plugin.api.util.withUtContext
57+
import org.utbot.framework.util.Conflict
5758
import org.utbot.framework.util.toValueTestCase
5859
import org.utbot.summary.summarize
5960
import java.io.File
@@ -2296,6 +2297,13 @@ abstract class UtValueTestCaseChecker(
22962297
walk(utMethod, mockStrategy)
22972298
}
22982299

2300+
// if force mocking took place in parametrized test generation,
2301+
// we do not need to process this [testSet]
2302+
if (TestCodeGeneratorPipeline.currentTestFrameworkConfiguration.isParametrizedAndMocked) {
2303+
conflictTriggers.reset(Conflict.ForceMockHappened, Conflict.ForceStaticMockHappened)
2304+
return
2305+
}
2306+
22992307
if (checkCoverageInCodeGenerationTests) {
23002308
// TODO JIRA:1407
23012309
}
@@ -2350,6 +2358,13 @@ abstract class UtValueTestCaseChecker(
23502358
}"
23512359
}
23522360

2361+
// if force mocking took place in parametrized test generation,
2362+
// we do not need to process this [testSet]
2363+
if (TestCodeGeneratorPipeline.currentTestFrameworkConfiguration.isParametrizedAndMocked) {
2364+
conflictTriggers.reset(Conflict.ForceMockHappened, Conflict.ForceStaticMockHappened)
2365+
return
2366+
}
2367+
23532368
val valueExecutions = valueTestCase.executions
23542369
assertTrue(branches(valueExecutions.size)) {
23552370
"Branch count matcher '$branches' fails for ${valueExecutions.size}: ${valueExecutions.prettify()}"
@@ -2770,10 +2785,14 @@ inline fun <reified T> withSettingsFromTestFrameworkConfiguration(
27702785
): T {
27712786
val substituteStaticsWithSymbolicVariable = UtSettings.substituteStaticsWithSymbolicVariable
27722787
UtSettings.substituteStaticsWithSymbolicVariable = config.resetNonFinalFieldsAfterClinit
2788+
2789+
val previousConfig = TestCodeGeneratorPipeline.currentTestFrameworkConfiguration
2790+
TestCodeGeneratorPipeline.currentTestFrameworkConfiguration = config
27732791
try {
27742792
return block()
27752793
} finally {
27762794
UtSettings.substituteStaticsWithSymbolicVariable = substituteStaticsWithSymbolicVariable
2795+
TestCodeGeneratorPipeline.currentTestFrameworkConfiguration = previousConfig
27772796
}
27782797
}
27792798

utbot-framework/src/test/kotlin/org/utbot/framework/codegen/TestCodeGeneratorPipeline.kt

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,9 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
7373

7474
val codegenLanguage = testFrameworkConfiguration.codegenLanguage
7575
val parametrizedTestSource = testFrameworkConfiguration.parametrizedTestSource
76-
val isParametrizedAndMocked = testFrameworkConfiguration.isParametrizedAndMocked
7776

7877
val testClass = callToCodeGenerator(testSets, classUnderTest)
7978

80-
// clear triggered flags from the current launch in order to get ready for the next possible run
81-
conflictTriggers.clear()
82-
8379
// actual number of the tests in the generated testClass
8480
val generatedMethodsCount = testClass
8581
.lines()
@@ -101,11 +97,8 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
10197
trimmedLine.startsWith(prefix)
10298
}
10399
// expected number of the tests in the generated testClass
104-
// if force mocking took place in parametrized test generation,
105-
// we don't generate tests at all
106100
val expectedNumberOfGeneratedMethods =
107-
if (isParametrizedAndMocked) 0
108-
else when (parametrizedTestSource) {
101+
when (parametrizedTestSource) {
109102
ParametrizedTestSource.DO_NOT_PARAMETRIZE -> testSets.sumOf { it.executions.size }
110103
ParametrizedTestSource.PARAMETRIZE -> testSets.filter { it.executions.isNotEmpty() }.size
111104
}
@@ -242,12 +235,7 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
242235
}
243236
val testClassCustomName = "${classUnderTest.java.simpleName}GeneratedTest"
244237

245-
// if force mocking took place in parametrized test generation,
246-
// we don't generate tests at all by passing empty list instead of test sets
247-
return codeGenerator.generateAsString(
248-
if (testFrameworkConfiguration.isParametrizedAndMocked) listOf() else testSets,
249-
testClassCustomName
250-
)
238+
return codeGenerator.generateAsString(testSets, testClassCustomName)
251239
}
252240

253241
private fun checkPipelinesResults(classesPipelines: List<ClassPipeline>) {
@@ -284,18 +272,17 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
284272
}
285273

286274
companion object {
287-
val CodegenLanguage.defaultCodegenPipeline: TestCodeGeneratorPipeline
288-
get() = TestCodeGeneratorPipeline(
289-
TestFrameworkConfiguration(
290-
testFramework = TestFramework.defaultItem,
291-
codegenLanguage = this,
292-
mockFramework = MockFramework.defaultItem,
293-
mockStrategy = MockStrategyApi.defaultItem,
294-
staticsMocking = StaticsMocking.defaultItem,
295-
parametrizedTestSource = ParametrizedTestSource.defaultItem,
296-
forceStaticMocking = ForceStaticMocking.defaultItem,
297-
)
298-
)
275+
var currentTestFrameworkConfiguration = defaultTestFrameworkConfiguration()
276+
277+
fun defaultTestFrameworkConfiguration(language: CodegenLanguage = CodegenLanguage.JAVA) = TestFrameworkConfiguration(
278+
testFramework = TestFramework.defaultItem,
279+
codegenLanguage = language,
280+
mockFramework = MockFramework.defaultItem,
281+
mockStrategy = MockStrategyApi.defaultItem,
282+
staticsMocking = StaticsMocking.defaultItem,
283+
parametrizedTestSource = ParametrizedTestSource.defaultItem,
284+
forceStaticMocking = ForceStaticMocking.defaultItem,
285+
)
299286

300287
private const val ERROR_REGION_BEGINNING = "///region Errors"
301288
private const val ERROR_REGION_END = "///endregion"

0 commit comments

Comments
 (0)