1
1
package org.utbot.framework.process
2
2
3
+ import com.jetbrains.rd.framework.IProtocol
4
+ import com.jetbrains.rd.framework.Protocol
3
5
import com.jetbrains.rd.util.Logger
4
6
import com.jetbrains.rd.util.info
5
7
import com.jetbrains.rd.util.lifetime.Lifetime
@@ -8,30 +10,42 @@ import kotlinx.coroutines.runBlocking
8
10
import mu.KotlinLogging
9
11
import org.utbot.analytics.AnalyticsConfigureUtil
10
12
import org.utbot.common.AbstractSettings
13
+ import org.utbot.common.allNestedClasses
11
14
import org.utbot.engine.util.mockListeners.ForceMockListener
12
15
import org.utbot.engine.util.mockListeners.ForceStaticMockListener
13
16
import org.utbot.framework.codegen.*
14
17
import org.utbot.framework.codegen.model.CodeGenerator
15
18
import org.utbot.framework.plugin.api.*
19
+ import org.utbot.framework.plugin.api.Signature
16
20
import org.utbot.framework.plugin.api.util.UtContext
21
+ import org.utbot.framework.plugin.api.util.executableId
22
+ import org.utbot.framework.plugin.api.util.id
23
+ import org.utbot.framework.plugin.api.util.jClass
17
24
import org.utbot.framework.plugin.services.JdkInfo
18
25
import org.utbot.framework.process.generated.*
19
26
import org.utbot.framework.util.ConflictTriggers
20
27
import org.utbot.framework.util.jimpleBody
21
28
import org.utbot.instrumentation.util.KryoHelper
22
29
import org.utbot.rd.CallsSynchronizer
23
30
import org.utbot.rd.ClientProtocolBuilder
24
- import org.utbot.rd.awaitTermination
25
31
import org.utbot.rd.findRdPort
26
32
import org.utbot.rd.loggers.UtRdKLoggerFactory
33
+ import org.utbot.sarif.RdSourceFindingStrategyFacade
34
+ import org.utbot.sarif.SarifRegion
35
+ import org.utbot.sarif.SarifReport
27
36
import org.utbot.summary.summarize
28
37
import soot.SootMethod
29
38
import soot.UnitPatchingChain
30
39
import soot.util.HashChain
31
40
import java.io.File
32
41
import java.net.URLClassLoader
42
+ import java.nio.file.Path
33
43
import java.nio.file.Paths
34
44
import java.util.*
45
+ import kotlin.reflect.KFunction
46
+ import kotlin.reflect.KParameter
47
+ import kotlin.reflect.full.functions
48
+ import kotlin.reflect.jvm.javaType
35
49
import kotlin.time.Duration.Companion.seconds
36
50
37
51
private val messageFromMainTimeoutMillis = 120 .seconds
@@ -61,20 +75,22 @@ suspend fun main(args: Array<String>) = runBlocking {
61
75
62
76
ClientProtocolBuilder ().withProtocolTimeout(messageFromMainTimeoutMillis).start(port) {
63
77
settingsModel
78
+ rdSourceFindingStrategy
79
+
64
80
AbstractSettings .setupFactory(RdSettingsContainerFactory (protocol))
65
81
val kryoHelper = KryoHelper (lifetime).setup()
66
-
67
- engineProcessModel.setup(kryoHelper, it)
82
+ engineProcessModel.setup(kryoHelper, it, protocol)
68
83
}
69
84
logger.info { " runBlocking ending" }
70
85
}.also {
71
86
logger.info { " runBlocking ended" }
72
87
}
88
+
73
89
private lateinit var testGenerator: TestCaseGenerator
90
+ private lateinit var testSets: List <UtMethodTestSet >
74
91
75
92
private fun EngineProcessModel.setup (
76
- kryoHelper : KryoHelper ,
77
- synchronizer : CallsSynchronizer
93
+ kryoHelper : KryoHelper , synchronizer : CallsSynchronizer , realProtocol : IProtocol
78
94
) {
79
95
val model = this
80
96
synchronizer.measureExecutionForTermination(setupUtContext) { params ->
@@ -96,8 +112,7 @@ private fun EngineProcessModel.setup(
96
112
}
97
113
synchronizer.measureExecutionForTermination(generate) { params ->
98
114
val mockFrameworkInstalled = params.mockInstalled
99
- val conflictTriggers =
100
- ConflictTriggers (kryoHelper.readObject(params.conflictTriggers))
115
+ val conflictTriggers = ConflictTriggers (kryoHelper.readObject(params.conflictTriggers))
101
116
if (! mockFrameworkInstalled) {
102
117
ForceMockListener .create(testGenerator, conflictTriggers)
103
118
}
@@ -114,15 +129,25 @@ private fun EngineProcessModel.setup(
114
129
isSymbolicEngineEnabled = params.isSymbolicEngineEnabled
115
130
isFuzzingEnabled = params.isFuzzingEnabled
116
131
fuzzingValue = params.fuzzingValue
117
- }).map { it.summarize(Paths .get(params.searchDirectory)) }
118
- .filterNot { it.executions.isEmpty() && it.errors.isEmpty() }.map {
132
+ })
133
+ .map { it.summarize(Paths .get(params.searchDirectory)) }
134
+ .filterNot { it.executions.isEmpty() && it.errors.isEmpty() }
135
+ .apply {
136
+ testSets = this
137
+ }
138
+ .map {
139
+ // kryo cannot serialize structures such as JimpleBody or Api.Step.stmt
140
+ // because soot entities use classes and collections with complex initialization logic
141
+ // which kryo cannot guess.
142
+ // so in the idea process such entities will be either null or empty, operating on them supported only
143
+ // in engine process.
144
+ // jimpleBody can be obtained from executionId, logic for path and fullpath should be discussed
119
145
it.copy(jimpleBody = null , executions = it.executions.map { execution ->
120
146
if (execution is UtSymbolicExecution ) execution.apply {
121
147
path = mutableListOf ()
122
148
fullPath = mutableListOf ()
123
149
}
124
- else
125
- execution
150
+ else execution
126
151
})
127
152
}
128
153
@@ -154,12 +179,46 @@ private fun EngineProcessModel.setup(
154
179
)
155
180
RenderResult (
156
181
kryoHelper.writeObject(
157
- codeGenerator.generateAsStringWithTestReport(
158
- kryoHelper.readObject<List <UtMethodTestSet >>(
159
- params.testSets
160
- ).map { it.copy(jimpleBody = jimpleBody(it.method)) }).copy(testsGenerationReport = null )
182
+ codeGenerator.generateAsStringWithTestReport(kryoHelper.readObject<List <UtMethodTestSet >>(
183
+ params.testSets
184
+ ).map { it.copy(jimpleBody = jimpleBody(it.method)) })
185
+ // currently due to moving engine out of idea process we cannot show test generation report
186
+ // because it contains CgElements, which kryo cannot deserialize because they use complex collections
187
+ // potentially it is possible to implement a lot of additional kryo serializers for that collections
188
+ .copy(testsGenerationReport = null )
161
189
)
162
190
)
163
191
}
164
192
synchronizer.measureExecutionForTermination(stopProcess) { synchronizer.stopProtocol() }
165
- }
193
+ synchronizer.measureExecutionForTermination(obtainClassId) { canonicalName ->
194
+ kryoHelper.writeObject(UtContext .currentContext()!! .classLoader.loadClass(canonicalName).id)
195
+ }
196
+ synchronizer.measureExecutionForTermination(findMethodsInClassMatchingSelected) { params ->
197
+ val classId = kryoHelper.readObject<ClassId >(params.classId)
198
+ val selectedSignatures = params.signatures.map { Signature (it.name, it.parametersTypes) }
199
+ FindMethodsInClassMatchingSelectedResult (kryoHelper.writeObject(classId.jClass.kotlin.allNestedClasses.flatMap { clazz ->
200
+ clazz.functions.sortedWith(compareBy { selectedSignatures.indexOf(it.signature()) })
201
+ .filter { it.signature().normalized() in selectedSignatures }
202
+ .map { it.executableId }
203
+ }))
204
+ }
205
+ synchronizer.measureExecutionForTermination(findMethodParamNames) { params ->
206
+ val classId = kryoHelper.readObject<ClassId >(params.classId)
207
+ val bySignature = kryoHelper.readObject<Map <Signature , List <String >>>(params.bySignature)
208
+ FindMethodParamNamesResult (kryoHelper.writeObject(
209
+ classId.jClass.kotlin.allNestedClasses.flatMap { it.functions }
210
+ .mapNotNull { method -> bySignature[method.signature()]?.let { params -> method.executableId to params } }
211
+ .toMap()
212
+ ))
213
+ }
214
+ synchronizer.measureExecutionForTermination(writeSarifReport) { params ->
215
+ val reportFilePath = Paths .get(params.reportFilePath)
216
+ reportFilePath.toFile().writeText(
217
+ SarifReport (
218
+ testSets,
219
+ params.generatedTestsCode,
220
+ RdSourceFindingStrategyFacade (realProtocol.rdSourceFindingStrategy)
221
+ ).createReport()
222
+ )
223
+ }
224
+ }
0 commit comments