1
1
package org.utbot.framework.coverage
2
2
3
- import org.jacoco.core.analysis.Analyzer
4
- import org.jacoco.core.analysis.CoverageBuilder
5
- import org.jacoco.core.analysis.IClassCoverage
6
- import org.jacoco.core.analysis.ICounter
7
- import org.jacoco.core.analysis.IMethodCoverage
8
- import org.jacoco.core.data.ExecutionDataStore
9
- import org.jacoco.core.data.SessionInfoStore
10
- import org.jacoco.core.instr.Instrumenter
11
- import org.jacoco.core.runtime.IRuntime
12
- import org.jacoco.core.runtime.LoggerRuntime
13
- import org.jacoco.core.runtime.RuntimeData
14
3
import org.utbot.framework.plugin.api.ExecutableId
15
4
import org.utbot.framework.plugin.api.UtValueExecution
16
5
import org.utbot.framework.plugin.api.util.jClass
@@ -19,123 +8,8 @@ import org.utbot.instrumentation.instrumentation.coverage.CoverageInfo
19
8
import org.utbot.instrumentation.instrumentation.coverage.CoverageInstrumentation
20
9
import org.utbot.instrumentation.instrumentation.coverage.collectCoverage
21
10
import org.utbot.instrumentation.util.StaticEnvironment
22
- import java.io.InputStream
23
- import kotlin.reflect.KClass
24
- import kotlin.reflect.full.createInstance
25
- import kotlin.reflect.full.declaredFunctions
26
11
import kotlinx.coroutines.runBlocking
27
12
28
- fun instrument (clazz : KClass <* >, instrumenter : Instrumenter ): ByteArray =
29
- clazz.asInputStream().use {
30
- instrumenter.instrument(it, clazz.qualifiedName)
31
- }
32
-
33
- fun calculateClassCoverage (targetClass : KClass <* >, testClass : KClass <* >): Coverage {
34
- val targetName = targetClass.qualifiedName!!
35
- val testClassName = testClass.qualifiedName!!
36
-
37
- // IRuntime instance to collect execution data
38
- val runtime: IRuntime = LoggerRuntime ()
39
-
40
- // create a modified version of target class with probes
41
- val instrumenter = Instrumenter (runtime)
42
- val instrumentedTarget = instrument(targetClass, instrumenter)
43
- val instrumentedTestClass = instrument(testClass, instrumenter)
44
-
45
- // startup the runtime
46
- val data = RuntimeData ()
47
- runtime.startup(data)
48
-
49
- // load class from byte[] instances
50
- val memoryClassLoader = MemoryClassLoader ()
51
- memoryClassLoader.addDefinition(targetName, instrumentedTarget)
52
- memoryClassLoader.addDefinition(testClassName, instrumentedTestClass)
53
-
54
- val instrumentedTests = memoryClassLoader.loadClass(testClassName).kotlin
55
-
56
- val tests = instrumentedTests.declaredFunctions
57
- val testClassInstance = instrumentedTests.createInstance()
58
- tests.forEach {
59
- it.call(testClassInstance)
60
- }
61
-
62
- // shutdown the runtime
63
- val executionData = ExecutionDataStore ()
64
- val sessionInfos = SessionInfoStore ()
65
- data.collect(executionData, sessionInfos, false )
66
- runtime.shutdown()
67
-
68
- // get coverage builder
69
- val coverageBuilder = CoverageBuilder ().apply {
70
- val analyzer = Analyzer (executionData, this )
71
- targetClass.asInputStream().use {
72
- analyzer.analyzeClass(it, targetName)
73
- }
74
- }
75
-
76
- val methodsCoverage = coverageBuilder.classes
77
- .single { it.qualifiedName == targetName }
78
- .methods
79
- .map { it.toMethodCoverage() }
80
-
81
- return methodsCoverage.toClassCoverage()
82
- }
83
-
84
- fun calculateCoverage (clazz : KClass <* >, block : (KClass <* >) -> Unit ): CoverageBuilder {
85
- val targetName = clazz.qualifiedName!!
86
-
87
- // IRuntime instance to collect execution data
88
- val runtime: IRuntime = LoggerRuntime ()
89
-
90
- // create a modified version of target class with probes
91
- val instrumenter = Instrumenter (runtime)
92
- val instrumented = instrument(clazz, instrumenter)
93
-
94
- // startup the runtime
95
- val data = RuntimeData ()
96
- runtime.startup(data)
97
-
98
- // load class from byte[] instances
99
- val memoryClassLoader = MemoryClassLoader ()
100
- memoryClassLoader.addDefinition(targetName, instrumented)
101
- val targetClass = memoryClassLoader.loadClass(targetName).kotlin
102
-
103
- // execute code
104
- block(targetClass)
105
-
106
- // shutdown the runtime
107
- val executionData = ExecutionDataStore ()
108
- val sessionInfos = SessionInfoStore ()
109
- data.collect(executionData, sessionInfos, false )
110
- runtime.shutdown()
111
-
112
- // calculate coverage
113
- return CoverageBuilder ().apply {
114
- val analyzer = Analyzer (executionData, this )
115
- clazz.asInputStream().use {
116
- analyzer.analyzeClass(it, targetName)
117
- }
118
- }
119
- }
120
-
121
- fun KClass <* >.asInputStream (): InputStream =
122
- java.getResourceAsStream(" /${qualifiedName!! .replace(' .' , ' /' )} .class" )!!
123
-
124
- class MemoryClassLoader : ClassLoader () {
125
- private val definitions: MutableMap <String , ByteArray > = HashMap ()
126
-
127
- fun addDefinition (name : String , bytes : ByteArray ) {
128
- definitions[name] = bytes
129
- }
130
-
131
- override fun loadClass (name : String , resolve : Boolean ): Class <* > {
132
- val bytes = definitions[name]
133
- return if (bytes != null ) {
134
- defineClass(name, bytes, 0 , bytes.size)
135
- } else super .loadClass(name, resolve)
136
- }
137
- }
138
-
139
13
fun methodCoverage (executable : ExecutableId , executions : List <UtValueExecution <* >>, classpath : String ): Coverage {
140
14
val methodSignature = executable.signature
141
15
val classId = executable.classId
@@ -174,11 +48,6 @@ fun CoverageInfo.toMethodCoverage(methodSignature: String): Coverage {
174
48
)
175
49
}
176
50
177
- fun IMethodCoverage.toMethodCoverage (): Coverage =
178
- Coverage (branchCounter.toCounter(), instructionCounter.toCounter(), lineCounter.toCounter())
179
-
180
- private fun ICounter.toCounter (): Counter = Counter (totalCount, coveredCount, missedCount)
181
-
182
51
data class Coverage (
183
52
val branchCounter : Counter = Counter (),
184
53
val instructionCounter : Counter = Counter (),
@@ -187,28 +56,13 @@ data class Coverage(
187
56
override fun toString () = " (branches: $branchCounter , instructions: $instructionCounter , lines: $lineCounter )"
188
57
}
189
58
190
- fun List<Coverage>.toClassCoverage (): Coverage {
191
- var branchCounter = Counter ()
192
- var instructionCounter = Counter ()
193
- var lineCounter = Counter ()
194
- forEach {
195
- branchCounter + = it.branchCounter
196
- instructionCounter + = it.instructionCounter
197
- lineCounter + = it.lineCounter
198
- }
199
- return Coverage (branchCounter, instructionCounter, lineCounter)
200
- }
201
-
202
59
operator fun Counter.plus (other : Counter ): Counter =
203
60
Counter (
204
61
total + other.total,
205
62
covered + other.covered,
206
63
missed + other.missed
207
64
)
208
65
209
- private val IClassCoverage .qualifiedName: String
210
- get() = this .name.replace(' /' , ' .' )
211
-
212
66
data class Counter (val total : Int = 0 , val covered : Int = 0 , val missed : Int = 0 ) {
213
67
override fun toString () = " $covered /$total "
214
68
}
0 commit comments