mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
[Commonizer] Implement associative commonization
^KT-47301 Verification Pending
This commit is contained in:
committed by
Space
parent
5fdbcb3dd1
commit
42f60d981f
@@ -26,7 +26,7 @@ public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<CommonizerDependency>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputTargets: Set<SharedCommonizerTarget>,
|
||||
outputDirectory: File,
|
||||
logLevel: CommonizerLogLevel
|
||||
) {
|
||||
@@ -35,7 +35,7 @@ public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
add("native-klib-commonize")
|
||||
add("-distribution-path"); add(konanHome.absolutePath)
|
||||
add("-input-libraries"); add(inputLibraries.joinToString(";") { it.absolutePath })
|
||||
add("-output-commonizer-target"); add(outputCommonizerTarget.identityString)
|
||||
add("-output-targets"); add(outputTargets.joinToString(";") { it.identityString })
|
||||
add("-output-path"); add(outputDirectory.absolutePath)
|
||||
if (dependencyLibraries.isNotEmpty()) {
|
||||
add("-dependency-libraries"); add(dependencyLibraries.joinToString(";"))
|
||||
@@ -44,6 +44,23 @@ public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
}
|
||||
executor(arguments)
|
||||
}
|
||||
|
||||
override fun commonizeNativeDistribution(
|
||||
konanHome: File,
|
||||
outputDirectory: File,
|
||||
outputTargets: Set<SharedCommonizerTarget>,
|
||||
logLevel: CommonizerLogLevel
|
||||
) {
|
||||
val arguments = mutableListOf<String>().apply {
|
||||
add("native-dist-commonize")
|
||||
add("-distribution-path"); add(konanHome.absolutePath)
|
||||
add("-output-path"); add(outputDirectory.absolutePath)
|
||||
add("-output-targets"); add(outputTargets.joinToString(";") { it.identityString })
|
||||
add("-log-level"); add(logLevel.name.lowercase())
|
||||
}
|
||||
|
||||
executor(arguments)
|
||||
}
|
||||
}
|
||||
|
||||
private class CommonizerClassLoaderExecutor(private val commonizerClassLoader: ClassLoader) : CliCommonizer.Executor {
|
||||
|
||||
@@ -9,13 +9,22 @@ import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
public interface Commonizer : Serializable {
|
||||
|
||||
@Throws(Throwable::class)
|
||||
public fun commonizeLibraries(
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<CommonizerDependency>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputTargets: Set<SharedCommonizerTarget>,
|
||||
outputDirectory: File,
|
||||
logLevel: CommonizerLogLevel = CommonizerLogLevel.Quiet
|
||||
)
|
||||
|
||||
@Throws(Throwable::class)
|
||||
public fun commonizeNativeDistribution(
|
||||
konanHome: File,
|
||||
outputDirectory: File,
|
||||
outputTargets: Set<SharedCommonizerTarget>,
|
||||
logLevel: CommonizerLogLevel = CommonizerLogLevel.Quiet
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.util.transitiveClosure
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.Serializable
|
||||
|
||||
// N.B. TargetPlatform/SimplePlatform are non exhaustive enough to address both target platforms such as
|
||||
// JVM, JS and concrete Kotlin/Native targets, e.g. macos_x64, ios_x64, linux_x64.
|
||||
public sealed class CommonizerTarget : Serializable {
|
||||
final override fun toString(): String = prettyName
|
||||
final override fun toString(): String = identityString
|
||||
}
|
||||
|
||||
public data class LeafCommonizerTarget public constructor(val name: String) : CommonizerTarget() {
|
||||
@@ -25,16 +24,10 @@ public data class LeafCommonizerTarget public constructor(val name: String) : Co
|
||||
public val konanTarget: KonanTarget get() = konanTargetOrNull ?: error("Unknown KonanTarget: $name")
|
||||
}
|
||||
|
||||
public data class SharedCommonizerTarget(val targets: Set<CommonizerTarget>) : CommonizerTarget() {
|
||||
public constructor(vararg targets: CommonizerTarget) : this(targets.toSet())
|
||||
public data class SharedCommonizerTarget(val targets: Set<LeafCommonizerTarget>) : CommonizerTarget() {
|
||||
public constructor(vararg targets: LeafCommonizerTarget) : this(targets.toSet())
|
||||
public constructor(vararg targets: KonanTarget) : this(targets.toSet())
|
||||
public constructor(targets: Iterable<KonanTarget>) : this(targets.map(::LeafCommonizerTarget).toSet())
|
||||
|
||||
public companion object {
|
||||
public fun ifNotEmpty(targets: Set<CommonizerTarget>): SharedCommonizerTarget? {
|
||||
return if (targets.isNotEmpty()) SharedCommonizerTarget(targets) else null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommonizerTarget(konanTargets: Iterable<KonanTarget>): CommonizerTarget {
|
||||
@@ -56,8 +49,11 @@ public fun CommonizerTarget(konanTarget: KonanTarget, vararg konanTargets: Konan
|
||||
return SharedCommonizerTarget(targets.map(::LeafCommonizerTarget).toSet())
|
||||
}
|
||||
|
||||
public fun CommonizerTarget(commonizerTarget: CommonizerTarget, vararg commonizerTargets: CommonizerTarget): SharedCommonizerTarget {
|
||||
val targets = mutableListOf<CommonizerTarget>().apply {
|
||||
public fun CommonizerTarget(
|
||||
commonizerTarget: LeafCommonizerTarget,
|
||||
vararg commonizerTargets: LeafCommonizerTarget
|
||||
): SharedCommonizerTarget {
|
||||
val targets = mutableListOf<LeafCommonizerTarget>().apply {
|
||||
add(commonizerTarget)
|
||||
addAll(commonizerTargets)
|
||||
}
|
||||
@@ -78,22 +74,6 @@ private val SharedCommonizerTarget.identityString: String
|
||||
)
|
||||
}
|
||||
|
||||
public val CommonizerTarget.prettyName: String
|
||||
get() = when (this) {
|
||||
is LeafCommonizerTarget -> "[$name]"
|
||||
is SharedCommonizerTarget -> prettyName(null)
|
||||
}
|
||||
|
||||
public fun SharedCommonizerTarget.prettyName(highlightedChild: CommonizerTarget?): String {
|
||||
return targets
|
||||
.sortedWith(compareBy<CommonizerTarget> { it.level }.thenBy { it.identityString }).joinToString(", ", "[", "]") { child ->
|
||||
when (child) {
|
||||
is LeafCommonizerTarget -> child.name
|
||||
is SharedCommonizerTarget -> child.prettyName(highlightedChild)
|
||||
} + if (child == highlightedChild) "(*)" else ""
|
||||
}
|
||||
}
|
||||
|
||||
public val CommonizerTarget.konanTargets: Set<KonanTarget>
|
||||
get() {
|
||||
return when (this) {
|
||||
@@ -102,6 +82,9 @@ public val CommonizerTarget.konanTargets: Set<KonanTarget>
|
||||
}
|
||||
}
|
||||
|
||||
public val Iterable<CommonizerTarget>.konanTargets: Set<KonanTarget> get() = flatMapTo(mutableSetOf()) { it.konanTargets }
|
||||
|
||||
// REMOVE
|
||||
public val CommonizerTarget.level: Int
|
||||
get() {
|
||||
return when (this) {
|
||||
@@ -110,30 +93,25 @@ public val CommonizerTarget.level: Int
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommonizerTarget.withAllAncestors(): Set<CommonizerTarget> {
|
||||
return setOf(this) + transitiveClosure(this) {
|
||||
when (this) {
|
||||
is SharedCommonizerTarget -> targets
|
||||
is LeafCommonizerTarget -> emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommonizerTarget.allLeaves(): Set<LeafCommonizerTarget> {
|
||||
return withAllAncestors().filterIsInstance<LeafCommonizerTarget>().toSet()
|
||||
}
|
||||
|
||||
public infix fun CommonizerTarget.isAncestorOf(other: CommonizerTarget): Boolean {
|
||||
if (this is SharedCommonizerTarget) {
|
||||
return targets.any { it == other } || targets.any { it.isAncestorOf(other) }
|
||||
return when (this) {
|
||||
is LeafCommonizerTarget -> setOf(this)
|
||||
is SharedCommonizerTarget -> this.targets
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public infix fun CommonizerTarget.isEqualOrAncestorOf(other: CommonizerTarget): Boolean {
|
||||
return this == other || this.isAncestorOf(other)
|
||||
public fun Iterable<CommonizerTarget>.allLeaves(): Set<LeafCommonizerTarget> {
|
||||
return flatMapTo(mutableSetOf()) { target -> target.allLeaves() }
|
||||
}
|
||||
|
||||
public infix fun CommonizerTarget.isDescendentOf(other: CommonizerTarget): Boolean {
|
||||
return other.isAncestorOf(this)
|
||||
public fun CommonizerTarget.withAllLeaves(): Set<CommonizerTarget> {
|
||||
return when (this) {
|
||||
is LeafCommonizerTarget -> setOf(this)
|
||||
is SharedCommonizerTarget -> setOf(this) + targets
|
||||
}
|
||||
}
|
||||
|
||||
public fun Iterable<CommonizerTarget>.withAllLeaves(): Set<CommonizerTarget> {
|
||||
return flatMapTo(mutableSetOf()) { it.withAllLeaves() }
|
||||
}
|
||||
@@ -5,30 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
||||
import java.io.File
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
|
||||
public fun interface CommonizerOutputLayout {
|
||||
public fun getTargetDirectory(root: File, target: CommonizerTarget): File
|
||||
}
|
||||
|
||||
public object NativeDistributionCommonizerOutputLayout : CommonizerOutputLayout {
|
||||
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||
return when (target) {
|
||||
is LeafCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.name)
|
||||
is SharedCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object HierarchicalCommonizerOutputLayout : CommonizerOutputLayout {
|
||||
public object CommonizerOutputFileLayout {
|
||||
internal const val maxFileNameLength = 150
|
||||
|
||||
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||
public fun getCommonizedDirectory(root: File, target: CommonizerTarget): File {
|
||||
return root.resolve(target.fileName)
|
||||
}
|
||||
|
||||
@@ -42,11 +26,18 @@ public object HierarchicalCommonizerOutputLayout : CommonizerOutputLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public val Set<CommonizerTarget>.fileName: String
|
||||
get() = this.joinToString(";") { it.identityString }.base64Hash
|
||||
|
||||
|
||||
private val CommonizerTarget.identityStringHash: String
|
||||
get() = identityString.base64Hash
|
||||
|
||||
private val String.base64Hash: String
|
||||
get() {
|
||||
val sha = MessageDigest.getInstance("SHA-1")
|
||||
val base64 = Base64.getUrlEncoder()
|
||||
return base64.encode(sha.digest(identityString.encodeToByteArray())).decodeToString()
|
||||
return base64.encode(sha.digest(this.encodeToByteArray())).decodeToString()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,8 +192,9 @@ private sealed class IdentityStringSyntaxNode {
|
||||
private fun buildCommonizerTarget(node: IdentityStringSyntaxNode): CommonizerTarget {
|
||||
return when (node) {
|
||||
is LeafTargetSyntaxNode -> LeafCommonizerTarget(node.token.value)
|
||||
// Previous nested ((a, b), c) notation is still valid and will be flattened to (a, b, c)
|
||||
is SharedTargetSyntaxNode -> SharedCommonizerTarget(
|
||||
node.children.map { child -> buildCommonizerTarget(child) }.toSet()
|
||||
node.children.flatMap { child -> buildCommonizerTarget(child).allLeaves() }.toSet()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class CliCommonizerTest {
|
||||
konanHome = konanHome,
|
||||
inputLibraries = emptySet(),
|
||||
dependencyLibraries = emptySet(),
|
||||
outputCommonizerTarget = CommonizerTarget(KonanTarget.LINUX_X64, KonanTarget.MACOS_X64),
|
||||
outputTargets = setOf(CommonizerTarget(KonanTarget.LINUX_X64, KonanTarget.MACOS_X64)),
|
||||
outputDirectory = temporaryOutputDirectory.root
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,24 +34,13 @@ class CommonizeLibcurlTest {
|
||||
KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_ARM64.name).listFiles().orEmpty()
|
||||
.map { TargetedCommonizerDependency(LeafCommonizerTarget(LINUX_ARM64), it) }
|
||||
.toSet(),
|
||||
outputCommonizerTarget = CommonizerTarget(LINUX_ARM64, LINUX_X64),
|
||||
outputDirectory = temporaryOutputDirectory.root
|
||||
outputTargets = setOf(CommonizerTarget(LINUX_ARM64, LINUX_X64)),
|
||||
outputDirectory = temporaryOutputDirectory.root,
|
||||
logLevel = CommonizerLogLevel.Info
|
||||
)
|
||||
|
||||
val x64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_X64).identityString)
|
||||
val arm64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_ARM64).identityString)
|
||||
val commonOutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_X64, LINUX_ARM64).identityString)
|
||||
|
||||
assertTrue(
|
||||
x64OutputDirectory.exists(),
|
||||
"Missing output directory for x64 target"
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
arm64OutputDirectory.exists(),
|
||||
"Missing output directory for arm64 target"
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
commonOutputDirectory.exists(),
|
||||
"Missing output directory for commonized x64&arm64 target"
|
||||
@@ -64,18 +53,8 @@ class CommonizeLibcurlTest {
|
||||
)
|
||||
}
|
||||
|
||||
assertContainsKnmFiles(x64OutputDirectory)
|
||||
assertContainsKnmFiles(arm64OutputDirectory)
|
||||
assertContainsKnmFiles(commonOutputDirectory)
|
||||
|
||||
|
||||
assertContainsManifestWithContent(x64OutputDirectory, "native_targets=linux_x64")
|
||||
assertContainsManifestWithContent(arm64OutputDirectory, "native_targets=linux_arm64")
|
||||
assertContainsManifestWithContent(commonOutputDirectory, "native_targets=linux_arm64 linux_x64")
|
||||
|
||||
assertContainsManifestWithContent(x64OutputDirectory, "commonizer_target=linux_x64")
|
||||
assertContainsManifestWithContent(arm64OutputDirectory, "commonizer_target=linux_arm64")
|
||||
|
||||
assertContainsManifestWithContent(commonOutputDirectory, "commonizer_native_targets=linux_arm64 linux_x64")
|
||||
assertContainsManifestWithContent(
|
||||
commonOutputDirectory, "commonizer_target=${CommonizerTarget(LINUX_X64, LINUX_ARM64).identityString}"
|
||||
@@ -98,22 +77,14 @@ class CommonizeLibcurlTest {
|
||||
KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_ARM64.name).listFiles().orEmpty()
|
||||
.map { TargetedCommonizerDependency(LeafCommonizerTarget(LINUX_ARM64), it) }
|
||||
.toSet(),
|
||||
outputCommonizerTarget = CommonizerTarget(LINUX_ARM64, LINUX_X64, MACOS_X64),
|
||||
outputTargets = setOf(CommonizerTarget(LINUX_ARM64, LINUX_X64, MACOS_X64)),
|
||||
outputDirectory = temporaryOutputDirectory.root
|
||||
)
|
||||
|
||||
val x64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_X64).identityString)
|
||||
val arm64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_ARM64).identityString)
|
||||
val commonOutputDirectory = temporaryOutputDirectory.root
|
||||
.resolve(CommonizerTarget(LINUX_X64, LINUX_ARM64, MACOS_X64).identityString)
|
||||
|
||||
assertContainsManifestWithContent(x64OutputDirectory, "native_targets=linux_x64")
|
||||
assertContainsManifestWithContent(arm64OutputDirectory, "native_targets=linux_arm64")
|
||||
assertContainsManifestWithContent(commonOutputDirectory, "native_targets=linux_arm64 linux_x64")
|
||||
|
||||
assertContainsManifestWithContent(x64OutputDirectory, "commonizer_target=linux_x64")
|
||||
assertContainsManifestWithContent(arm64OutputDirectory, "commonizer_target=linux_arm64")
|
||||
|
||||
assertContainsManifestWithContent(commonOutputDirectory, "commonizer_native_targets=linux_arm64 linux_x64 macos_x64")
|
||||
assertContainsManifestWithContent(
|
||||
commonOutputDirectory, "commonizer_target=${CommonizerTarget(LINUX_X64, LINUX_ARM64, MACOS_X64).identityString}"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.getCommonizedDirectory
|
||||
import org.jetbrains.kotlin.commonizer.utils.konanHome
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
class CommonizeNativeDistributionTest {
|
||||
|
||||
@get:Rule
|
||||
val temporaryOutputDirectory = TemporaryFolder()
|
||||
|
||||
@Test
|
||||
fun commonizeLinuxPlatforms() {
|
||||
val linuxTarget1 = CommonizerTarget(LINUX_X64, LINUX_ARM64)
|
||||
val linuxTarget2 = CommonizerTarget(LINUX_X64, LINUX_ARM64, LINUX_ARM32_HFP)
|
||||
|
||||
CliCommonizer(this::class.java.classLoader).commonizeNativeDistribution(
|
||||
konanHome = konanHome,
|
||||
outputTargets = setOf(linuxTarget1, linuxTarget2),
|
||||
outputDirectory = temporaryOutputDirectory.root,
|
||||
logLevel = CommonizerLogLevel.Info
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
getCommonizedDirectory(temporaryOutputDirectory.root, linuxTarget1).isDirectory,
|
||||
"Expected directory for $linuxTarget1"
|
||||
)
|
||||
|
||||
assertTrue(
|
||||
getCommonizedDirectory(temporaryOutputDirectory.root, linuxTarget2).isDirectory,
|
||||
"Expected directory for $linuxTarget2"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ class CommonizerDependencyTest {
|
||||
@Test
|
||||
fun `sample identityString`() {
|
||||
assertEquals(
|
||||
"((a, b), c)::${File("/").canonicalPath}hello.txt",
|
||||
TargetedCommonizerDependency(parseCommonizerTarget("((a,b), c)"), File("/hello.txt")).identityString
|
||||
"(a, b, c)::${File("/").canonicalPath}hello.txt",
|
||||
TargetedCommonizerDependency(parseCommonizerTarget("(a, b, c)"), File("/hello.txt")).identityString
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.HierarchicalCommonizerOutputLayout.fileName
|
||||
import org.jetbrains.kotlin.commonizer.HierarchicalCommonizerOutputLayout.maxFileNameLength
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.fileName
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.maxFileNameLength
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import kotlin.test.Test
|
||||
|
||||
@@ -33,60 +33,14 @@ class CommonizerTargetIdentityStringTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hierarchical commonizer targets`() {
|
||||
val hierarchy = SharedCommonizerTarget(
|
||||
CommonizerTarget(LINUX_X64, MACOS_X64),
|
||||
CommonizerTarget(IOS_ARM64, IOS_X64)
|
||||
)
|
||||
assertEquals(setOf(LINUX_X64, MACOS_X64, IOS_ARM64, IOS_X64), hierarchy.konanTargets)
|
||||
assertEquals(hierarchy, parseCommonizerTarget(hierarchy.identityString))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multilevel hierarchical commonizer targets`() {
|
||||
val hierarchy = SharedCommonizerTarget(
|
||||
SharedCommonizerTarget(
|
||||
SharedCommonizerTarget(
|
||||
SharedCommonizerTarget(
|
||||
CommonizerTarget(LINUX_X64, MACOS_X64),
|
||||
CommonizerTarget(IOS_X64, IOS_ARM64)
|
||||
),
|
||||
CommonizerTarget(LINUX_ARM32_HFP)
|
||||
),
|
||||
CommonizerTarget(LINUX_MIPSEL32)
|
||||
),
|
||||
CommonizerTarget(WATCHOS_X86, WATCHOS_ARM64)
|
||||
)
|
||||
|
||||
assertEquals(hierarchy, parseCommonizerTarget(hierarchy.identityString))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parsing CommonizerTarget`() {
|
||||
fun `parsing CommonizerTarget with 1 5 20 notation`() {
|
||||
val target = parseCommonizerTarget("(x, (x, y, (a, b), (b, c)))")
|
||||
assertEquals(
|
||||
SharedCommonizerTarget(
|
||||
LeafCommonizerTarget("x"),
|
||||
SharedCommonizerTarget(
|
||||
LeafCommonizerTarget("x"),
|
||||
LeafCommonizerTarget("y"),
|
||||
SharedCommonizerTarget(
|
||||
LeafCommonizerTarget("a"),
|
||||
LeafCommonizerTarget("b"),
|
||||
),
|
||||
SharedCommonizerTarget(
|
||||
LeafCommonizerTarget("b"),
|
||||
LeafCommonizerTarget("c")
|
||||
)
|
||||
)
|
||||
),
|
||||
target
|
||||
)
|
||||
assertEquals(SharedCommonizerTarget(setOf("x", "y", "a", "b", "c").map(::LeafCommonizerTarget).toSet()), target)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty shared target`() {
|
||||
assertEquals(SharedCommonizerTarget(emptySet<CommonizerTarget>()), parseCommonizerTarget("()"))
|
||||
assertEquals(SharedCommonizerTarget(emptySet<LeafCommonizerTarget>()), parseCommonizerTarget("()"))
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.commonizer
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class CommonizerTargetPrettyNameTest {
|
||||
|
||||
@Test
|
||||
fun leafTargetNames() {
|
||||
listOf(
|
||||
Triple("foo", "[foo]", FOO),
|
||||
Triple("bar", "[bar]", BAR),
|
||||
Triple("baz_123", "[baz_123]", BAZ),
|
||||
).forEach { (name, prettyName, target: LeafCommonizerTarget) ->
|
||||
assertEquals(name, target.name)
|
||||
assertEquals(prettyName, target.prettyName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sharedTargetNames() {
|
||||
listOf(
|
||||
"[foo]" to SharedTarget(FOO),
|
||||
"[bar, foo]" to SharedTarget(FOO, BAR),
|
||||
"[bar, baz_123, foo]" to SharedTarget(FOO, BAR, BAZ),
|
||||
"[bar, baz_123, foo, [bar, foo]]" to SharedTarget(FOO, BAR, BAZ, SharedTarget(FOO, BAR))
|
||||
).forEach { (prettyName, target: SharedCommonizerTarget) ->
|
||||
assertEquals(prettyName, target.prettyName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun prettyCommonizedName() {
|
||||
val sharedTarget = SharedTarget(FOO, BAR, BAZ)
|
||||
listOf(
|
||||
"[bar, baz_123, foo(*)]" to FOO,
|
||||
"[bar(*), baz_123, foo]" to BAR,
|
||||
"[bar, baz_123(*), foo]" to BAZ,
|
||||
"[bar, baz_123, foo]" to sharedTarget,
|
||||
).forEach { (prettyCommonizerName, target: CommonizerTarget) ->
|
||||
assertEquals(prettyCommonizerName, sharedTarget.prettyName(target))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun prettyNestedName() {
|
||||
val target = parseCommonizerTarget("(a, b, (c, (d, e)))") as SharedCommonizerTarget
|
||||
|
||||
assertEquals(
|
||||
"[a, b, [c, [d, e]]]", target.prettyName
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"[a, b, [c, [d, e(*)]]]", target.prettyName(LeafCommonizerTarget("e"))
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"[a, b, [c, [d, e](*)]]", target.prettyName(parseCommonizerTarget("(d, e)"))
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"[a, b, [c, [d, e]](*)]", target.prettyName(parseCommonizerTarget("(c, (d, e))"))
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"[a, b(*), [c, [d, e]]]", target.prettyName(LeafCommonizerTarget("b"))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sharedTargetNoInnerTargets() {
|
||||
assertEquals(
|
||||
"[]", SharedCommonizerTarget(emptySet<CommonizerTarget>()).prettyName
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val FOO = LeafCommonizerTarget("foo")
|
||||
val BAR = LeafCommonizerTarget("bar")
|
||||
val BAZ = LeafCommonizerTarget("baz_123")
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
fun SharedTarget(vararg targets: CommonizerTarget) = SharedCommonizerTarget(linkedSetOf(*targets))
|
||||
}
|
||||
}
|
||||
@@ -7,53 +7,9 @@ package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CommonizerTargetUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `isAncestorOf isDescendentOf`() {
|
||||
val child = LeafCommonizerTarget("a")
|
||||
val parent = SharedCommonizerTarget(LeafCommonizerTarget("a"))
|
||||
|
||||
assertTrue(child isDescendentOf parent, "Expected child isDescendent of parent")
|
||||
assertTrue(parent isAncestorOf child, "Expected parent isAncestor of child")
|
||||
assertFalse(child isDescendentOf child, "Expected same target not being descendent of itself")
|
||||
assertFalse(parent isDescendentOf parent, "Expected same target not being descendent of itself")
|
||||
assertFalse(LeafCommonizerTarget("b") isDescendentOf parent, "Expected orphan target not being descendent of parent")
|
||||
|
||||
val hierarchicalParent = SharedCommonizerTarget(parent, parseCommonizerTarget("((c, d), e)"))
|
||||
assertTrue(child isDescendentOf hierarchicalParent, "Expected child being descendent of hierarchical parent")
|
||||
assertTrue(hierarchicalParent isAncestorOf child, "Expected hierarchicalParent being ancestor of child")
|
||||
assertTrue(parseCommonizerTarget("(c, d)") isDescendentOf hierarchicalParent)
|
||||
assertTrue(LeafCommonizerTarget("e") isDescendentOf hierarchicalParent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withAllAncestors() {
|
||||
val target = parseCommonizerTarget("((a, b), (c, d), (e, (f, g)))")
|
||||
|
||||
assertEquals(
|
||||
setOf(
|
||||
target,
|
||||
parseCommonizerTarget("(a, b)"),
|
||||
parseCommonizerTarget("(c, d)"),
|
||||
parseCommonizerTarget("(e, (f, g))"),
|
||||
parseCommonizerTarget("(f, g)"),
|
||||
LeafCommonizerTarget("a"),
|
||||
LeafCommonizerTarget("b"),
|
||||
LeafCommonizerTarget("c"),
|
||||
LeafCommonizerTarget("d"),
|
||||
LeafCommonizerTarget("e"),
|
||||
LeafCommonizerTarget("f"),
|
||||
LeafCommonizerTarget("g")
|
||||
),
|
||||
target.withAllAncestors(),
|
||||
"Expected all targets present"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun allLeaves() {
|
||||
val target = parseCommonizerTarget("((a, b), (c, d), (e, (f, g)))")
|
||||
@@ -76,5 +32,18 @@ class CommonizerTargetUtilsTest {
|
||||
"Expected LeafCommonizerTarget returns itself in 'allLeaves'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `withAllLeaves LeafCommonizerTarget`() {
|
||||
assertEquals(setOf(LeafCommonizerTarget("a")), LeafCommonizerTarget("a").withAllLeaves())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `withAllLeaves SharedCommonizerTarget`() {
|
||||
assertEquals(
|
||||
setOf(parseCommonizerTarget("(a, b)"), LeafCommonizerTarget("a"), LeafCommonizerTarget("b")),
|
||||
parseCommonizerTarget("(a, b)").withAllLeaves()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user