Skip to content

Commit f0095ab

Browse files
Use summaries in ContestEstimator (#1661)
Support symbolic executions in ContestEstimator Co-authored-by: Andrey Tarbeev
1 parent 345580e commit f0095ab

File tree

9 files changed

+121
-24
lines changed

9 files changed

+121
-24
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,9 +60,12 @@ 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.minimization.minimizeExecutions
6566
import org.utbot.framework.plugin.api.util.isSynthetic
67+
import org.utbot.framework.util.jimpleBody
68+
import org.utbot.summary.summarize
6669

6770
internal const val junitVersion = 4
6871
private val logger = KotlinLogging.logger {}
@@ -161,7 +164,7 @@ fun setOptions() {
161164
UtSettings.classfilesCanChange = false
162165
// We need to use assemble model generator to increase readability
163166
UtSettings.useAssembleModelGenerator = true
164-
UtSettings.enableSummariesGeneration = false
167+
UtSettings.summaryGenerationType = SummariesGenerationType.LIGHT
165168
UtSettings.preferredCexOption = false
166169
UtSettings.warmupConcreteExecution = true
167170
UtSettings.testMinimizationStrategyType = TestSelectionStrategyType.COVERAGE_STRATEGY
@@ -393,7 +396,10 @@ fun runGeneration(
393396
}
394397
cancellator.cancel()
395398

396-
val testSets = testsByMethod.map { (method, executions) -> UtMethodTestSet(method, minimizeExecutions(executions)) }
399+
val testSets = testsByMethod.map { (method, executions) ->
400+
UtMethodTestSet(method, minimizeExecutions(executions), jimpleBody(method))
401+
.summarize(cut.classfileDir.toPath())
402+
}
397403

398404
logger.info().bracket("Flushing tests for [${cut.simpleName}] on disk") {
399405
writeTestClass(cut, codeGenerator.generateAsString(testSets))

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

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

33
import com.github.javaparser.ast.body.MethodDeclaration
4-
import org.utbot.framework.UtSettings
54
import org.utbot.framework.plugin.api.UtClusterInfo
65
import org.utbot.framework.plugin.api.UtSymbolicExecution
76
import org.utbot.framework.plugin.api.UtExecutionCluster
@@ -18,12 +17,15 @@ import java.io.File
1817
import java.nio.file.Path
1918
import java.nio.file.Paths
2019
import mu.KotlinLogging
20+
import org.utbot.framework.SummariesGenerationType
2121
import org.utbot.framework.UtSettings.enableClusterCommentsGeneration
2222
import org.utbot.framework.UtSettings.enableJavaDocGeneration
2323
import org.utbot.framework.UtSettings.useDisplayNameArrowStyle
2424
import org.utbot.framework.UtSettings.enableDisplayNameGeneration
2525
import org.utbot.framework.UtSettings.enableTestNamesGeneration
26+
import org.utbot.framework.UtSettings.summaryGenerationType
2627
import org.utbot.framework.UtSettings.useCustomJavaDocTags
28+
import org.utbot.framework.plugin.api.util.isConstructor
2729
import org.utbot.framework.plugin.api.util.jClass
2830
import org.utbot.fuzzer.FuzzedMethodDescription
2931
import org.utbot.fuzzer.FuzzedValue
@@ -36,11 +38,18 @@ import soot.SootMethod
3638
private val logger = KotlinLogging.logger {}
3739

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

4143
return try {
4244
makeDiverseExecutions(this)
43-
val invokeDescriptions = invokeDescriptions(this, searchDirectory)
45+
46+
// HACK: we avoid calling [invokeDescriptions] method to save time, it is useless in Contest
47+
val invokeDescriptions = when (summaryGenerationType) {
48+
SummariesGenerationType.FULL -> invokeDescriptions(this, searchDirectory)
49+
SummariesGenerationType.LIGHT,
50+
SummariesGenerationType.NONE -> emptyList()
51+
}
52+
4453
// every cluster has summary and list of executions
4554
val executionClusters = Summarization(sourceFile, invokeDescriptions).fillSummaries(this)
4655
val updatedExecutions = executionClusters.flatMap { it.executions }
@@ -83,9 +92,18 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
8392

8493
val executionClusters = mutableListOf<UtExecutionCluster>()
8594

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

90108
return if (enableClusterCommentsGeneration && executionClusters.size > 0)
91109
executionClusters
@@ -210,6 +228,53 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
210228
return clustersToReturn.toList()
211229
}
212230

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