[Commonizer] Clean-up in AbstractCommonizationFromSourcesTest
This commit is contained in:
+199
-113
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer
|
package org.jetbrains.kotlin.descriptors.commonizer
|
||||||
|
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.testFramework.PlatformTestUtil.lowercaseFirstLetter
|
import com.intellij.testFramework.PlatformTestUtil.lowercaseFirstLetter
|
||||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.assertCommonizationPerformed
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.assertCommonizationPerformed
|
||||||
@@ -18,14 +20,15 @@ import org.jetbrains.kotlin.descriptors.commonizer.utils.assertModulesAreEqual
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.assertValidModule
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.assertValidModule
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils.*
|
import org.jetbrains.kotlin.test.KotlinTestUtils.*
|
||||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
@ExperimentalContracts
|
@ExperimentalContracts
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
||||||
companion object {
|
companion object {
|
||||||
init {
|
init {
|
||||||
@@ -35,137 +38,45 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
|||||||
fun Collection<ModuleDescriptor>.eachModuleAsTarget() = mapIndexed { index, moduleDescriptor ->
|
fun Collection<ModuleDescriptor>.eachModuleAsTarget() = mapIndexed { index, moduleDescriptor ->
|
||||||
InputTarget("target_$index") to moduleDescriptor
|
InputTarget("target_$index") to moduleDescriptor
|
||||||
}.toMap().toCommonizationParameters()
|
}.toMap().toCommonizationParameters()
|
||||||
|
|
||||||
fun Map<InputTarget, ModuleDescriptor>.toCommonizationParameters() = Parameters().also {
|
|
||||||
forEach { (target, moduleDescriptor) ->
|
|
||||||
it.addTarget(
|
|
||||||
TargetProvider(
|
|
||||||
target = target,
|
|
||||||
builtInsClass = moduleDescriptor.builtIns::class.java,
|
|
||||||
builtInsProvider = BuiltInsProvider.wrap(moduleDescriptor.builtIns),
|
|
||||||
modulesProvider = ModulesProvider.wrap(moduleDescriptor)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createEnvironment(bareModuleName: String): KotlinCoreEnvironment {
|
private fun getTestDataDir(): File {
|
||||||
check(Name.isValidIdentifier(bareModuleName))
|
val testCaseDir = lowercaseFirstLetter(
|
||||||
val configuration = newConfiguration()
|
this::class.java.simpleName.substringBefore("FromSources").substringBefore("Test"),
|
||||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, bareModuleName)
|
true
|
||||||
|
)
|
||||||
|
val testDir = testDirectoryName
|
||||||
|
|
||||||
return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.METADATA_CONFIG_FILES)
|
return File(getHomeDirectory())
|
||||||
|
.resolve("native/commonizer/testData")
|
||||||
|
.resolve(testCaseDir)
|
||||||
|
.resolve(testDir)
|
||||||
|
.also(::assertIsDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val KotlinCoreEnvironment.moduleName: Name
|
|
||||||
get() {
|
|
||||||
val bareModuleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
|
||||||
return Name.special("<$bareModuleName>")
|
|
||||||
}
|
|
||||||
|
|
||||||
protected val testDataDir: File
|
|
||||||
get() {
|
|
||||||
val testCaseDir = lowercaseFirstLetter(
|
|
||||||
this::class.java.simpleName.substringBefore("FromSources").substringBefore("Test"),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
val testDir = testDirectoryName
|
|
||||||
|
|
||||||
return File(getHomeDirectory())
|
|
||||||
.resolve("native/commonizer/testData")
|
|
||||||
.resolve(testCaseDir)
|
|
||||||
.resolve(testDir)
|
|
||||||
.also(::assertIsDirectory)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected val sourceModuleRoots: Triple<Set<File>, Set<File>, File>
|
|
||||||
get() {
|
|
||||||
val testDataDir = testDataDir
|
|
||||||
|
|
||||||
val originalRoots = testDataDir
|
|
||||||
.resolve("original")
|
|
||||||
.also(::assertIsDirectory)
|
|
||||||
.listFiles()
|
|
||||||
?.toSet()
|
|
||||||
?.also { it.forEach(::assertIsDirectory) }
|
|
||||||
|
|
||||||
val commonizedRoots = testDataDir
|
|
||||||
.resolve("commonized")
|
|
||||||
.also(::assertIsDirectory)
|
|
||||||
.listFiles()
|
|
||||||
?.toSet()
|
|
||||||
?.also { it.forEach(::assertIsDirectory) }
|
|
||||||
|
|
||||||
val commonRoot = commonizedRoots?.singleOrNull { it.name == "common" }
|
|
||||||
|
|
||||||
check(
|
|
||||||
!originalRoots.isNullOrEmpty() && !commonizedRoots.isNullOrEmpty() && commonRoot != null
|
|
||||||
&& (originalRoots + commonRoot).map { it.name }.toSet() == commonizedRoots.map { it.name }.toSet()
|
|
||||||
) {
|
|
||||||
"Source module misconfiguration in $testDataDir"
|
|
||||||
}
|
|
||||||
|
|
||||||
return Triple(originalRoots, commonizedRoots - commonRoot, commonRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected val sourceModuleDescriptors: Pair<Map<InputTarget, ModuleDescriptor>, Map<Target, ModuleDescriptor>>
|
|
||||||
get() {
|
|
||||||
fun analyzeTarget(targetRoot: File): ModuleDescriptor {
|
|
||||||
val environment = createEnvironment(targetRoot.parentFile.parentFile.name)
|
|
||||||
val psiFactory = KtPsiFactory(environment.project)
|
|
||||||
|
|
||||||
val psiFiles = targetRoot.walkTopDown()
|
|
||||||
.filter { it.isFile }
|
|
||||||
.map { psiFactory.createFile(it.name, doLoadFile(it)) }
|
|
||||||
.toList()
|
|
||||||
|
|
||||||
return CommonResolverForModuleFactory.analyzeFiles(
|
|
||||||
files = psiFiles,
|
|
||||||
moduleName = environment.moduleName,
|
|
||||||
dependOnBuiltIns = true,
|
|
||||||
languageVersionSettings = environment.configuration.languageVersionSettings,
|
|
||||||
targetPlatform = CommonPlatforms.defaultCommonPlatform
|
|
||||||
) { content ->
|
|
||||||
environment.createPackagePartProvider(content.moduleContentScope)
|
|
||||||
}.moduleDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
val originalModules = sourceModuleRoots.first
|
|
||||||
.map { InputTarget(it.name) to analyzeTarget(it) }
|
|
||||||
.toMap()
|
|
||||||
|
|
||||||
val commonizedModules = sourceModuleRoots.second
|
|
||||||
.map { InputTarget(it.name) to analyzeTarget(it) }
|
|
||||||
.toMap()
|
|
||||||
|
|
||||||
val commonModule = OutputTarget(commonizedModules.keys) to analyzeTarget(sourceModuleRoots.third)
|
|
||||||
|
|
||||||
return originalModules to commonizedModules + commonModule
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun doTestSuccessfulCommonization() {
|
protected fun doTestSuccessfulCommonization() {
|
||||||
val (originalModules, commonizedModules) = sourceModuleDescriptors
|
val sourceModuleRoots: SourceModuleRoots = SourceModuleRoots.load(getTestDataDir())
|
||||||
|
val analyzedModules: AnalyzedModules = AnalyzedModules.create(sourceModuleRoots, testRootDisposable)
|
||||||
|
|
||||||
val result = runCommonization(originalModules.toCommonizationParameters())
|
val result: Result = runCommonization(analyzedModules.toCommonizationParameters())
|
||||||
assertCommonizationPerformed(result)
|
assertCommonizationPerformed(result)
|
||||||
|
|
||||||
val commonTarget = commonizedModules.keys.filterIsInstance<OutputTarget>().single()
|
val commonTarget: OutputTarget = analyzedModules.commonizedCommonModule.target
|
||||||
assertEquals(commonTarget, result.commonTarget)
|
assertEquals(commonTarget, result.commonTarget)
|
||||||
|
|
||||||
val commonModuleAsExpected = commonizedModules.getValue(commonTarget)
|
val commonModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedCommonModule.module
|
||||||
val commonModuleByCommonizer = result.modulesByTargets.getValue(commonTarget).single()
|
val commonModuleByCommonizer: ModuleDescriptor = result.modulesByTargets.getValue(commonTarget).single()
|
||||||
|
|
||||||
assertValidModule(commonModuleAsExpected)
|
assertValidModule(commonModuleAsExpected)
|
||||||
assertValidModule(commonModuleByCommonizer)
|
assertValidModule(commonModuleByCommonizer)
|
||||||
assertModulesAreEqual(commonModuleAsExpected, commonModuleByCommonizer, "\"$commonTarget\" target")
|
assertModulesAreEqual(commonModuleAsExpected, commonModuleByCommonizer, "\"$commonTarget\" target")
|
||||||
|
|
||||||
val concreteTargets = commonizedModules.keys - commonTarget
|
val concreteTargets: Set<InputTarget> = analyzedModules.commonizedPlatformModules.keys
|
||||||
assertEquals(concreteTargets, result.concreteTargets)
|
assertEquals(concreteTargets, result.concreteTargets)
|
||||||
|
|
||||||
for (target in concreteTargets) {
|
for (target in concreteTargets) {
|
||||||
val targetModuleAsExpected = commonizedModules.getValue(target)
|
val targetModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedPlatformModules.getValue(target).module
|
||||||
val targetModuleByCommonizer = result.modulesByTargets.getValue(target).single()
|
val targetModuleByCommonizer: ModuleDescriptor = result.modulesByTargets.getValue(target).single()
|
||||||
|
|
||||||
assertValidModule(targetModuleAsExpected)
|
assertValidModule(targetModuleAsExpected)
|
||||||
assertValidModule(targetModuleByCommonizer)
|
assertValidModule(targetModuleByCommonizer)
|
||||||
@@ -173,3 +84,178 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val COMMON_TARGET_NAME = "common"
|
||||||
|
|
||||||
|
private data class SourceModuleRoot(
|
||||||
|
val targetName: String,
|
||||||
|
val root: File
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
assertIsDirectory(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun load(directory: File): SourceModuleRoot = SourceModuleRoot(
|
||||||
|
targetName = directory.name,
|
||||||
|
root = directory
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SourceModuleRoots(
|
||||||
|
val originalPlatformRoots: Map<String, SourceModuleRoot>,
|
||||||
|
val commonizedPlatformRoots: Map<String, SourceModuleRoot>,
|
||||||
|
val commonizedCommonRoot: SourceModuleRoot
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
check(originalPlatformRoots.isNotEmpty())
|
||||||
|
check(COMMON_TARGET_NAME !in originalPlatformRoots)
|
||||||
|
check(originalPlatformRoots.keys == commonizedPlatformRoots.keys)
|
||||||
|
check(commonizedCommonRoot.targetName == COMMON_TARGET_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun load(dataDir: File): SourceModuleRoots = try {
|
||||||
|
val originalRoots = listRoots(dataDir, ORIGINAL_ROOTS_DIR)
|
||||||
|
val commonizedRoots = listRoots(dataDir, COMMONIZED_ROOTS_DIR)
|
||||||
|
|
||||||
|
SourceModuleRoots(
|
||||||
|
originalPlatformRoots = originalRoots,
|
||||||
|
commonizedPlatformRoots = commonizedRoots - COMMON_TARGET_NAME,
|
||||||
|
commonizedCommonRoot = commonizedRoots.getValue(COMMON_TARGET_NAME)
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
fail("Source module misconfiguration in $dataDir", cause = e)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ORIGINAL_ROOTS_DIR = "original"
|
||||||
|
private const val COMMONIZED_ROOTS_DIR = "commonized"
|
||||||
|
|
||||||
|
private fun listRoots(dataDir: File, rootsDirName: String): Map<String, SourceModuleRoot> =
|
||||||
|
dataDir.resolve(rootsDirName).listFiles()?.toSet().orEmpty().map(SourceModuleRoot::load).associateBy { it.targetName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnalyzedModule<T : Target>(
|
||||||
|
val target: T,
|
||||||
|
val module: ModuleDescriptor
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun <T : Target> create(
|
||||||
|
target: T,
|
||||||
|
sourceModuleRoot: SourceModuleRoot,
|
||||||
|
parentDisposable: Disposable
|
||||||
|
): AnalyzedModule<T> {
|
||||||
|
val moduleName: String = sourceModuleRoot.root.parentFile.parentFile.name
|
||||||
|
check(Name.isValidIdentifier(moduleName))
|
||||||
|
|
||||||
|
return AnalyzedModule(
|
||||||
|
target = target,
|
||||||
|
module = analyze(
|
||||||
|
moduleName = moduleName,
|
||||||
|
moduleRoot = sourceModuleRoot.root,
|
||||||
|
parentDisposable = parentDisposable
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyze(
|
||||||
|
moduleName: String,
|
||||||
|
moduleRoot: File,
|
||||||
|
parentDisposable: Disposable
|
||||||
|
): ModuleDescriptor {
|
||||||
|
val configuration: CompilerConfiguration = newConfiguration()
|
||||||
|
configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||||
|
|
||||||
|
val environment: KotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
|
||||||
|
parentDisposable = parentDisposable,
|
||||||
|
initialConfiguration = configuration,
|
||||||
|
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||||
|
)
|
||||||
|
|
||||||
|
val psiFactory = KtPsiFactory(environment.project)
|
||||||
|
|
||||||
|
val psiFiles: List<KtFile> = moduleRoot.walkTopDown()
|
||||||
|
.filter { it.isFile }
|
||||||
|
.map { psiFactory.createFile(it.name, doLoadFile(it)) }
|
||||||
|
.toList()
|
||||||
|
|
||||||
|
return CommonResolverForModuleFactory.analyzeFiles(
|
||||||
|
files = psiFiles,
|
||||||
|
moduleName = Name.special("<$moduleName>"),
|
||||||
|
dependOnBuiltIns = true,
|
||||||
|
languageVersionSettings = environment.configuration.languageVersionSettings,
|
||||||
|
targetPlatform = CommonPlatforms.defaultCommonPlatform
|
||||||
|
) { content ->
|
||||||
|
environment.createPackagePartProvider(content.moduleContentScope)
|
||||||
|
}.moduleDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnalyzedModules(
|
||||||
|
val originalPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>>,
|
||||||
|
val commonizedPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>>,
|
||||||
|
val commonizedCommonModule: AnalyzedModule<OutputTarget>
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
check(originalPlatformModules.isNotEmpty())
|
||||||
|
check(originalPlatformModules.keys == commonizedPlatformModules.keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toCommonizationParameters(): Parameters = originalPlatformModules.mapValues { it.value.module }.toCommonizationParameters()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(
|
||||||
|
sourceModuleRoots: SourceModuleRoots,
|
||||||
|
parentDisposable: Disposable
|
||||||
|
): AnalyzedModules {
|
||||||
|
val originalPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>> = createInputTargetModules(
|
||||||
|
sourceModuleRoots = sourceModuleRoots.originalPlatformRoots,
|
||||||
|
parentDisposable = parentDisposable
|
||||||
|
)
|
||||||
|
|
||||||
|
val commonizedCommonModule: AnalyzedModule<OutputTarget> = AnalyzedModule.create(
|
||||||
|
target = OutputTarget(originalPlatformModules.keys),
|
||||||
|
sourceModuleRoot = sourceModuleRoots.commonizedCommonRoot,
|
||||||
|
parentDisposable = parentDisposable
|
||||||
|
)
|
||||||
|
|
||||||
|
val commonizedPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>> = createInputTargetModules(
|
||||||
|
sourceModuleRoots = sourceModuleRoots.commonizedPlatformRoots,
|
||||||
|
parentDisposable = parentDisposable
|
||||||
|
)
|
||||||
|
|
||||||
|
return AnalyzedModules(
|
||||||
|
originalPlatformModules = originalPlatformModules,
|
||||||
|
commonizedPlatformModules = commonizedPlatformModules,
|
||||||
|
commonizedCommonModule = commonizedCommonModule
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createInputTargetModules(
|
||||||
|
sourceModuleRoots: Map<String, SourceModuleRoot>,
|
||||||
|
parentDisposable: Disposable
|
||||||
|
): Map<InputTarget, AnalyzedModule<InputTarget>> = sourceModuleRoots.map { (targetName, sourceModuleRoot) ->
|
||||||
|
AnalyzedModule.create(
|
||||||
|
target = InputTarget(targetName),
|
||||||
|
sourceModuleRoot = sourceModuleRoot,
|
||||||
|
parentDisposable = parentDisposable
|
||||||
|
)
|
||||||
|
}.associateBy { it.target }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Map<InputTarget, ModuleDescriptor>.toCommonizationParameters(): Parameters = Parameters().also {
|
||||||
|
forEach { (target, moduleDescriptor) ->
|
||||||
|
it.addTarget(
|
||||||
|
TargetProvider(
|
||||||
|
target = target,
|
||||||
|
builtInsClass = moduleDescriptor.builtIns::class.java,
|
||||||
|
builtInsProvider = BuiltInsProvider.wrap(moduleDescriptor.builtIns),
|
||||||
|
modulesProvider = ModulesProvider.wrap(moduleDescriptor)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user