Skip to content

Commit 0183418

Browse files
sofurihafeEgorkaKulikov
authored andcommitted
Support symbolic executions in ContestEstimator
1 parent e345e30 commit 0183418

File tree

9 files changed

+122
-23
lines changed

9 files changed

+122
-23
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS
134134
/**
135135
* Enable the Summarization module to generate summaries for methods under test.
136136
*
137-
* Note: if it is false, all the execution for a particular method will be stored at the same nameless region.
137+
* Note: if it is [SummariesGenerationType.NONE],
138+
* all the execution for a particular method will be stored at the same nameless region.
138139
*/
139-
var enableSummariesGeneration by getBooleanProperty(true)
140+
var summaryGenerationType by getEnumProperty(SummariesGenerationType.FULL)
140141

141142
/**
142143
* If True test comments will be generated.
@@ -632,3 +633,23 @@ enum class MLPredictorType {
632633
*/
633634
LINREG
634635
}
636+
637+
/**
638+
* Enum to describe how we analyze code to obtain summaries.
639+
*/
640+
enum class SummariesGenerationType {
641+
/**
642+
* All possible analysis actions are taken
643+
*/
644+
FULL,
645+
646+
/**
647+
* Analysis actions based on sources are NOT taken
648+
*/
649+
LIGHT,
650+
651+
/**
652+
* No summaries are generated
653+
*/
654+
NONE,
655+
}

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ object UtTestsDialogProcessor {
141141

142142
UtSettings.concreteExecutionTimeoutInInstrumentedProcess = model.hangingTestsTimeout.timeoutMs
143143
UtSettings.useCustomJavaDocTags = model.commentStyle == JavaDocCommentStyle.CUSTOM_JAVADOC_TAGS
144-
UtSettings.enableSummariesGeneration = model.enableSummariesGeneration
144+
UtSettings.summaryGenerationType = model.summariesGenerationType
145145

146146
fun now() = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"))
147147

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/models/GenerateTestsModel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.intellij.psi.PsiClass
1616
import com.intellij.psi.PsiJavaFile
1717
import com.intellij.refactoring.util.classMembers.MemberInfo
1818
import org.jetbrains.kotlin.psi.KtFile
19+
import org.utbot.framework.SummariesGenerationType
1920
import org.utbot.framework.UtSettings
2021
import org.utbot.framework.plugin.api.JavaDocCommentStyle
2122
import org.utbot.framework.util.ConflictTriggers
@@ -55,7 +56,7 @@ class GenerateTestsModel(
5556
val conflictTriggers: ConflictTriggers = ConflictTriggers()
5657

5758
var runGeneratedTestsWithCoverage : Boolean = false
58-
var enableSummariesGeneration : Boolean = UtSettings.enableSummariesGeneration
59+
var summariesGenerationType : SummariesGenerationType = UtSettings.summaryGenerationType
5960
}
6061

6162
val PsiClass.packageName: String

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/Settings.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import org.utbot.intellij.plugin.models.GenerateTestsModel
3636
import java.util.concurrent.CompletableFuture
3737
import kotlin.reflect.KClass
3838
import org.utbot.common.isWindows
39+
import org.utbot.framework.SummariesGenerationType
3940
import org.utbot.framework.plugin.api.isSummarizationCompatible
4041

4142
@State(
@@ -63,7 +64,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
6364
var fuzzingValue: Double = 0.05,
6465
var runGeneratedTestsWithCoverage: Boolean = false,
6566
var commentStyle: JavaDocCommentStyle = JavaDocCommentStyle.defaultItem,
66-
var enableSummariesGeneration: Boolean = UtSettings.enableSummariesGeneration,
67+
var summariesGenerationType: SummariesGenerationType = UtSettings.summaryGenerationType,
6768
var enableExperimentalLanguagesSupport: Boolean = false,
6869
) {
6970
constructor(model: GenerateTestsModel) : this(
@@ -82,7 +83,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
8283
fuzzingValue = model.fuzzingValue,
8384
runGeneratedTestsWithCoverage = model.runGeneratedTestsWithCoverage,
8485
commentStyle = model.commentStyle,
85-
enableSummariesGeneration = model.enableSummariesGeneration
86+
summariesGenerationType = model.summariesGenerationType
8687
)
8788

8889
override fun equals(other: Any?): Boolean {
@@ -107,7 +108,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
107108
if (fuzzingValue != other.fuzzingValue) return false
108109
if (runGeneratedTestsWithCoverage != other.runGeneratedTestsWithCoverage) return false
109110
if (commentStyle != other.commentStyle) return false
110-
if (enableSummariesGeneration != other.enableSummariesGeneration) return false
111+
if (summariesGenerationType != other.summariesGenerationType) return false
111112

112113
return true
113114
}
@@ -127,7 +128,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
127128
result = 31 * result + classesToMockAlways.contentHashCode()
128129
result = 31 * result + fuzzingValue.hashCode()
129130
result = 31 * result + if (runGeneratedTestsWithCoverage) 1 else 0
130-
result = 31 * result + if (enableSummariesGeneration) 1 else 0
131+
result = 31 * result + summariesGenerationType.hashCode()
131132

132133
return result
133134
}
@@ -173,7 +174,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
173174
}
174175
var runGeneratedTestsWithCoverage = state.runGeneratedTestsWithCoverage
175176

176-
var enableSummariesGeneration = state.enableSummariesGeneration
177+
var enableSummariesGeneration = state.summariesGenerationType
177178

178179
fun setClassesToMockAlways(classesToMockAlways: List<String>) {
179180
state.classesToMockAlways = classesToMockAlways.distinct().toTypedArray()
@@ -209,7 +210,7 @@ class Settings(val project: Project) : PersistentStateComponent<Settings.State>
209210
override fun loadState(state: State) {
210211
this.state = state
211212
if (!state.codegenLanguage.isSummarizationCompatible()) {
212-
this.state.enableSummariesGeneration = false
213+
this.state.summariesGenerationType = SummariesGenerationType.NONE
213214
}
214215
}
215216

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/settings/SettingsWindow.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.intellij.ui.layout.withValueBinding
1818
import com.intellij.util.castSafelyTo
1919
import com.intellij.util.ui.UIUtil
2020
import com.intellij.util.ui.components.BorderLayoutPanel
21+
import org.utbot.framework.SummariesGenerationType
2122
import org.utbot.framework.UtSettings
2223
import org.utbot.framework.codegen.domain.ForceStaticMocking
2324
import org.utbot.framework.codegen.domain.HangingTestsTimeout
@@ -138,13 +139,15 @@ class SettingsWindow(val project: Project) {
138139
cell {
139140
enableSummarizationGenerationCheckBox = checkBox("Enable Summaries Generation")
140141
.onApply {
141-
settings.state.enableSummariesGeneration = enableSummarizationGenerationCheckBox.isSelected
142+
settings.state.summariesGenerationType =
143+
if (enableSummarizationGenerationCheckBox.isSelected) SummariesGenerationType.FULL else SummariesGenerationType.NONE
142144
}
143145
.onReset {
144-
enableSummarizationGenerationCheckBox.isSelected = settings.state.enableSummariesGeneration
146+
enableSummarizationGenerationCheckBox.isSelected =
147+
settings.state.summariesGenerationType != SummariesGenerationType.NONE
145148
}
146149
.onIsModified {
147-
enableSummarizationGenerationCheckBox.isSelected xor settings.state.enableSummariesGeneration
150+
enableSummarizationGenerationCheckBox.isSelected xor (settings.state.summariesGenerationType != SummariesGenerationType.NONE)
148151
}
149152
.enableIf(codegenLanguageCombo.selectedValueMatches(CodegenLanguage?::isSummarizationCompatible))
150153
.component

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FILE_CONTENT
116116
import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FOLDER
117117
import org.utbot.framework.plugin.api.utils.MOCKITO_MOCKMAKER_FILE_NAME
118118
import org.utbot.framework.util.Conflict
119-
import org.utbot.intellij.plugin.generator.UtTestsDialogProcessor
120119
import org.utbot.intellij.plugin.models.GenerateTestsModel
121120
import org.utbot.intellij.plugin.models.id
122121
import org.utbot.intellij.plugin.models.jUnit4LibraryDescriptor
@@ -530,7 +529,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
530529
model.chosenClassesToMockAlways = chosenClassesToMockAlways()
531530
model.fuzzingValue = fuzzingValue
532531
model.commentStyle = javaDocCommentStyle
533-
model.enableSummariesGeneration = state.enableSummariesGeneration
532+
model.summariesGenerationType = state.summariesGenerationType
534533
UtSettings.treatOverflowAsError = treatOverflowAsError == TreatOverflowAsError.AS_ERROR
535534
}
536535

utbot-junit-contest/src/main/kotlin/org/utbot/contest/Contest.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ import kotlinx.coroutines.newSingleThreadContext
6060
import kotlinx.coroutines.runBlocking
6161
import kotlinx.coroutines.withTimeoutOrNull
6262
import kotlinx.coroutines.yield
63+
import org.utbot.framework.SummariesGenerationType
6364
import org.utbot.framework.codegen.services.language.CgLanguageAssistant
6465
import org.utbot.framework.plugin.api.util.isSynthetic
66+
import org.utbot.framework.util.jimpleBody
67+
import org.utbot.summary.summarize
6568

6669
internal const val junitVersion = 4
6770
private val logger = KotlinLogging.logger {}
@@ -160,7 +163,7 @@ fun setOptions() {
160163
UtSettings.classfilesCanChange = false
161164
// We need to use assemble model generator to increase readability
162165
UtSettings.useAssembleModelGenerator = true
163-
UtSettings.enableSummariesGeneration = false
166+
UtSettings.summaryGenerationType = SummariesGenerationType.LIGHT
164167
UtSettings.preferredCexOption = false
165168
UtSettings.warmupConcreteExecution = true
166169
UtSettings.testMinimizationStrategyType = TestSelectionStrategyType.COVERAGE_STRATEGY
@@ -341,7 +344,10 @@ fun runGeneration(
341344
statsForClass.testedClassNames.add(className)
342345

343346
//TODO: it is a strange hack to create fake test case for one [UtResult]
344-
testSets.add(UtMethodTestSet(method, listOf(result)))
347+
testSets.add(
348+
UtMethodTestSet(method, listOf(result), jimpleBody(method))
349+
.summarize(cut.classfileDir.toPath())
350+
)
345351
} catch (e: Throwable) {
346352
//Here we need isolation
347353
logger.error(e) { "Code generation failed" }

utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ import java.io.File
1818
import java.nio.file.Path
1919
import java.nio.file.Paths
2020
import mu.KotlinLogging
21+
import org.utbot.framework.SummariesGenerationType
2122
import org.utbot.framework.UtSettings.enableClusterCommentsGeneration
2223
import org.utbot.framework.UtSettings.enableJavaDocGeneration
2324
import org.utbot.framework.UtSettings.useDisplayNameArrowStyle
2425
import org.utbot.framework.UtSettings.enableDisplayNameGeneration
2526
import org.utbot.framework.UtSettings.enableTestNamesGeneration
27+
import org.utbot.framework.UtSettings.summaryGenerationType
2628
import org.utbot.framework.UtSettings.useCustomJavaDocTags
29+
import org.utbot.framework.plugin.api.util.isConstructor
2730
import org.utbot.framework.plugin.api.util.jClass
2831
import org.utbot.fuzzer.FuzzedMethodDescription
2932
import org.utbot.fuzzer.FuzzedValue
@@ -36,11 +39,18 @@ import soot.SootMethod
3639
private val logger = KotlinLogging.logger {}
3740

3841
fun UtMethodTestSet.summarize(sourceFile: File?, searchDirectory: Path = Paths.get("")): UtMethodTestSet {
39-
if (!UtSettings.enableSummariesGeneration) return this
42+
if (summaryGenerationType == SummariesGenerationType.NONE) return this
4043

4144
return try {
4245
makeDiverseExecutions(this)
43-
val invokeDescriptions = invokeDescriptions(this, searchDirectory)
46+
47+
// HACK: we avoid calling [invokeDescriptions] method to save time, it is useless in Contest
48+
val invokeDescriptions = when (summaryGenerationType) {
49+
SummariesGenerationType.FULL -> invokeDescriptions(this, searchDirectory)
50+
SummariesGenerationType.LIGHT,
51+
SummariesGenerationType.NONE -> emptyList()
52+
}
53+
4454
// every cluster has summary and list of executions
4555
val executionClusters = Summarization(sourceFile, invokeDescriptions).fillSummaries(this)
4656
val updatedExecutions = executionClusters.flatMap { it.executions }
@@ -55,6 +65,7 @@ fun UtMethodTestSet.summarize(sourceFile: File?, searchDirectory: Path = Paths.g
5565
executions = updatedExecutions,
5666
clustersInfo = clustersInfo
5767
) // TODO: looks weird and don't create the real copy
68+
5869
} catch (e: Throwable) {
5970
logger.info(e) { "Summary generation error: ${e.message}" }
6071
this
@@ -83,9 +94,18 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
8394

8495
val executionClusters = mutableListOf<UtExecutionCluster>()
8596

86-
executionClusters += generateSummariesForTestsWithNonEmptyPathsProducedBySymbolicExecutor(testSet)
87-
executionClusters += generateSummariesForTestsProducedByFuzzer(testSet)
88-
executionClusters += generateSummariesForTestsWithEmptyPathsProducedBySymbolicExecutor(testSet)
97+
when (summaryGenerationType) {
98+
SummariesGenerationType.FULL -> {
99+
executionClusters += generateSummariesForTestsWithNonEmptyPathsProducedBySymbolicExecutor(testSet)
100+
executionClusters += generateSummariesForTestsProducedByFuzzer(testSet)
101+
executionClusters += generateSummariesForTestsWithEmptyPathsProducedBySymbolicExecutor(testSet)
102+
}
103+
SummariesGenerationType.LIGHT -> {
104+
executionClusters += generateSummariesForTestsProducedBySymbolicExecutorInContestEstimator(testSet)
105+
executionClusters += generateSummariesForTestsProducedByFuzzer(testSet)
106+
}
107+
SummariesGenerationType.NONE -> error("We must not fill summaries if SummariesGenerationType is NONE")
108+
}
89109

90110
return if (enableClusterCommentsGeneration && executionClusters.size > 0)
91111
executionClusters
@@ -210,6 +230,53 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
210230
return clustersToReturn.toList()
211231
}
212232

233+
private fun generateSummariesForTestsProducedBySymbolicExecutorInContestEstimator(
234+
testSet: UtMethodTestSet
235+
) : List<UtExecutionCluster> {
236+
val clustersToReturn: MutableList<UtExecutionCluster> = mutableListOf()
237+
238+
val testSetWithFuzzedExecutions = prepareTestSetForByteCodeAnalysis(testSet)
239+
val executions = testSetWithFuzzedExecutions.executions as List<UtSymbolicExecution>
240+
241+
if (executions.isNotEmpty()) {
242+
executions.forEach { utExecution ->
243+
244+
val nameSuggester = sequenceOf(ModelBasedNameSuggester(), MethodBasedNameSuggester())
245+
val testMethodName = try {
246+
nameSuggester.flatMap {
247+
val executableId = testSet.method
248+
val description = FuzzedMethodDescription(executableId).apply {
249+
compilableName = if (!executableId.isConstructor) executableId.name else null
250+
}
251+
it.suggest(
252+
description,
253+
utExecution.stateBefore.parameters.map { value -> FuzzedValue(value) },
254+
utExecution.result
255+
)
256+
}.firstOrNull()
257+
} catch (t: Throwable) {
258+
logger.error(t) { "Cannot create suggested test name for $utExecution" }
259+
null
260+
}
261+
utExecution.testMethodName = testMethodName?.testName
262+
utExecution.displayName = testMethodName?.displayName
263+
utExecution.summary = testMethodName?.javaDoc
264+
}
265+
266+
val clusteredExecutions = groupFuzzedExecutions(testSetWithFuzzedExecutions)
267+
clusteredExecutions.forEach {
268+
clustersToReturn.add(
269+
UtExecutionCluster(
270+
UtClusterInfo(it.header),
271+
it.executions
272+
)
273+
)
274+
}
275+
}
276+
277+
return clustersToReturn.toList()
278+
}
279+
213280
private fun generateSummariesForTestsProducedByFuzzer(
214281
testSet: UtMethodTestSet
215282
): List<UtExecutionCluster> {

utbot-testing/src/main/kotlin/org/utbot/testing/UtValueTestCaseChecker.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.utbot.common.FileUtil.clearTempDirectory
88
import org.utbot.common.FileUtil.findPathToClassFiles
99
import org.utbot.common.FileUtil.locateClass
1010
import org.utbot.engine.prettify
11+
import org.utbot.framework.SummariesGenerationType
1112
import org.utbot.framework.UtSettings
1213
import org.utbot.framework.UtSettings.daysLimitForTempFiles
1314
import org.utbot.framework.UtSettings.testDisplayName
@@ -87,7 +88,7 @@ abstract class UtValueTestCaseChecker(
8788
UtSettings.saveRemainingStatesForConcreteExecution = false
8889
UtSettings.useFuzzing = false
8990
UtSettings.useCustomJavaDocTags = false
90-
UtSettings.enableSummariesGeneration = true
91+
UtSettings.summaryGenerationType = SummariesGenerationType.FULL
9192
}
9293

9394
// checks paramsBefore and result

0 commit comments

Comments
 (0)