@@ -16,13 +16,20 @@ import org.utbot.summary.UtSummarySettings.GENERATE_NAMES
16
16
import org.utbot.summary.analysis.ExecutionStructureAnalysis
17
17
import org.utbot.summary.ast.JimpleToASTMap
18
18
import org.utbot.summary.ast.SourceCodeParser
19
- import org.utbot.summary.comment.SimpleClusterCommentBuilder
19
+ import org.utbot.summary.comment.SymbolicExecutionClusterCommentBuilder
20
20
import org.utbot.summary.comment.SimpleCommentBuilder
21
21
import org.utbot.summary.name.SimpleNameBuilder
22
22
import java.io.File
23
23
import java.nio.file.Path
24
24
import java.nio.file.Paths
25
25
import mu.KotlinLogging
26
+ import org.utbot.framework.plugin.api.UtConcreteExecutionFailure
27
+ import org.utbot.framework.plugin.api.UtExecutionSuccess
28
+ import org.utbot.framework.plugin.api.UtExplicitlyThrownException
29
+ import org.utbot.framework.plugin.api.UtImplicitlyThrownException
30
+ import org.utbot.framework.plugin.api.UtOverflowFailure
31
+ import org.utbot.framework.plugin.api.UtSandboxFailure
32
+ import org.utbot.framework.plugin.api.UtTimeoutException
26
33
import org.utbot.fuzzer.FuzzedMethodDescription
27
34
import org.utbot.fuzzer.FuzzedValue
28
35
import org.utbot.fuzzer.UtFuzzedExecution
@@ -40,7 +47,7 @@ fun UtMethodTestSet.summarize(sourceFile: File?, searchDirectory: Path = Paths.g
40
47
makeDiverseExecutions(this )
41
48
val invokeDescriptions = invokeDescriptions(this , searchDirectory)
42
49
// every cluster has summary and list of executions
43
- val executionClusters = Summarization (sourceFile, invokeDescriptions).summary (this )
50
+ val executionClusters = Summarization (sourceFile, invokeDescriptions).fillSummaries (this )
44
51
val updatedExecutions = executionClusters.flatMap { it.executions }
45
52
var pos = 0
46
53
val clustersInfo = executionClusters.map {
@@ -49,7 +56,10 @@ fun UtMethodTestSet.summarize(sourceFile: File?, searchDirectory: Path = Paths.g
49
56
pos + = clusterSize
50
57
it.clusterInfo to indices
51
58
}
52
- this .copy(executions = updatedExecutions, clustersInfo = clustersInfo) // TODO: looks weird and don't create the real copy
59
+ this .copy(
60
+ executions = updatedExecutions,
61
+ clustersInfo = clustersInfo
62
+ ) // TODO: looks weird and don't create the real copy
53
63
} catch (e: Throwable ) {
54
64
logger.info(e) { " Summary generation error" }
55
65
this
@@ -64,7 +74,7 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
64
74
private val tagGenerator = TagGenerator ()
65
75
private val jimpleBodyAnalysis = ExecutionStructureAnalysis ()
66
76
67
- fun summary (testSet : UtMethodTestSet ): List <UtExecutionCluster > {
77
+ fun fillSummaries (testSet : UtMethodTestSet ): List <UtExecutionCluster > {
68
78
val namesCounter = mutableMapOf<String , Int >()
69
79
70
80
if (testSet.executions.isEmpty()) {
@@ -83,28 +93,61 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
83
93
84
94
// handles tests produced by fuzzing
85
95
val executionsProducedByFuzzer = testSet.executions.filterIsInstance<UtFuzzedExecution >()
96
+ val successfulFuzzerExecutions = mutableListOf<UtFuzzedExecution >()
97
+ val unsuccessfulFuzzerExecutions = mutableListOf<UtFuzzedExecution >()
86
98
87
99
if (executionsProducedByFuzzer.isNotEmpty()) {
88
100
executionsProducedByFuzzer.forEach { utExecution ->
89
101
90
102
val nameSuggester = sequenceOf(ModelBasedNameSuggester (), MethodBasedNameSuggester ())
91
103
val testMethodName = try {
92
- nameSuggester.flatMap { it.suggest(utExecution.fuzzedMethodDescription as FuzzedMethodDescription , utExecution.fuzzingValues as List <FuzzedValue >, utExecution.result) }.firstOrNull()
104
+ nameSuggester.flatMap {
105
+ it.suggest(
106
+ utExecution.fuzzedMethodDescription as FuzzedMethodDescription ,
107
+ utExecution.fuzzingValues as List <FuzzedValue >,
108
+ utExecution.result
109
+ )
110
+ }.firstOrNull()
93
111
} catch (t: Throwable ) {
94
112
logger.error(t) { " Cannot create suggested test name for $utExecution " } // TODO: add better explanation or default behavoiur
95
113
null
96
114
}
97
115
98
116
utExecution.testMethodName = testMethodName?.testName
99
- utExecution.displayName = testMethodName?.displayName
117
+ utExecution.displayName = testMethodName?.displayName
118
+
119
+ when (utExecution.result) {
120
+ is UtConcreteExecutionFailure -> unsuccessfulFuzzerExecutions.add(utExecution)
121
+ is UtExplicitlyThrownException -> unsuccessfulFuzzerExecutions.add(utExecution)
122
+ is UtImplicitlyThrownException -> unsuccessfulFuzzerExecutions.add(utExecution)
123
+ is UtOverflowFailure -> unsuccessfulFuzzerExecutions.add(utExecution)
124
+ is UtSandboxFailure -> unsuccessfulFuzzerExecutions.add(utExecution)
125
+ is UtTimeoutException -> unsuccessfulFuzzerExecutions.add(utExecution)
126
+ is UtExecutionSuccess -> successfulFuzzerExecutions.add(utExecution)
127
+ }
100
128
}
101
129
102
- clustersToReturn.add(
103
- UtExecutionCluster (
104
- UtClusterInfo (), // TODO: add something https://github.com/UnitTestBot/UTBotJava/issues/430
105
- executionsProducedByFuzzer
130
+ if (successfulFuzzerExecutions.isNotEmpty()) {
131
+ val clusterHeader = buildFuzzerClusterHeaderForSuccessfulExecutions(testSet)
132
+
133
+ clustersToReturn.add(
134
+ UtExecutionCluster (
135
+ UtClusterInfo (clusterHeader, null ),
136
+ successfulFuzzerExecutions
137
+ )
106
138
)
107
- )
139
+ }
140
+
141
+ if (unsuccessfulFuzzerExecutions.isNotEmpty()) {
142
+ val clusterHeader = buildFuzzerClusterHeaderForUnsuccessfulExecutions(testSet)
143
+
144
+ clustersToReturn.add(
145
+ UtExecutionCluster (
146
+ UtClusterInfo (clusterHeader, null ),
147
+ unsuccessfulFuzzerExecutions
148
+ )
149
+ )
150
+ }
108
151
}
109
152
110
153
// handles tests produced by symbolic engine, but with empty paths
@@ -113,14 +156,14 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
113
156
if (executionsWithEmptyPaths.isNotEmpty()) {
114
157
executionsWithEmptyPaths.forEach {
115
158
logger.info {
116
- " Test is created by Symbolic Engine. The path for test ${it.testMethodName} " +
159
+ " Test is created by Symbolic Execution Engine. The path for test ${it.testMethodName} " +
117
160
" for method ${testSet.method.clazz.qualifiedName} is empty and summaries could not be generated."
118
161
}
119
162
}
120
163
121
164
clustersToReturn.add(
122
165
UtExecutionCluster (
123
- UtClusterInfo (), // TODO: https://github.com/UnitTestBot/UTBotJava/issues/430
166
+ UtClusterInfo (),
124
167
executionsWithEmptyPaths
125
168
)
126
169
)
@@ -135,13 +178,13 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
135
178
jimpleBodyAnalysis.traceStructuralAnalysis(jimpleBody, clusteredTags, methodUnderTest, invokeDescriptions)
136
179
val numberOfSuccessfulClusters = clusteredTags.filter { it.isSuccessful }.size
137
180
for (clusterTraceTags in clusteredTags) {
138
- val clusterHeader = clusterTraceTags.summary .takeIf { GENERATE_CLUSTER_COMMENTS }
181
+ val clusterHeader = clusterTraceTags.clusterHeader .takeIf { GENERATE_CLUSTER_COMMENTS }
139
182
val clusterContent = if (
140
183
GENERATE_CLUSTER_COMMENTS && clusterTraceTags.isSuccessful // add only for successful executions
141
184
&& numberOfSuccessfulClusters > 1 // there is more than one successful execution
142
185
&& clusterTraceTags.traceTags.size > 1 // add if there is more than 1 execution
143
186
) {
144
- SimpleClusterCommentBuilder (clusterTraceTags.commonStepsTraceTag, sootToAST)
187
+ SymbolicExecutionClusterCommentBuilder (clusterTraceTags.commonStepsTraceTag, sootToAST)
145
188
.buildString(methodUnderTest)
146
189
.takeIf { it.isNotBlank() }
147
190
?.let {
@@ -204,6 +247,20 @@ class Summarization(val sourceFile: File?, val invokeDescriptions: List<InvokeDe
204
247
return listOf (UtExecutionCluster (UtClusterInfo (), testSet.executions))
205
248
}
206
249
250
+ private fun buildFuzzerClusterHeaderForSuccessfulExecutions (testSet : UtMethodTestSet ): String {
251
+ val commentPrefix = " FUZZER:"
252
+ val commentPostfix = " for method ${testSet.method.humanReadableName} "
253
+
254
+ return " $commentPrefix ${ExecutionGroup .SUCCESSFUL_EXECUTIONS .displayName} $commentPostfix "
255
+ }
256
+
257
+ private fun buildFuzzerClusterHeaderForUnsuccessfulExecutions (testSet : UtMethodTestSet ): String {
258
+ val commentPrefix = " FUZZER:"
259
+ val commentPostfix = " for method ${testSet.method.humanReadableName} "
260
+
261
+ return " $commentPrefix ${ExecutionGroup .EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS } $commentPostfix "
262
+ }
263
+
207
264
private fun prepareTestSetForByteCodeAnalysis (testSet : UtMethodTestSet ): UtMethodTestSet {
208
265
val executions =
209
266
testSet.executions.filterIsInstance<UtSymbolicExecution >().filter { it.path.isNotEmpty() }
@@ -278,7 +335,8 @@ private fun makeDiverseExecutions(testSet: UtMethodTestSet) {
278
335
}
279
336
280
337
private fun invokeDescriptions (testSet : UtMethodTestSet , searchDirectory : Path ): List <InvokeDescription > {
281
- val sootInvokes = testSet.executions.filterIsInstance<UtSymbolicExecution >().flatMap { it.path.invokeJimpleMethods() }.toSet()
338
+ val sootInvokes =
339
+ testSet.executions.filterIsInstance<UtSymbolicExecution >().flatMap { it.path.invokeJimpleMethods() }.toSet()
282
340
return sootInvokes
283
341
// TODO(SAT-1170)
284
342
.filterNot { " \$ lambda" in it.declaringClass.name }
0 commit comments