Skip to content

Commit 4446a9d

Browse files
UtMethod removal (#862)
1 parent e856e5f commit 4446a9d

File tree

54 files changed

+608
-1168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+608
-1168
lines changed

utbot-cli/src/main/kotlin/org/utbot/cli/BunchTestGeneratorCommand.kt

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.github.ajalt.clikt.parameters.arguments.argument
44
import com.github.ajalt.clikt.parameters.options.default
55
import com.github.ajalt.clikt.parameters.options.option
66
import com.github.ajalt.clikt.parameters.types.choice
7+
import mu.KotlinLogging
78
import org.utbot.cli.util.createClassLoader
89
import org.utbot.engine.Mocker
910
import org.utbot.framework.plugin.api.ClassId
@@ -14,9 +15,6 @@ import java.io.File
1415
import java.net.URLClassLoader
1516
import java.nio.file.Paths
1617
import java.time.temporal.ChronoUnit
17-
import kotlin.reflect.KClass
18-
import kotlin.reflect.jvm.jvmName
19-
import mu.KotlinLogging
2018

2119

2220
private val logger = KotlinLogging.logger {}
@@ -93,16 +91,15 @@ class BunchTestGeneratorCommand : GenerateTestsAbstractCommand(
9391
logger.debug { "Generating test for [$targetClassFqn] - started" }
9492
logger.debug { "Classpath to be used: ${newline()} $classPath ${newline()}" }
9593

96-
val classUnderTest: KClass<*> = loadClassBySpecifiedFqn(targetClassFqn)
97-
val targetMethods = classUnderTest.targetMethods()
98-
if (targetMethods.isEmpty()) return
99-
100-
val testCaseGenerator = initializeGenerator(workingDirectory)
101-
102-
// utContext is used in `generate`, `generateTest`, `generateReport`
94+
// utContext is used in `targetMethods`, `generate`, `generateTest`, `generateReport`
10395
withUtContext(UtContext(classLoader)) {
96+
val classIdUnderTest = ClassId(targetClassFqn)
97+
val targetMethods = classIdUnderTest.targetMethods()
98+
if (targetMethods.isEmpty()) return
99+
100+
val testCaseGenerator = initializeGenerator(workingDirectory)
104101

105-
val testClassName = "${classUnderTest.simpleName}Test"
102+
val testClassName = "${classIdUnderTest.simpleName}Test"
106103

107104
val testSets = generateTestSets(
108105
testCaseGenerator,
@@ -112,7 +109,7 @@ class BunchTestGeneratorCommand : GenerateTestsAbstractCommand(
112109
.mapTo(mutableSetOf()) { ClassId(it) }
113110
)
114111

115-
val testClassBody = generateTest(classUnderTest, testClassName, testSets)
112+
val testClassBody = generateTest(classIdUnderTest, testClassName, testSets)
116113

117114
val outputArgAsFile = File(output ?: "")
118115
if (!outputArgAsFile.exists()) {
@@ -121,7 +118,7 @@ class BunchTestGeneratorCommand : GenerateTestsAbstractCommand(
121118

122119
val outputDir = "$outputArgAsFile${File.separator}"
123120

124-
val packageNameAsList = classUnderTest.jvmName.split('.').dropLast(1)
121+
val packageNameAsList = classIdUnderTest.jvmName.split('.').dropLast(1)
125122
val path = Paths.get("${outputDir}${packageNameAsList.joinToString(separator = File.separator)}")
126123
path.toFile().mkdirs()
127124

utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,20 @@ import org.utbot.framework.codegen.model.CodeGenerator
2424
import org.utbot.framework.codegen.testFrameworkByName
2525
import org.utbot.framework.plugin.api.ClassId
2626
import org.utbot.framework.plugin.api.CodegenLanguage
27+
import org.utbot.framework.plugin.api.ExecutableId
28+
import org.utbot.framework.plugin.api.MethodId
2729
import org.utbot.framework.plugin.api.MockStrategyApi
28-
import org.utbot.framework.plugin.api.TreatOverflowAsError
2930
import org.utbot.framework.plugin.api.TestCaseGenerator
30-
import org.utbot.framework.plugin.api.UtMethod
31+
import org.utbot.framework.plugin.api.TreatOverflowAsError
3132
import org.utbot.framework.plugin.api.UtMethodTestSet
32-
import org.utbot.framework.plugin.api.util.id
3333
import org.utbot.summary.summarize
3434
import java.io.File
35-
import java.lang.reflect.Method
3635
import java.net.URLClassLoader
3736
import java.nio.file.Files
3837
import java.nio.file.Path
3938
import java.nio.file.Paths
4039
import java.time.LocalDateTime
4140
import java.time.temporal.ChronoUnit
42-
import kotlin.reflect.KCallable
43-
import kotlin.reflect.KClass
44-
import kotlin.reflect.jvm.kotlinFunction
4541

4642
private const val LONG_GENERATION_TIMEOUT = 1_200_000L
4743

@@ -151,12 +147,9 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) :
151147
return Paths.get(classAbsolutePath)
152148
}
153149

154-
protected fun loadClassBySpecifiedFqn(classFqn: String): KClass<*> =
155-
classLoader.loadClass(classFqn).kotlin
156-
157150
protected fun generateTestSets(
158151
testCaseGenerator: TestCaseGenerator,
159-
targetMethods: List<UtMethod<*>>,
152+
targetMethods: List<ExecutableId>,
160153
sourceCodeFile: Path? = null,
161154
searchDirectory: Path,
162155
chosenClassesToMockAlways: Set<ClassId>
@@ -186,7 +179,7 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) :
186179
}
187180
}
188181

189-
protected fun generateTest(classUnderTest: KClass<*>, testClassname: String, testSets: List<UtMethodTestSet>): String =
182+
protected fun generateTest(classUnderTest: ClassId, testClassname: String, testSets: List<UtMethodTestSet>): String =
190183
initializeCodeGenerator(
191184
testFramework,
192185
classUnderTest
@@ -201,31 +194,21 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) :
201194
return TestCaseGenerator(workingDirectory, classPathNormalized, System.getProperty("java.class.path"))
202195
}
203196

204-
private fun initializeCodeGenerator(testFramework: String, classUnderTest: KClass<*>): CodeGenerator {
197+
private fun initializeCodeGenerator(testFramework: String, classUnderTest: ClassId): CodeGenerator {
205198
val generateWarningsForStaticMocking =
206199
forceStaticMocking == ForceStaticMocking.FORCE && staticsMocking is NoStaticMocking
207200
return CodeGenerator(
208201
testFramework = testFrameworkByName(testFramework),
209-
classUnderTest = classUnderTest.id,
202+
classUnderTest = classUnderTest,
210203
codegenLanguage = codegenLanguage,
211204
staticsMocking = staticsMocking,
212205
forceStaticMocking = forceStaticMocking,
213206
generateWarningsForStaticMocking = generateWarningsForStaticMocking,
214207
)
215208
}
216209

217-
protected fun KClass<*>.targetMethods() =
218-
this.java.declaredMethods.mapNotNull {
219-
toUtMethod(it, kClass = this)
220-
}
221-
222-
private fun toUtMethod(method: Method, kClass: KClass<*>): UtMethod<*>? =
223-
method.kotlinFunction?.let {
224-
UtMethod(it as KCallable<*>, kClass)
225-
} ?: run {
226-
logger.info("Method does not have a kotlin function: $method")
227-
null
228-
}
210+
protected fun ClassId.targetMethods(): List<MethodId> =
211+
allMethods.filter { it.classId == this }.toList() // only declared methods
229212

230213
protected fun saveToFile(snippet: String, outputPath: String?) =
231214
outputPath?.let {

utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsCommand.kt

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@ import com.github.ajalt.clikt.parameters.options.flag
77
import com.github.ajalt.clikt.parameters.options.option
88
import com.github.ajalt.clikt.parameters.options.required
99
import com.github.ajalt.clikt.parameters.types.choice
10+
import mu.KotlinLogging
1011
import org.utbot.common.PathUtil.toPath
12+
import org.utbot.common.filterWhen
1113
import org.utbot.engine.Mocker
14+
import org.utbot.framework.UtSettings
1215
import org.utbot.framework.plugin.api.ClassId
1316
import org.utbot.framework.plugin.api.CodegenLanguage
1417
import org.utbot.framework.plugin.api.UtMethodTestSet
1518
import org.utbot.framework.plugin.api.util.UtContext
19+
import org.utbot.framework.plugin.api.util.isAbstract
1620
import org.utbot.framework.plugin.api.util.withUtContext
21+
import org.utbot.framework.util.isKnownSyntheticMethod
1722
import org.utbot.sarif.SarifReport
1823
import org.utbot.sarif.SourceFindingStrategyDefault
1924
import java.nio.file.Files
2025
import java.nio.file.Paths
2126
import java.time.temporal.ChronoUnit
22-
import kotlin.reflect.KClass
23-
import mu.KotlinLogging
24-
import org.utbot.common.filterWhen
25-
import org.utbot.framework.UtSettings
26-
import org.utbot.framework.util.isKnownSyntheticMethod
2727

2828

2929
private val logger = KotlinLogging.logger {}
@@ -93,20 +93,20 @@ class GenerateTestsCommand :
9393
logger.debug { "Generating test for [$targetClassFqn] - started" }
9494
logger.debug { "Classpath to be used: ${newline()} $classPath ${newline()}" }
9595

96-
val classUnderTest: KClass<*> = loadClassBySpecifiedFqn(targetClassFqn)
97-
val targetMethods = classUnderTest.targetMethods()
98-
.filterWhen(UtSettings.skipTestGenerationForSyntheticMethods) { !isKnownSyntheticMethod(it) }
99-
.filterNot { it.callable.isAbstract }
100-
val testCaseGenerator = initializeGenerator(workingDirectory)
96+
// utContext is used in `targetMethods`, `generate`, `generateTest`, `generateReport`
97+
withUtContext(UtContext(classLoader)) {
98+
val classIdUnderTest = ClassId(targetClassFqn)
99+
val targetMethods = classIdUnderTest.targetMethods()
100+
.filterWhen(UtSettings.skipTestGenerationForSyntheticMethods) { !isKnownSyntheticMethod(it) }
101+
.filterNot { it.isAbstract }
102+
val testCaseGenerator = initializeGenerator(workingDirectory)
101103

102-
if (targetMethods.isEmpty()) {
103-
throw Exception("Nothing to process. No methods were provided")
104-
}
105-
// utContext is used in `generate`, `generateTest`, `generateReport`
106-
withUtContext(UtContext(targetMethods.first().clazz.java.classLoader)) {
104+
if (targetMethods.isEmpty()) {
105+
throw Exception("Nothing to process. No methods were provided")
106+
}
107107

108108
val testClassName = output?.toPath()?.toFile()?.nameWithoutExtension
109-
?: "${classUnderTest.simpleName}Test"
109+
?: "${classIdUnderTest.simpleName}Test"
110110
val testSets = generateTestSets(
111111
testCaseGenerator,
112112
targetMethods,
@@ -115,7 +115,7 @@ class GenerateTestsCommand :
115115
chosenClassesToMockAlways = (Mocker.defaultSuperClassesToMockAlwaysNames + classesToMockAlways)
116116
.mapTo(mutableSetOf()) { ClassId(it) }
117117
)
118-
val testClassBody = generateTest(classUnderTest, testClassName, testSets)
118+
val testClassBody = generateTest(classIdUnderTest, testClassName, testSets)
119119

120120
if (printToStdOut) {
121121
logger.info { testClassBody }

utbot-core/src/main/kotlin/org/utbot/common/FileUtil.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ import java.time.Duration
1515
import java.util.concurrent.TimeUnit
1616
import java.util.zip.ZipFile
1717
import kotlin.concurrent.thread
18-
import kotlin.reflect.KClass
1918
import kotlin.streams.asSequence
2019
import mu.KotlinLogging
2120

22-
fun KClass<*>.toClassFilePath(): String {
23-
val name = requireNotNull(java.name) { "Class is local or anonymous" }
21+
fun Class<*>.toClassFilePath(): String {
22+
val name = requireNotNull(name) { "Class is local or anonymous" }
2423

2524
return "${name.replace('.', '/')}.class"
2625
}
@@ -83,12 +82,12 @@ object FileUtil {
8382
* Copy the class file for given [classes] to temporary folder.
8483
* It can be used for Soot analysis.
8584
*/
86-
fun isolateClassFiles(vararg classes: KClass<*>): File {
85+
fun isolateClassFiles(vararg classes: Class<*>): File {
8786
val tempDir = createTempDirectory("generated-").toFile()
8887

8988
for (clazz in classes) {
9089
val path = clazz.toClassFilePath()
91-
val resource = clazz.java.classLoader.getResource(path) ?: error("No such file: $path")
90+
val resource = clazz.classLoader.getResource(path) ?: error("No such file: $path")
9291

9392
if (resource.toURI().scheme == "jar") {
9493
val jarLocation = resource.toURI().extractJarName()
@@ -107,7 +106,7 @@ object FileUtil {
107106

108107
private fun URI.extractJarName(): URI = URI(this.schemeSpecificPart.substringBefore("!").replace(" ", "%20"))
109108

110-
private fun extractClassFromArchive(archiveFile: Path, clazz: KClass<*>, destPath: Path) {
109+
private fun extractClassFromArchive(archiveFile: Path, clazz: Class<*>, destPath: Path) {
111110
val classFilePath = clazz.toClassFilePath()
112111
ZipFile(archiveFile.toFile()).use { archive ->
113112
val entry = archive.stream().asSequence().filter { it.name.normalizePath() == classFilePath }.single()
@@ -121,9 +120,9 @@ object FileUtil {
121120
* Locates class path by class.
122121
* It can be used for Soot analysis.
123122
*/
124-
fun locateClassPath(clazz: KClass<*>): File? {
123+
fun locateClassPath(clazz: Class<*>): File? {
125124
val path = clazz.toClassFilePath()
126-
val resource = requireNotNull(clazz.java.classLoader.getResource(path)) { "No such file: $path" }
125+
val resource = requireNotNull(clazz.classLoader.getResource(path)) { "No such file: $path" }
127126
if (resource.toURI().scheme == "jar") return null
128127
val fullPath = resource.path.removeSuffix(path)
129128
return File(fullPath)
@@ -132,9 +131,9 @@ object FileUtil {
132131
/**
133132
* Locates class and returns class location. Could be directory or jar based.
134133
*/
135-
fun locateClass(clazz: KClass<*>): ClassLocation {
134+
fun locateClass(clazz: Class<*>): ClassLocation {
136135
val path = clazz.toClassFilePath()
137-
val resource = requireNotNull(clazz.java.classLoader.getResource(path)) { "No such file: $path" }
136+
val resource = requireNotNull(clazz.classLoader.getResource(path)) { "No such file: $path" }
138137
return if (resource.toURI().scheme == "jar") {
139138
val jarLocation = resource.toURI().extractJarName()
140139
JarClassLocation(Paths.get(jarLocation))

utbot-core/src/main/kotlin/org/utbot/common/ReflectionUtil.kt

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package org.utbot.common
22

33
import org.utbot.common.Reflection.setModifiers
4+
import sun.misc.Unsafe
45
import java.lang.reflect.AccessibleObject
56
import java.lang.reflect.Field
6-
import java.lang.reflect.Modifier
7-
import sun.misc.Unsafe
7+
import java.lang.reflect.Member
88
import java.lang.reflect.Method
9+
import java.lang.reflect.Modifier
910

1011
object Reflection {
1112
val unsafe: Unsafe
@@ -73,3 +74,41 @@ inline fun <reified R> Field.withAccessibility(block: () -> R): R {
7374
setModifiers(this, prevModifiers)
7475
}
7576
}
77+
78+
// utility properties
79+
80+
val Member.isAbstract
81+
get() = Modifier.isAbstract(modifiers)
82+
83+
val Member.isStatic
84+
get() = Modifier.isStatic(modifiers)
85+
86+
val Member.isPrivate
87+
get() = Modifier.isPrivate(modifiers)
88+
89+
val Member.isPublic
90+
get() = Modifier.isPublic(modifiers)
91+
92+
val Member.isFinal
93+
get() = Modifier.isFinal(modifiers)
94+
95+
val Member.isProtected
96+
get() = Modifier.isProtected(modifiers)
97+
98+
val Class<*>.isAbstract
99+
get() = Modifier.isAbstract(modifiers)
100+
101+
val Class<*>.isStatic
102+
get() = Modifier.isStatic(modifiers)
103+
104+
val Class<*>.isPrivate
105+
get() = Modifier.isPrivate(modifiers)
106+
107+
val Class<*>.isPublic
108+
get() = Modifier.isPublic(modifiers)
109+
110+
val Class<*>.isFinal
111+
get() = Modifier.isFinal(modifiers)
112+
113+
val Class<*>.isProtected
114+
get() = Modifier.isProtected(modifiers)

0 commit comments

Comments
 (0)