[K/N] Implement ObjCExportNamerTest and ObjCExportMapperTest
... to provide simple and quick validation for their corresponding entities. Those tests can also act as convenient entry points for debugging.
This commit is contained in:
committed by
Space Team
parent
269b60b420
commit
04df33eec1
@@ -189,6 +189,9 @@ dependencies {
|
||||
cli_bcApiElements sourceSets.cli_bc.output
|
||||
|
||||
testImplementation(project(path: ":compiler:tests-common", configuration: "tests-jar"))
|
||||
testImplementation(libs.junit.jupiter.api)
|
||||
testImplementation(libs.junit.jupiter.params)
|
||||
testRuntimeOnly(libs.junit.jupiter.engine)
|
||||
}
|
||||
|
||||
classes.dependsOn 'compilerClasses', 'cli_bcClasses'
|
||||
@@ -254,9 +257,10 @@ RepoArtifacts.javadocJar(project)
|
||||
Configure 'test' task
|
||||
*/
|
||||
|
||||
TasksKt.projectTest(project)
|
||||
TasksKt.projectTest(project, JUnitMode.JUnit5)
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
dependsOn ':kotlin-native:dist'
|
||||
systemProperty("org.jetbrains.kotlin.native.home", distDir.canonicalPath)
|
||||
workingDir(rootProject.projectDir)
|
||||
|
||||
+3
-89
@@ -53,8 +53,6 @@ object Fe10ObjCExportHeaderGenerator : AbstractObjCExportHeaderGeneratorTest.Obj
|
||||
}
|
||||
|
||||
private fun createObjCExportHeaderGenerator(disposable: Disposable, root: File): ObjCExportHeaderGenerator {
|
||||
val compilerConfiguration = createCompilerConfiguration()
|
||||
|
||||
val mapper = ObjCExportMapper(
|
||||
unitSuspendFunctionExport = UnitSuspendFunctionObjCExport.DEFAULT
|
||||
)
|
||||
@@ -69,106 +67,22 @@ object Fe10ObjCExportHeaderGenerator : AbstractObjCExportHeaderGeneratorTest.Obj
|
||||
override fun getAdditionalPrefix(module: ModuleDescriptor): String? = null
|
||||
override val objcGenerics: Boolean = true
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
val environment: KotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
|
||||
parentDisposable = disposable,
|
||||
initialConfiguration = compilerConfiguration,
|
||||
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||
)
|
||||
|
||||
val environment: KotlinCoreEnvironment = createKotlinCoreEnvironment(disposable)
|
||||
val phaseContext = BasicPhaseContext(
|
||||
KonanConfig(environment.project, compilerConfiguration)
|
||||
KonanConfig(environment.project, environment.configuration)
|
||||
)
|
||||
|
||||
val kotlinFiles = root.walkTopDown().filter { it.isFile }.filter { it.extension == "kt" }.toList()
|
||||
|
||||
return ObjCExportHeaderGeneratorImpl(
|
||||
context = phaseContext,
|
||||
moduleDescriptors = listOf(getModuleDescriptor(environment, kotlinFiles)),
|
||||
moduleDescriptors = listOf(createModuleDescriptor(environment, kotlinFiles)),
|
||||
mapper = mapper,
|
||||
namer = namer,
|
||||
problemCollector = ObjCExportProblemCollector.SILENT,
|
||||
objcGenerics = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun getModuleDescriptor(
|
||||
environment: KotlinCoreEnvironment, kotlinFiles: List<File>
|
||||
): ModuleDescriptor {
|
||||
val psiFactory = KtPsiFactory(environment.project)
|
||||
val kotlinPsiFiles = kotlinFiles.map { file -> psiFactory.createFile(file.name, KtTestUtil.doLoadFile(file)) }
|
||||
|
||||
val analysisResult = CommonResolverForModuleFactory.analyzeFiles(
|
||||
files = kotlinPsiFiles,
|
||||
moduleName = Name.special("<test_module>"),
|
||||
dependOnBuiltIns = true,
|
||||
languageVersionSettings = environment.configuration.languageVersionSettings,
|
||||
targetPlatform = CommonPlatforms.defaultCommonPlatform,
|
||||
targetEnvironment = CompilerEnvironment,
|
||||
dependenciesContainer = DependenciesContainerImpl,
|
||||
) { content ->
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}
|
||||
|
||||
return analysisResult.moduleDescriptor
|
||||
}
|
||||
|
||||
|
||||
private object DependenciesContainerImpl : CommonDependenciesContainer {
|
||||
override val moduleInfos: List<ModuleInfo> get() = listOf(DefaultBuiltInsModuleInfo, KotlinNativeStdlibModuleInfo)
|
||||
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
override val refinesModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit
|
||||
override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null
|
||||
|
||||
private val stdlibModuleDescriptor = KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||
library = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File("$konanHomePath/klib/common/stdlib")),
|
||||
languageVersionSettings = createLanguageVersionSettings(),
|
||||
builtIns = DefaultBuiltIns.Instance,
|
||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||
packageAccessHandler = null
|
||||
).also { it.setDependencies(it) }
|
||||
|
||||
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor {
|
||||
if (moduleInfo == DefaultBuiltInsModuleInfo) return DefaultBuiltIns.Instance.builtInsModule
|
||||
if (moduleInfo == KotlinNativeStdlibModuleInfo) return stdlibModuleDescriptor
|
||||
error("Unknown module info $moduleInfo")
|
||||
}
|
||||
}
|
||||
|
||||
private object DefaultBuiltInsModuleInfo : ModuleInfo {
|
||||
override val name get() = DefaultBuiltIns.Instance.builtInsModule.name
|
||||
override fun dependencies() = listOf(this)
|
||||
override fun dependencyOnBuiltIns() = ModuleInfo.DependencyOnBuiltIns.LAST
|
||||
override val platform get() = NativePlatforms.unspecifiedNativePlatform
|
||||
override val analyzerServices get() = NativePlatformAnalyzerServices
|
||||
}
|
||||
|
||||
private object KotlinNativeStdlibModuleInfo : ModuleInfo {
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices = NativePlatformAnalyzerServices
|
||||
override val name: Name = Name.special("<stdlib>")
|
||||
override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform
|
||||
override fun dependencies(): List<ModuleInfo> = listOf(this)
|
||||
}
|
||||
|
||||
private fun createCompilerConfiguration(): CompilerConfiguration {
|
||||
val configuration = KotlinTestUtils.newConfiguration()
|
||||
configuration.put(KONAN_HOME, konanHomePath)
|
||||
configuration.put(CLIConfigurationKeys.FLEXIBLE_PHASE_CONFIG, createFlexiblePhaseConfig(K2NativeCompilerArguments()))
|
||||
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, createLanguageVersionSettings())
|
||||
configuration.put(KonanConfigKeys.PRODUCE, CompilerOutputKind.FRAMEWORK)
|
||||
configuration.put(KonanConfigKeys.AUTO_CACHEABLE_FROM, emptyList())
|
||||
configuration.put(KonanConfigKeys.CACHE_DIRECTORIES, emptyList())
|
||||
configuration.put(KonanConfigKeys.CACHED_LIBRARIES, emptyMap())
|
||||
configuration.put(KonanConfigKeys.FRAMEWORK_IMPORT_HEADERS, emptyList())
|
||||
configuration.put(KonanConfigKeys.EXPORT_KDOC, true)
|
||||
return configuration
|
||||
}
|
||||
|
||||
private fun createLanguageVersionSettings() = LanguageVersionSettingsImpl(
|
||||
languageVersion = LanguageVersion.LATEST_STABLE,
|
||||
apiVersion = ApiVersion.LATEST_STABLE
|
||||
)
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.backend.konan.KlibFactories
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2NativeCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.createFlexiblePhaseConfig
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.konan.NativePlatforms
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import java.io.File
|
||||
|
||||
fun createModuleDescriptor(
|
||||
environment: KotlinCoreEnvironment,
|
||||
tempDir: File,
|
||||
kotlinSources: List<String>
|
||||
): ModuleDescriptor {
|
||||
val testModuleRoot = tempDir.resolve("testModule")
|
||||
testModuleRoot.mkdirs()
|
||||
val testSourcesFiles = kotlinSources.mapIndexed { index, kotlinSource ->
|
||||
testModuleRoot.resolve("TestSources$index.kt").apply {
|
||||
writeText(kotlinSource)
|
||||
}
|
||||
}
|
||||
return createModuleDescriptor(environment, testSourcesFiles)
|
||||
}
|
||||
|
||||
fun createModuleDescriptor(
|
||||
environment: KotlinCoreEnvironment,
|
||||
kotlinFiles: List<File>,
|
||||
): ModuleDescriptor {
|
||||
val psiFactory = KtPsiFactory(environment.project)
|
||||
val kotlinPsiFiles = kotlinFiles.map { file -> psiFactory.createFile(file.name, KtTestUtil.doLoadFile(file)) }
|
||||
|
||||
val analysisResult = CommonResolverForModuleFactory.analyzeFiles(
|
||||
files = kotlinPsiFiles,
|
||||
moduleName = Name.special("<test_module>"),
|
||||
dependOnBuiltIns = true,
|
||||
languageVersionSettings = environment.configuration.languageVersionSettings,
|
||||
targetPlatform = CommonPlatforms.defaultCommonPlatform,
|
||||
targetEnvironment = CompilerEnvironment,
|
||||
dependenciesContainer = DependenciesContainerImpl,
|
||||
) { content ->
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}
|
||||
|
||||
return analysisResult.moduleDescriptor
|
||||
}
|
||||
|
||||
fun createKotlinCoreEnvironment(
|
||||
disposable: Disposable, compilerConfiguration: CompilerConfiguration = createCompilerConfiguration()
|
||||
): KotlinCoreEnvironment {
|
||||
return KotlinCoreEnvironment.createForTests(
|
||||
parentDisposable = disposable,
|
||||
initialConfiguration = compilerConfiguration,
|
||||
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||
)
|
||||
}
|
||||
|
||||
private fun createCompilerConfiguration(): CompilerConfiguration {
|
||||
val configuration = KotlinTestUtils.newConfiguration()
|
||||
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, createLanguageVersionSettings())
|
||||
configuration.put(CLIConfigurationKeys.FLEXIBLE_PHASE_CONFIG, createFlexiblePhaseConfig(K2NativeCompilerArguments()))
|
||||
configuration.put(KonanConfigKeys.KONAN_HOME, konanHomePath)
|
||||
configuration.put(KonanConfigKeys.PRODUCE, CompilerOutputKind.FRAMEWORK)
|
||||
configuration.put(KonanConfigKeys.AUTO_CACHEABLE_FROM, emptyList())
|
||||
configuration.put(KonanConfigKeys.CACHE_DIRECTORIES, emptyList())
|
||||
configuration.put(KonanConfigKeys.CACHED_LIBRARIES, emptyMap())
|
||||
configuration.put(KonanConfigKeys.FRAMEWORK_IMPORT_HEADERS, emptyList())
|
||||
configuration.put(KonanConfigKeys.EXPORT_KDOC, true)
|
||||
return configuration
|
||||
}
|
||||
|
||||
private fun createLanguageVersionSettings() = LanguageVersionSettingsImpl(
|
||||
languageVersion = LanguageVersion.LATEST_STABLE,
|
||||
apiVersion = ApiVersion.LATEST_STABLE
|
||||
)
|
||||
|
||||
private object DependenciesContainerImpl : CommonDependenciesContainer {
|
||||
override val moduleInfos: List<ModuleInfo> get() = listOf(DefaultBuiltInsModuleInfo, KotlinNativeStdlibModuleInfo)
|
||||
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
override val refinesModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit
|
||||
override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null
|
||||
|
||||
private val stdlibModuleDescriptor = KlibFactories.DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||
library = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File("$konanHomePath/klib/common/stdlib")),
|
||||
languageVersionSettings = createLanguageVersionSettings(),
|
||||
builtIns = DefaultBuiltIns.Instance,
|
||||
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||
packageAccessHandler = null
|
||||
).also { it.setDependencies(it) }
|
||||
|
||||
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor {
|
||||
if (moduleInfo == DefaultBuiltInsModuleInfo) return DefaultBuiltIns.Instance.builtInsModule
|
||||
if (moduleInfo == KotlinNativeStdlibModuleInfo) return stdlibModuleDescriptor
|
||||
error("Unknown module info $moduleInfo")
|
||||
}
|
||||
}
|
||||
|
||||
private object DefaultBuiltInsModuleInfo : ModuleInfo {
|
||||
override val name get() = DefaultBuiltIns.Instance.builtInsModule.name
|
||||
override fun dependencies() = listOf(this)
|
||||
override fun dependencyOnBuiltIns() = ModuleInfo.DependencyOnBuiltIns.LAST
|
||||
override val platform get() = NativePlatforms.unspecifiedNativePlatform
|
||||
override val analyzerServices get() = NativePlatformAnalyzerServices
|
||||
}
|
||||
|
||||
private object KotlinNativeStdlibModuleInfo : ModuleInfo {
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices = NativePlatformAnalyzerServices
|
||||
override val name: Name = Name.special("<stdlib>")
|
||||
override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform
|
||||
override fun dependencies(): List<ModuleInfo> = listOf(this)
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Test Environment that enables quick 'inline' creation of [ModuleDescriptor] instances.
|
||||
*
|
||||
* # Examples
|
||||
* ## Test operating on a single Kotlin Source file:
|
||||
*
|
||||
* ```kotlin
|
||||
* class MyTest : InlineSourceTestEnvironment {
|
||||
* @Test
|
||||
* fun `test - my unit`() {
|
||||
* val moduleDescriptor = createModuleDescriptor("""
|
||||
* package com.example
|
||||
* class MyClassUnderTest
|
||||
* """.trimIndent()
|
||||
* )
|
||||
*
|
||||
* // my test!
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ## Test that requires several source files (e.g. multiple packages are involved)
|
||||
* ```kotlin
|
||||
* @Test
|
||||
* fun `test - my unit`() {
|
||||
* val moduleDescriptor = createModuleDescriptor {
|
||||
* source("class Foo")
|
||||
* source("""
|
||||
* package com.example
|
||||
* class Foo
|
||||
* """)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
interface InlineSourceTestEnvironment {
|
||||
val kotlinCoreEnvironment: KotlinCoreEnvironment
|
||||
val testDisposable: Disposable
|
||||
val testTempDir: File
|
||||
}
|
||||
|
||||
|
||||
interface InlineSourceCodeCollector {
|
||||
fun source(@Language("kotlin") sourceCode: String)
|
||||
}
|
||||
|
||||
fun InlineSourceTestEnvironment.createModuleDescriptor(@Language("kotlin") sourceCode: String): ModuleDescriptor =
|
||||
createModuleDescriptor(kotlinCoreEnvironment, testTempDir, listOf(sourceCode))
|
||||
|
||||
fun InlineSourceTestEnvironment.createModuleDescriptor(build: InlineSourceCodeCollector.() -> Unit): ModuleDescriptor {
|
||||
val sources = mutableListOf<String>()
|
||||
object : InlineSourceCodeCollector {
|
||||
override fun source(sourceCode: String) {
|
||||
sources.add(sourceCode)
|
||||
}
|
||||
}.build()
|
||||
|
||||
return createModuleDescriptor(kotlinCoreEnvironment, testTempDir, sources.toList())
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.testUtils
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.UnitSuspendFunctionObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportMapper
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamerImpl
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportProblemCollector
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
internal fun createObjCExportNamerConfiguration(
|
||||
topLevelNamePrefix: String = "",
|
||||
additionalPrefix: (moduleName: Name) -> String? = { null }
|
||||
): ObjCExportNamer.Configuration {
|
||||
return object : ObjCExportNamer.Configuration {
|
||||
override val topLevelNamePrefix: String get() = topLevelNamePrefix
|
||||
override fun getAdditionalPrefix(module: ModuleDescriptor): String? = additionalPrefix(module.name)
|
||||
override val objcGenerics: Boolean = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createObjCExportMapper(
|
||||
deprecationResolver: DeprecationResolver? = null,
|
||||
local: Boolean = false,
|
||||
unitSuspendFunctionObjCExport: UnitSuspendFunctionObjCExport = UnitSuspendFunctionObjCExport.DEFAULT
|
||||
): ObjCExportMapper {
|
||||
return ObjCExportMapper(deprecationResolver, local, unitSuspendFunctionObjCExport)
|
||||
}
|
||||
|
||||
internal fun createObjCExportNamer(
|
||||
configuration: ObjCExportNamer.Configuration = createObjCExportNamerConfiguration(),
|
||||
builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
|
||||
local: Boolean = false,
|
||||
problemCollector: ObjCExportProblemCollector = ObjCExportProblemCollector.SILENT,
|
||||
mapper: ObjCExportMapper = createObjCExportMapper(local = local),
|
||||
): ObjCExportNamer {
|
||||
return ObjCExportNamerImpl(
|
||||
builtIns = builtIns,
|
||||
mapper = mapper,
|
||||
local = local,
|
||||
problemCollector = problemCollector,
|
||||
configuration = configuration
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.konan.tests
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportHeaderGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.AbstractFE10ObjCExportHeaderGeneratorTest
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.tests
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfig
|
||||
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.TypeAttributes
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
* This test shall cover test the [ObjCExportMapper];
|
||||
* The test will invoke the type mapping a known type (e.g. List<Int>) and check
|
||||
* the corresponding conversion to [ObjCNonNullReferenceType].
|
||||
*
|
||||
* The test also acts as quick entry point for debugging the [ObjCExportMapper]
|
||||
*/
|
||||
class ObjCExportMapperTest : InlineSourceTestEnvironment {
|
||||
override val testDisposable = Disposer.newDisposable()
|
||||
override val kotlinCoreEnvironment: KotlinCoreEnvironment = createKotlinCoreEnvironment(testDisposable)
|
||||
|
||||
@TempDir
|
||||
override lateinit var testTempDir: File
|
||||
|
||||
@AfterEach
|
||||
fun dispose() {
|
||||
Disposer.dispose(testDisposable)
|
||||
}
|
||||
|
||||
/**
|
||||
* No 'type mapper' expected for a simple Kotlin class like 'Foo'.
|
||||
* Only well known standard types (List, ...) will get mapped to their corresponding
|
||||
* ObjC counterpart (NSArray, ...)
|
||||
*/
|
||||
@Test
|
||||
fun `test - simple class`() {
|
||||
val module = createModuleDescriptor("class Foo")
|
||||
val foo = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
|
||||
assertNull(createObjCExportMapper().getCustomTypeMapper(foo))
|
||||
}
|
||||
|
||||
/**
|
||||
* Will test ObjC type mapping from List<Int> to NSArray<Int *> *
|
||||
*/
|
||||
@Test
|
||||
fun `test - List of int`() {
|
||||
/* We are only using built in / stdlib parts, so we can provide empty source code */
|
||||
val module = createModuleDescriptor("")
|
||||
val objcExportMapper = createObjCExportMapper()
|
||||
val objcExportNamer = createObjCExportNamer(mapper = objcExportMapper)
|
||||
|
||||
val objcExportTranslator = ObjCExportTranslatorImpl(
|
||||
generator = ObjCExportHeaderGeneratorImpl(
|
||||
context = BasicPhaseContext(
|
||||
KonanConfig(kotlinCoreEnvironment.project, kotlinCoreEnvironment.configuration)
|
||||
),
|
||||
moduleDescriptors = listOf(module),
|
||||
mapper = objcExportMapper,
|
||||
namer = objcExportNamer,
|
||||
problemCollector = ObjCExportProblemCollector.SILENT,
|
||||
objcGenerics = true
|
||||
),
|
||||
mapper = objcExportMapper,
|
||||
namer = objcExportNamer,
|
||||
problemCollector = ObjCExportProblemCollector.SILENT,
|
||||
objcGenerics = true
|
||||
)
|
||||
|
||||
val listClassDescriptor = module.findClassAcrossModuleDependencies(ClassId.fromString("kotlin/collections/List"))!!
|
||||
val intClassDescriptor = module.findClassAcrossModuleDependencies(ClassId.fromString("kotlin/Int"))!!
|
||||
|
||||
/* Represents List<Int> */
|
||||
val listOfIntType = KotlinTypeFactory.simpleNotNullType(TypeAttributes.Empty, listClassDescriptor, listOf(
|
||||
TypeProjectionImpl(KotlinTypeFactory.simpleNotNullType(TypeAttributes.Empty, intClassDescriptor, emptyList()))
|
||||
))
|
||||
|
||||
val typeMapper = assertNotNull(objcExportMapper.getCustomTypeMapper(listClassDescriptor))
|
||||
assertEquals(ClassId.fromString("kotlin/collections/List"), typeMapper.mappedClassId)
|
||||
val listOfIntMapped = typeMapper.mapType(listOfIntType, objcExportTranslator, objCExportScope = ObjCRootExportScope)
|
||||
|
||||
assertEquals(ObjCClassType("NSArray", typeArguments = listOf(ObjCClassType("Int"))), listOfIntMapped)
|
||||
assertEquals("NSArray<Int *> *", listOfIntMapped.toString())
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.tests
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.enumEntries
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer.ClassOrProtocolName
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer.PropertyName
|
||||
import org.jetbrains.kotlin.backend.konan.testUtils.*
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.resolve.scopes.findFirstVariable
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
/**
|
||||
* ## Test Scope
|
||||
* This test will cover basic cases of the [ObjCExportNamer]. <br>
|
||||
*
|
||||
* The __input__ to this test will be descriptors defined as 'inline source code'.
|
||||
* (e.g. a String like "class Foo").<br>
|
||||
*
|
||||
* The __output__ of this test will be result of the request to the [ObjCExportNamer].
|
||||
* (e.g. the [ClassOrProtocolName])
|
||||
*/
|
||||
class ObjCExportNamerTest : InlineSourceTestEnvironment {
|
||||
|
||||
override val testDisposable = Disposer.newDisposable()
|
||||
|
||||
override val kotlinCoreEnvironment = createKotlinCoreEnvironment(testDisposable)
|
||||
|
||||
@TempDir
|
||||
override lateinit var testTempDir: File
|
||||
|
||||
@AfterEach
|
||||
fun dispose() {
|
||||
Disposer.dispose(testDisposable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple class`() {
|
||||
val module = createModuleDescriptor("class Foo")
|
||||
val clazz = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
|
||||
assertEquals(
|
||||
ClassOrProtocolName("Foo", "Foo"),
|
||||
createObjCExportNamer().getClassOrProtocolName(clazz)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple class - with prefix`() {
|
||||
val module = createModuleDescriptor("class Foo")
|
||||
val clazz = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
|
||||
assertEquals(
|
||||
ClassOrProtocolName("Foo", "XFoo"),
|
||||
createObjCExportNamer(createObjCExportNamerConfiguration(topLevelNamePrefix = "X")).getClassOrProtocolName(clazz)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple function`() {
|
||||
val module = createModuleDescriptor("fun foo() = 42")
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findSingleFunction(Name.identifier("foo"))
|
||||
assertEquals("foo()", createObjCExportNamer().getSwiftName(foo))
|
||||
assertEquals("foo", createObjCExportNamer().getSelector(foo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - function with parameters`() {
|
||||
val module = createModuleDescriptor("fun foo(a: Int, b: Int) = a + b")
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findSingleFunction(Name.identifier("foo"))
|
||||
assertEquals("foo(a:b:)", createObjCExportNamer().getSwiftName(foo))
|
||||
assertEquals("fooA:b:", createObjCExportNamer().getSelector(foo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple property`() {
|
||||
val module = createModuleDescriptor("val foo = 42")
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findFirstVariable("foo") { true }!!
|
||||
assertEquals(PropertyName("foo", "foo"), createObjCExportNamer().getPropertyName(foo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple property - with prefix`() {
|
||||
val module = createModuleDescriptor("val foo = 42")
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findFirstVariable("foo") { true }!!
|
||||
assertEquals(
|
||||
PropertyName("foo", "foo"),
|
||||
createObjCExportNamer(createObjCExportNamerConfiguration(topLevelNamePrefix = "X")).getPropertyName(foo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - function inside class`() {
|
||||
val module = createModuleDescriptor("""
|
||||
package bar
|
||||
class Foo {
|
||||
fun someFunction(a: Int, b: Int) = a + b
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val fooClass = module.findClassAcrossModuleDependencies(ClassId.fromString("bar/Foo"))!!
|
||||
val someFunction = fooClass.unsubstitutedMemberScope.findSingleFunction(Name.identifier("someFunction"))
|
||||
assertEquals("someFunction(a:b:)", createObjCExportNamer().getSwiftName(someFunction))
|
||||
assertEquals("someFunctionA:b:", createObjCExportNamer().getSelector(someFunction))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - class with ObjCName annotation`() {
|
||||
val module = createModuleDescriptor("""
|
||||
@kotlin.native.ObjCName("ObjCFoo", "SwiftFoo")
|
||||
class Foo
|
||||
""".trimIndent())
|
||||
|
||||
val fooClass = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
|
||||
assertEquals(
|
||||
ClassOrProtocolName(swiftName = "SwiftFoo", objCName = "ObjCFoo"),
|
||||
createObjCExportNamer().getClassOrProtocolName(fooClass)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple parameter`() {
|
||||
val module = createModuleDescriptor("fun foo(a: Int)")
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findSingleFunction(Name.identifier("foo"))
|
||||
val parameterA = foo.valueParameters.find { it.name == Name.identifier("a") }!!
|
||||
assertEquals("a", createObjCExportNamer().getParameterName(parameterA))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - parameter with ObjCName annotation`() {
|
||||
val module = createModuleDescriptor("""
|
||||
import kotlin.native.ObjCName
|
||||
fun foo(@ObjCName("aObjC", "aSwift") a: Int)
|
||||
""".trimIndent())
|
||||
|
||||
val foo = module.getPackage(FqName.ROOT).memberScope.findSingleFunction(Name.identifier("foo"))
|
||||
val parameterA = foo.valueParameters.find { it.name == Name.identifier("a") }!!
|
||||
assertEquals("aObjC", createObjCExportNamer().getParameterName(parameterA))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - class mangling`() {
|
||||
val module = createModuleDescriptor {
|
||||
source("""
|
||||
package a
|
||||
class Foo
|
||||
""".trimIndent())
|
||||
source("""
|
||||
package b
|
||||
class Foo
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
val aFoo = module.findClassAcrossModuleDependencies(ClassId.fromString("a/Foo"))!!
|
||||
val bFoo = module.findClassAcrossModuleDependencies(ClassId.fromString("b/Foo"))!!
|
||||
|
||||
val namer = createObjCExportNamer()
|
||||
assertEquals(ClassOrProtocolName("Foo", "Foo"), namer.getClassOrProtocolName(aFoo))
|
||||
assertEquals(ClassOrProtocolName("Foo_", "Foo_"), namer.getClassOrProtocolName(bFoo))
|
||||
|
||||
/* Check caching in namer: Should return same name again */
|
||||
assertEquals(ClassOrProtocolName("Foo", "Foo"), namer.getClassOrProtocolName(aFoo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple enum`() {
|
||||
val module = createModuleDescriptor("""
|
||||
enum class Foo {
|
||||
A, B, C
|
||||
}
|
||||
""".trimIndent())
|
||||
|
||||
val foo = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
|
||||
val fooA = foo.enumEntries.find { it.name == Name.identifier("A") }!!
|
||||
val namer = createObjCExportNamer()
|
||||
|
||||
assertEquals(ClassOrProtocolName("Foo", "Foo"), namer.getClassOrProtocolName(foo))
|
||||
assertEquals("a", namer.getEnumEntrySelector(fooA))
|
||||
assertEquals("a", namer.getEnumEntrySwiftName(fooA))
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,11 @@ enum class JUnitMode {
|
||||
*/
|
||||
fun projectTest(project: Project) = project.projectTest()
|
||||
|
||||
/**
|
||||
* Convenience function to expose Project.projectTest for groovy
|
||||
*/
|
||||
fun projectTest(project: Project, jUnitMode: JUnitMode) = project.projectTest(jUnitMode = jUnitMode)
|
||||
|
||||
/**
|
||||
* @param parallel is redundant if @param jUnit5Enabled is true, because
|
||||
* JUnit5 supports parallel test execution by itself, without gradle help
|
||||
|
||||
Reference in New Issue
Block a user