Skip to content

Add summarization for usvm-sbft #2682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ fun setOptions() {
// We need to use assemble model generator to increase readability
UtSettings.useAssembleModelGenerator = true
UtSettings.summaryGenerationType = SummariesGenerationType.LIGHT
UtSettings.enableTestNamesGeneration = true
UtSettings.enableDisplayNameGeneration = false
UtSettings.enableJavaDocGeneration = true
UtSettings.preferredCexOption = false
UtSettings.warmupConcreteExecution = true
UtSettings.testMinimizationStrategyType = TestSelectionStrategyType.COVERAGE_STRATEGY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import org.utbot.framework.plugin.api.util.method
import org.utbot.framework.plugin.services.JdkInfoService
import org.utbot.fuzzer.ReferencePreservingIntIdGenerator
import org.utbot.fuzzer.UtFuzzedExecution
import org.utbot.summary.summarizeAll
import org.utbot.summary.usvm.summarizeAll
import java.io.File
import java.net.URLClassLoader
import java.util.*
Expand Down Expand Up @@ -265,7 +265,7 @@ fun runUsvmGeneration(

val testSets = testsByMethod.map { (method, executions) ->
UtMethodTestSet(method, minimizeExecutions(executions), jimpleBody = null)
}.summarizeAll(cut.classfileDir.toPath(), sourceFile = null)
}.summarizeAll()

logger.info().measureTime({ "Flushing tests for [${cut.simpleName}] on disk" }) {
writeTestClass(cut, codeGenerator.generateAsString(testSets))
Expand Down
18 changes: 13 additions & 5 deletions utbot-summary/src/main/kotlin/org/utbot/summary/Summarization.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private fun UtMethodTestSet.summarizeOne(searchDirectory: Path, sourceFile: File
) // TODO: looks weird and don't create the real copy
}

class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDescription>) {
open class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDescription>) {
private val tagGenerator = TagGenerator()
private val jimpleBodyAnalysis = ExecutionStructureAnalysis()

Expand Down Expand Up @@ -239,10 +239,7 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
descriptionSource: MethodDescriptionSource = MethodDescriptionSource.FUZZER
): List<UtExecutionCluster> {
val clustersToReturn: MutableList<UtExecutionCluster> = mutableListOf()
val methodTestSet = when (descriptionSource) {
MethodDescriptionSource.FUZZER -> prepareTestSetWithFuzzedExecutions(testSet)
MethodDescriptionSource.SYMBOLIC -> prepareTestSetForByteCodeAnalysis(testSet)
}
val methodTestSet = prepareMethodTestSet(testSet, descriptionSource)

if (methodTestSet.executions.isNotEmpty()) {
methodTestSet.executions.forEach { utExecution ->
Expand All @@ -263,7 +260,11 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
MethodDescriptionSource.SYMBOLIC -> {
val executableId = testSet.method
val description = FuzzedMethodDescription(executableId).apply {
packageName = executableId.classId.packageName
className = executableId.classId.simpleName
compilableName = if (!executableId.isConstructor) executableId.name else null
canonicalName = executableId.classId.canonicalName
isNested = executableId.classId.isNested
}
it.suggest(
description,
Expand Down Expand Up @@ -309,6 +310,13 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
return clustersToReturn.toList()
}

open fun prepareMethodTestSet(testSet: UtMethodTestSet, descriptionSource: MethodDescriptionSource): UtMethodTestSet{
return when (descriptionSource) {
MethodDescriptionSource.FUZZER -> prepareTestSetWithFuzzedExecutions(testSet)
MethodDescriptionSource.SYMBOLIC -> prepareTestSetForByteCodeAnalysis(testSet)
}
}

/** Filter and copies executions with non-empty paths. */
private fun prepareTestSetForByteCodeAnalysis(testSet: UtMethodTestSet): UtMethodTestSet {
val executions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import org.utbot.framework.plugin.api.UtExecutionResult
import org.utbot.fuzzer.FuzzedMethodDescription
import org.utbot.fuzzer.FuzzedValue
import org.utbot.summary.MethodDescriptionSource
import java.util.*

class MethodBasedNameSuggester(private val source: MethodDescriptionSource = MethodDescriptionSource.FUZZER) : NameSuggester {
override fun suggest(
description: FuzzedMethodDescription,
values: List<FuzzedValue>,
result: UtExecutionResult?
): Sequence<TestSuggestedInfo> {
val compilableName = description.compilableName?.capitalize() ?: "Created"
val compilableName = description.compilableName?.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
?: "Created"
// See [Summarization.generateSummariesForTests].
val suffix = if (source == MethodDescriptionSource.FUZZER) "ByFuzzer" else ""
return sequenceOf(TestSuggestedInfo("test${compilableName}${suffix}"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.utbot.summary.usvm

import org.utbot.framework.plugin.api.UtMethodTestSet
import mu.KotlinLogging
import org.utbot.common.measureTime
import org.utbot.common.info
import org.utbot.framework.SummariesGenerationType.*
import org.utbot.framework.UtSettings.enableDisplayNameGeneration
import org.utbot.framework.UtSettings.enableJavaDocGeneration
import org.utbot.framework.UtSettings.enableTestNamesGeneration
import org.utbot.framework.UtSettings.summaryGenerationType
import org.utbot.summary.InvokeDescription
import org.utbot.summary.MethodDescriptionSource
import org.utbot.summary.Summarization
import java.io.File

private val logger = KotlinLogging.logger {}

/**
USummarization is used to generate summaries for *usvm-sbft*.

To generate summary, use the following settings:
- *SummariesGenerationType == LIGHT*
- *enableTestNamesGeneration = true*
- *enableDisplayNameGeneration = false*
- *enableJavaDocGeneration = true*
*/

fun Collection<UtMethodTestSet>.summarizeAll(): List<UtMethodTestSet> =
logger.info().measureTime({
"----------------------------------------------------------------------------------------\n" +
"-------------------Summarization started for ${this.size} test cases--------------------\n" +
"----------------------------------------------------------------------------------------"
}) {
this.map {
it.summarizeOne()
}
}

private fun UtMethodTestSet.summarizeOne(): UtMethodTestSet =
logger.info().measureTime({ "Summarization for ${this.method}" }) {

if (summaryGenerationType != LIGHT || !enableTestNamesGeneration || enableDisplayNameGeneration || !enableJavaDocGeneration) {
logger.info {
"Incorrect settings are used to generate Summaries for usvm-sbft"
}
return this
}

USummarization(sourceFile = null, invokeDescriptions = emptyList()).fillSummaries(this)
return this
}

class USummarization(sourceFile: File?, invokeDescriptions: List<InvokeDescription>) :
Summarization(sourceFile, invokeDescriptions) {

/*
* Used to prepare methodTestSet for further generation of summaries.
* In the case of generating tests using USVM, we only need to work with Symbolic tests.
*/
override fun prepareMethodTestSet(
testSet: UtMethodTestSet,
descriptionSource: MethodDescriptionSource
): UtMethodTestSet {
return when (descriptionSource) {
MethodDescriptionSource.FUZZER -> UtMethodTestSet(
method = testSet.method,
executions = emptyList(),
jimpleBody = testSet.jimpleBody,
errors = testSet.errors,
clustersInfo = testSet.clustersInfo
)

MethodDescriptionSource.SYMBOLIC -> testSet
}
}
}