Skip to content

Commit 16d859b

Browse files
committed
Added tests for Kotlin top-level functions
1 parent 3c88ab3 commit 16d859b

File tree

5 files changed

+94
-6
lines changed

5 files changed

+94
-6
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt

+1
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ val Method.displayName: String
498498

499499
val KCallable<*>.declaringClazz: Class<*>
500500
get() = when (this) {
501+
is KFunction<*> -> javaMethod?.declaringClass?.kotlin
501502
is CallableReference -> owner as? KClass<*>
502503
else -> instanceParameter?.type?.classifier as? KClass<*>
503504
}?.java ?: tryConstructor(this) ?: error("Can't get parent class for $this")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.utbot.examples.codegen
2+
3+
import org.junit.jupiter.api.Test
4+
import org.utbot.testcheckers.eq
5+
import org.utbot.tests.infrastructure.UtValueTestCaseChecker
6+
7+
// We can't access real declaration class of the methods (`FileWithTopLevelFunctionsKt`) from Kotlin, so
8+
// testClass is fictive here, and we can only test code generation through `checkAllCombinations`
9+
internal class FileWithTopLevelFunctionsTest : UtValueTestCaseChecker(testClass = CodegenExample::class) {
10+
@Test
11+
fun topLevelSumTest() {
12+
withEnabledTestingCodeGeneration(false) {
13+
check(
14+
::topLevelSum,
15+
eq(1),
16+
)
17+
}
18+
checkAllCombinations(::topLevelSum)
19+
}
20+
21+
@Test
22+
fun extensionOnBasicTypeTest() {
23+
withEnabledTestingCodeGeneration(false) {
24+
check(
25+
Int::extensionOnBasicType,
26+
eq(1),
27+
)
28+
}
29+
checkAllCombinations(Int::extensionOnBasicType)
30+
}
31+
32+
@Test
33+
fun extensionOnCustomClassTest() {
34+
withEnabledTestingCodeGeneration(false) {
35+
check(
36+
CustomClass::extensionOnCustomClass,
37+
eq(1),
38+
additionalDependencies = dependenciesForClassExtensions
39+
)
40+
}
41+
checkAllCombinations(
42+
CustomClass::extensionOnCustomClass,
43+
additionalDependencies = dependenciesForClassExtensions
44+
)
45+
}
46+
47+
companion object {
48+
// Compilation of extension methods for ref objects produces call to
49+
// `kotlin.jvm.internal.Intrinsics::checkNotNullParameter`, so we need to add it to dependencies
50+
val dependenciesForClassExtensions = arrayOf<Class<*>>(kotlin.jvm.internal.Intrinsics::class.java)
51+
}
52+
}

utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/UtValueTestCaseChecker.kt

+6-5
Original file line numberDiff line numberDiff line change
@@ -2346,15 +2346,15 @@ abstract class UtValueTestCaseChecker(
23462346
* or just generate one top-level test class
23472347
* @see [ClassWithStaticAndInnerClassesTest]
23482348
*/
2349-
fun checkAllCombinations(method: KFunction<*>, generateWithNested: Boolean = false) {
2349+
fun checkAllCombinations(method: KFunction<*>, generateWithNested: Boolean = false, additionalDependencies: Array<Class<*>> = arrayOf()) {
23502350
val failed = mutableListOf<TestFrameworkConfiguration>()
23512351
val succeeded = mutableListOf<TestFrameworkConfiguration>()
23522352

23532353
allTestFrameworkConfigurations
23542354
.filterNot { it.isDisabled }
23552355
.forEach { config ->
23562356
runCatching {
2357-
internalCheckForCodeGeneration(method, config, generateWithNested)
2357+
internalCheckForCodeGeneration(method, config, generateWithNested, additionalDependencies)
23582358
}.onFailure {
23592359
failed += config
23602360
}.onSuccess {
@@ -2377,13 +2377,14 @@ abstract class UtValueTestCaseChecker(
23772377
private fun internalCheckForCodeGeneration(
23782378
method: KFunction<*>,
23792379
testFrameworkConfiguration: TestFrameworkConfiguration,
2380-
generateWithNested: Boolean
2380+
generateWithNested: Boolean,
2381+
additionalDependencies: Array<Class<*>>
23812382
) {
23822383
withSettingsFromTestFrameworkConfiguration(testFrameworkConfiguration) {
23832384
with(testFrameworkConfiguration) {
23842385

23852386
val executableId = method.executableId
2386-
computeAdditionalDependenciesClasspathAndBuildDir(method.declaringClazz, emptyArray())
2387+
val additionalDependenciesClassPath = computeAdditionalDependenciesClasspathAndBuildDir(method.declaringClazz, additionalDependencies)
23872388
val utContext = UtContext(method.declaringClazz.classLoader)
23882389

23892390
clearTempDirectory(daysLimitForTempFiles)
@@ -2393,7 +2394,7 @@ abstract class UtValueTestCaseChecker(
23932394
MethodWithMockStrategy(executableId, mockStrategy, resetNonFinalFieldsAfterClinit)
23942395

23952396
val (testSet, coverage) = analyzedMethods.getOrPut(methodWithStrategy) {
2396-
walk(executableId, mockStrategy)
2397+
walk(executableId, mockStrategy, additionalDependenciesClassPath)
23972398
}
23982399

23992400
// if force mocking took place in parametrized test generation,

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt

+10-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,16 @@ class EngineProcess(parent: Lifetime, val project: Project) {
234234
}
235235

236236
private fun MemberInfo.paramNames(): List<String> =
237-
(this.member as PsiMethod).parameterList.parameters.map { it.name }
237+
(this.member as PsiMethod).parameterList.parameters.map {
238+
if (it.name.startsWith("\$this"))
239+
// If member is Kotlin extension function, name of first argument isn't good for further usage,
240+
// so we better choose name based on type of receiver.
241+
//
242+
// There seems no API to check whether parameter is an extension receiver by PSI
243+
it.type.presentableText
244+
else
245+
it.name
246+
}
238247

239248
fun generate(
240249
mockInstalled: Boolean,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.utbot.examples.codegen
2+
3+
// TODO: currently we can't properly handle properties in constructors, change CustomClass to data class after that is fixed
4+
class CustomClass {
5+
var x: Int = 0
6+
var y: Int = 0
7+
8+
fun f(): Int {
9+
return 0
10+
}
11+
}
12+
13+
fun topLevelSum(a: Int, b: Int): Int {
14+
return a + b
15+
}
16+
17+
fun Int.extensionOnBasicType(other: Int): Int {
18+
return this + other
19+
}
20+
21+
fun CustomClass.extensionOnCustomClass(add: Int): CustomClass {
22+
this.x += add
23+
this.y += add
24+
return this
25+
}

0 commit comments

Comments
 (0)