KT-MR-5666 SourceSetMappedFragmentLocator

* fix choosing longest module name (did mistakenly choose shortest)
* fix missing return for single-part name
* add unit tests
This commit is contained in:
Sergey Igushkin
2022-02-08 18:57:01 +04:00
committed by Space
parent 5e8c74d3ad
commit a574a1f6d2
4 changed files with 114 additions and 9 deletions
@@ -0,0 +1,106 @@
/*
* Copyright 2010-2022 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.
*/
/* Associate compilations are not yet supported by the IDE. KT-34102 */
@file:Suppress("invisible_reference", "invisible_member", "FunctionName", "DuplicatedCode")
package org.jetbrains.kotlin.gradle.sources.kpm
import org.jetbrains.kotlin.gradle.MultiplatformExtensionTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import org.jetbrains.kotlin.gradle.plugin.sources.kpm.MultiplatformSourceSetMappedFragmentLocator
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.kpmModules
import org.jetbrains.kotlin.gradle.plugin.sources.kpm.SourceSetMappedFragmentLocator
internal open class MultiplatformSourceSetMappedFragmentLocatorTest : MultiplatformExtensionTest() {
protected val locator = MultiplatformSourceSetMappedFragmentLocator()
@BeforeTest
override fun setup() {
project.extensions.extraProperties.set(PropertiesProvider.PropertyNames.KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING, "true")
super.setup()
}
protected fun doTest(sourceSetName: String, checkResult: SourceSetMappedFragmentLocator.FragmentLocation.() -> Unit) {
val result = checkNotNull(locator.locateFragmentForSourceSet(project, sourceSetName))
checkResult(result)
}
protected fun doTest(sourceSetName: String, fragmentName: String, moduleName: String) {
doTest(sourceSetName) {
assertEquals(fragmentName, this.fragmentName)
assertEquals(moduleName, this.moduleName)
}
}
@Test
fun `name with one part is returned as fragment name with main module`() {
doTest("foo", "foo", KotlinGradleModule.MAIN_MODULE_NAME)
}
@Test
fun `main is truncated from name`() {
doTest("fooBarMain", "fooBar", KotlinGradleModule.MAIN_MODULE_NAME)
}
@Test
fun `module chosen for test fragment`() {
doTest("abcDefGhiTest", "abcDefGhi", KotlinGradleModule.TEST_MODULE_NAME)
}
@Test
fun `digits accepted`() {
val nameWithDigits = "testDigits123Accepted123"
project.kpmModules.create(nameWithDigits)
doTest("foo${nameWithDigits.capitalize()}", "foo", nameWithDigits)
doTest("${nameWithDigits}Main", nameWithDigits, KotlinGradleModule.MAIN_MODULE_NAME)
}
@Test
fun `capitalized name handling`() {
doTest("IAmTheMain", "IAmThe", KotlinGradleModule.MAIN_MODULE_NAME)
}
@Test
fun `live module logic update`() {
val nameForTest = "someNewTest"
doTest(nameForTest, "someNew", "test")
project.kpmModules.create("newTest")
doTest(nameForTest, "some", "newTest")
// also check for the same logic in fragments that go to main if no suffix matched:
val nameForMain = "fooBarBaz"
doTest(nameForMain, nameForMain, KotlinGradleModule.MAIN_MODULE_NAME)
val moduleSuffixName = "barBaz"
project.kpmModules.create(moduleSuffixName)
doTest(nameForMain, "foo", moduleSuffixName)
}
}
internal class MultiplatformSourceSetMappedFragmentLocatorTestWithAndroid : MultiplatformSourceSetMappedFragmentLocatorTest() {
override fun setup() {
super.setup()
project.plugins.apply("android-library")
kotlin.android()
}
@Test
fun `android source set names`() {
doTest("androidMain", "android", KotlinGradleModule.MAIN_MODULE_NAME)
doTest("androidTest", "android", KotlinGradleModule.TEST_MODULE_NAME)
doTest("androidAndroidTest", "androidAndroid", KotlinGradleModule.TEST_MODULE_NAME)
doTest("androidDebug", "androidDebug", KotlinGradleModule.MAIN_MODULE_NAME)
doTest("androidDebugTest", "androidDebug", KotlinGradleModule.TEST_MODULE_NAME)
doTest("androidDebugAndroidTest", "androidDebugAndroid", KotlinGradleModule.TEST_MODULE_NAME)
}
}
@@ -224,7 +224,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
get() = booleanProperty("kotlin.wasm.stability.nowarn") ?: false
val experimentalKpmModelMapping: Boolean
get() = booleanProperty("kotlin.kpm.experimentalModelMapping") ?: false
get() = booleanProperty(PropertyNames.KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING) ?: false
val ignoreDisabledNativeTargets: Boolean?
get() = booleanProperty(DisabledNativeTargetsReporter.DISABLE_WARNING_PROPERTY_NAME)
@@ -488,6 +488,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT = "kotlin.mpp.hierarchicalStructureSupport"
const val KOTLIN_NATIVE_DEPENDENCY_PROPAGATION = "kotlin.native.enableDependencyPropagation"
const val KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION = "kotlin.mpp.enableOptimisticNumberCommonization"
const val KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING = "kotlin.kpm.experimentalModelMapping"
}
companion object {
@@ -17,9 +17,8 @@ class FragmentMappedKotlinSourceSetFactory constructor(private val project: Proj
override fun create(name: String): FragmentMappedKotlinSourceSet {
val locator = SourceSetMappedFragmentLocator.get(project)
val location = locator.locateFragmentForSourceSet(project, name) ?: error("Couldn't map the source set name $name to KPM fragment")
val (moduleName, fragmentName) = location
val modules = project.kpmModules
val fragment = modules.maybeCreate(moduleName).fragments.maybeCreate(fragmentName)
val fragment = project.kpmModules.maybeCreate(location.moduleName).fragments.maybeCreate(location.fragmentName)
/** TODO setup JS-specific attributes similar to [org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory]*/
return FragmentMappedKotlinSourceSet(name, project, fragment)
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.sources.kpm
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.dsl.topLevelExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTargetPreset
@@ -33,11 +32,11 @@ interface SourceSetMappedFragmentLocator {
}
}
private class MultiplatformSourceSetMappedFragmentLocator : SourceSetMappedFragmentLocator {
override fun locateFragmentForSourceSet(project: Project, sourceSetName: String): SourceSetMappedFragmentLocator.FragmentLocation? {
internal class MultiplatformSourceSetMappedFragmentLocator : SourceSetMappedFragmentLocator {
override fun locateFragmentForSourceSet(project: Project, sourceSetName: String): SourceSetMappedFragmentLocator.FragmentLocation {
val camelCaseParts = sourceSetName.camelCaseParts()
if (camelCaseParts.size < 2) {
SourceSetMappedFragmentLocator.FragmentLocation(KotlinGradleModule.MAIN_MODULE_NAME, sourceSetName)
return SourceSetMappedFragmentLocator.FragmentLocation(KotlinGradleModule.MAIN_MODULE_NAME, sourceSetName)
}
val androidTarget = when (val ext = project.topLevelExtension) {
@@ -55,7 +54,7 @@ private class MultiplatformSourceSetMappedFragmentLocator : SourceSetMappedFragm
if (androidTarget != null && sourceSetName.startsWith(androidTarget.name))
androidSourceSetModuleName(androidTarget.name, sourceSetName)
else null
} ?: candidateModuleNames.firstOrNull { project.kpmModules.findByName(it) != null }
} ?: candidateModuleNames.lastOrNull { project.kpmModules.findByName(it) != null }
?: KotlinGradleModule.MAIN_MODULE_NAME
val fragmentName =