migrated XCFrameworkIT and AppleSiliconIT to junit5 and gradle TestKit

This commit is contained in:
Dmitrii Krasnov
2023-04-19 15:28:01 +02:00
committed by Space Team
parent 2cac7319fe
commit 36fc398358
6 changed files with 170 additions and 156 deletions
@@ -1,34 +1,34 @@
/* /*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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. * 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.gradle.native package org.jetbrains.kotlin.gradle.native
import org.jetbrains.kotlin.gradle.BaseGradleIT import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.GradleVersionRequired import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.junit.Assume.assumeTrue import org.junit.jupiter.api.DisplayName
import org.junit.Test import org.junit.jupiter.api.condition.EnabledOnOs
import kotlin.test.BeforeTest import org.junit.jupiter.api.condition.OS
import kotlin.test.fail import kotlin.test.fail
class AppleSiliconIT : BaseGradleIT() { @EnabledOnOs(OS.MAC, disabledReason = "Test requires MacOS host")
override val defaultGradleVersion: GradleVersionRequired = GradleVersionRequired.FOR_MPP_SUPPORT @DisplayName("Tests for Apple Silicon builds")
@NativeGradlePluginTests
class AppleSiliconIT : KGPBaseTest() {
// TODO(Dmitrii Krasnov): remove it, when KT-58104 will be fixed
override val defaultBuildOptions = super.defaultBuildOptions.copy(statisticsForceValidation = false)
private val host = HostManager.host private val host = HostManager.host
@BeforeTest @DisplayName("Tests compilation")
fun assumeMacosHost() { @GradleTest
assumeTrue("Test requires MacOS host", HostManager.hostIsMac) fun shouldCompiledSuccessfully(gradleVersion: GradleVersion) {
} nativeProject("appleSilicon", gradleVersion) {
@Test
fun `test compilation`() {
with(Project("appleSilicon")) {
build("assemble") { build("assemble") {
assertSuccessful()
assertTasksExecuted( assertTasksExecuted(
":compileKotlinIosArm64", ":compileKotlinIosArm64",
":compileKotlinIosSimulatorArm64", ":compileKotlinIosSimulatorArm64",
@@ -53,13 +53,13 @@ class AppleSiliconIT : BaseGradleIT() {
} }
} }
@Test @DisplayName("Tests execution")
fun `test execution`() { @GradleTest
with(Project("appleSilicon")) { fun shouldExecuteTestsSuccessfully(gradleVersion: GradleVersion) {
nativeProject("appleSilicon", gradleVersion) {
build("check") { build("check") {
assertSuccessful()
assertTasksExecuted(":jvmTest") assertTasksExecuted(":jvmTest")
assertContains("Executed Code from: commonMain/jvmMain") assertOutputContains("Executed Code from: commonMain/jvmMain")
val armTestOutputs = listOf( val armTestOutputs = listOf(
"commonMain/iosMain/iosSimulatorArm64Main", "commonMain/iosMain/iosSimulatorArm64Main",
@@ -77,13 +77,22 @@ class AppleSiliconIT : BaseGradleIT() {
when (host) { when (host) {
KonanTarget.MACOS_ARM64 -> { KonanTarget.MACOS_ARM64 -> {
assertContains(*armTestOutputs.toTypedArray()) for (s in armTestOutputs) {
assertNotContains(*x64TestOutputs.toTypedArray()) assertOutputContains(s)
}
for (s in x64TestOutputs) {
assertOutputDoesNotContain(s)
}
} }
KonanTarget.MACOS_X64 -> { KonanTarget.MACOS_X64 -> {
assertContains(*x64TestOutputs.toTypedArray()) for (s in x64TestOutputs) {
assertNotContains(*armTestOutputs.toTypedArray()) assertOutputContains(s)
}
for (s in armTestOutputs) {
assertOutputDoesNotContain(s)
}
} }
else -> fail("Unexpected host $host") else -> fail("Unexpected host $host")
@@ -106,12 +115,12 @@ class AppleSiliconIT : BaseGradleIT() {
when (host) { when (host) {
KonanTarget.MACOS_ARM64 -> { KonanTarget.MACOS_ARM64 -> {
assertTasksExecuted(armTests) assertTasksExecuted(armTests)
assertTasksNotExecuted(x64Tests) assertTasksSkipped(*x64Tests.toTypedArray())
} }
KonanTarget.MACOS_X64 -> { KonanTarget.MACOS_X64 -> {
assertTasksExecuted(x64Tests) assertTasksExecuted(x64Tests)
assertTasksNotExecuted(armTests) assertTasksSkipped(*armTests.toTypedArray())
} }
else -> fail("Unexpected host $host") else -> fail("Unexpected host $host")
@@ -22,16 +22,18 @@ class NativeLibraryDslIT : KGPBaseTest() {
fun shouldSharedAndLibRegisteredTasks(gradleVersion: GradleVersion) { fun shouldSharedAndLibRegisteredTasks(gradleVersion: GradleVersion) {
nativeProject("new-kn-library-dsl", gradleVersion) { nativeProject("new-kn-library-dsl", gradleVersion) {
buildAndAssertAllTasks( buildAndAssertAllTasks(
"shared:assembleMyfatframeFatFramework", listOf(
"shared:assembleMyframeFrameworkIosArm64", "shared:assembleMyfatframeFatFramework",
"shared:assembleMylibSharedLibraryLinuxX64", "shared:assembleMyframeFrameworkIosArm64",
"shared:assembleMyslibSharedLibraryLinuxX64", "shared:assembleMylibSharedLibraryLinuxX64",
"shared:assembleSharedXCFramework", "shared:assembleMyslibSharedLibraryLinuxX64",
"lib:assembleGroofatframeFatFramework", "shared:assembleSharedXCFramework",
"lib:assembleGrooframeFrameworkIosArm64", "lib:assembleGroofatframeFatFramework",
"lib:assembleGroolibSharedLibraryIosX64", "lib:assembleGrooframeFrameworkIosArm64",
"lib:assembleLibXCFramework", "lib:assembleGroolibSharedLibraryIosX64",
notRegisteredTasks = listOf("shared:assembleMyslibReleaseSharedLibraryLinuxX64") "lib:assembleLibXCFramework"
),
listOf("shared:assembleMyslibReleaseSharedLibraryLinuxX64")
) )
} }
} }
@@ -22,15 +22,17 @@ class NativeLibraryDslWithCocoapodsIT : KGPBaseTest() {
fun shouldCheckGradleRegisteredTasks(gradleVersion: GradleVersion) { fun shouldCheckGradleRegisteredTasks(gradleVersion: GradleVersion) {
buildNewKnLibraryDslCocoapodsProjectWithTasks(gradleVersion) { buildNewKnLibraryDslCocoapodsProjectWithTasks(gradleVersion) {
buildAndAssertAllTasks( buildAndAssertAllTasks(
"shared:generateMylibStaticLibraryLinuxX64Podspec", listOf(
"shared:generateMyslibSharedLibraryLinuxX64Podspec", "shared:generateMylibStaticLibraryLinuxX64Podspec",
"shared:generateMyframeFrameworkIosArm64Podspec", "shared:generateMyslibSharedLibraryLinuxX64Podspec",
"shared:generateMyfatframeFatFrameworkPodspec", "shared:generateMyframeFrameworkIosArm64Podspec",
"shared:generateSharedXCFrameworkPodspec", "shared:generateMyfatframeFatFrameworkPodspec",
"lib:generateGrooframeFrameworkIosArm64Podspec", "shared:generateSharedXCFrameworkPodspec",
"lib:generateGrooxcframeXCFrameworkPodspec", "lib:generateGrooframeFrameworkIosArm64Podspec",
"shared:generateMyframewihtoutpodspecFrameworkIosArm64Podspec", "lib:generateGrooxcframeXCFrameworkPodspec",
"lib:generateGrooxcframewithoutpodspecXCFrameworkPodspec" "shared:generateMyframewihtoutpodspecFrameworkIosArm64Podspec",
"lib:generateGrooxcframewithoutpodspecXCFrameworkPodspec"
)
) )
} }
} }
@@ -1,42 +1,31 @@
/* /*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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. * 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.gradle.native package org.jetbrains.kotlin.gradle.native
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.* import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.testbase.TestVersions import org.jetbrains.kotlin.gradle.util.replaceFirst
import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl import org.jetbrains.kotlin.gradle.util.replaceText
import org.jetbrains.kotlin.gradle.util.AGPVersion import org.junit.jupiter.api.DisplayName
import org.jetbrains.kotlin.konan.target.HostManager import org.junit.jupiter.api.condition.EnabledOnOs
import org.jetbrains.kotlin.test.util.KtTestUtil import org.junit.jupiter.api.condition.OS
import org.junit.Assume
import org.junit.BeforeClass
import kotlin.test.Test
class XCFrameworkIT : BaseGradleIT() { @EnabledOnOs(OS.MAC)
companion object { @DisplayName("Tests for K/N with apple XCFramework")
@BeforeClass @NativeGradlePluginTests
@JvmStatic class XCFrameworkIT : KGPBaseTest() {
fun assumeItsMac() {
Assume.assumeTrue(HostManager.hostIsMac)
}
}
override val defaultGradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT // TODO(Dmitrii Krasnov): remove it, when KT-58104 will be fixed
override fun defaultBuildOptions() = super.defaultBuildOptions().copy( override val defaultBuildOptions = super.defaultBuildOptions.copy(statisticsForceValidation = false)
androidHome = KtTestUtil.findAndroidSdk(),
androidGradlePluginVersion = AGPVersion.v7_4_0,
javaHome = KtTestUtil.getJdk17Home()
)
@Test @DisplayName("Assembling shared debug XCFramework for all available ios and watchos targets ")
fun `assemble XCFramework for all available ios and watchos targets`() { @GradleTest
with(Project("appleXCFramework")) { fun shouldAssembleXCFrameworkForAllAvailableTargets(gradleVersion: GradleVersion) {
project("appleXCFramework", gradleVersion) {
build("assembleSharedDebugXCFramework") { build("assembleSharedDebugXCFramework") {
assertSuccessful()
assertTasksExecuted(":shared:linkDebugFrameworkIosX64") assertTasksExecuted(":shared:linkDebugFrameworkIosX64")
assertTasksExecuted(":shared:linkDebugFrameworkIosArm64") assertTasksExecuted(":shared:linkDebugFrameworkIosArm64")
assertTasksExecuted(":shared:linkDebugFrameworkIosArm32") assertTasksExecuted(":shared:linkDebugFrameworkIosArm32")
@@ -52,14 +41,13 @@ class XCFrameworkIT : BaseGradleIT() {
assertTasksExecuted(":shared:assembleDebugWatchosFatFrameworkForSharedXCFramework") assertTasksExecuted(":shared:assembleDebugWatchosFatFrameworkForSharedXCFramework")
assertTasksExecuted(":shared:assembleDebugWatchosSimulatorFatFrameworkForSharedXCFramework") assertTasksExecuted(":shared:assembleDebugWatchosSimulatorFatFrameworkForSharedXCFramework")
assertTasksExecuted(":shared:assembleSharedDebugXCFramework") assertTasksExecuted(":shared:assembleSharedDebugXCFramework")
assertFileExists("/shared/build/XCFrameworks/debug/shared.xcframework") assertDirectoryInProjectExists("shared/build/XCFrameworks/debug/shared.xcframework")
assertFileExists("/shared/build/XCFrameworks/debug/shared.xcframework/ios-arm64_x86_64-simulator/dSYMs/shared.framework.dSYM") assertDirectoryInProjectExists("shared/build/XCFrameworks/debug/shared.xcframework/ios-arm64_x86_64-simulator/dSYMs/shared.framework.dSYM")
assertFileExists("/shared/build/sharedXCFrameworkTemp/fatframework/debug/watchos/shared.framework") assertDirectoryInProjectExists("shared/build/sharedXCFrameworkTemp/fatframework/debug/watchos/shared.framework")
assertFileExists("/shared/build/sharedXCFrameworkTemp/fatframework/debug/watchos/shared.framework.dSYM") assertDirectoryInProjectExists("shared/build/sharedXCFrameworkTemp/fatframework/debug/watchos/shared.framework.dSYM")
} }
build("assembleSharedDebugXCFramework") { build("assembleSharedDebugXCFramework") {
assertSuccessful()
assertTasksUpToDate(":shared:linkDebugFrameworkIosArm64") assertTasksUpToDate(":shared:linkDebugFrameworkIosArm64")
assertTasksUpToDate(":shared:linkDebugFrameworkIosX64") assertTasksUpToDate(":shared:linkDebugFrameworkIosX64")
assertTasksUpToDate(":shared:linkDebugFrameworkWatchosArm32") assertTasksUpToDate(":shared:linkDebugFrameworkWatchosArm32")
@@ -72,85 +60,78 @@ class XCFrameworkIT : BaseGradleIT() {
} }
} }
@Test @DisplayName("Assembling other XCFramework for ios targets")
fun `assemble other XCFramework for ios targets`() { @GradleTest
with(Project("appleXCFramework")) { fun shouldAssembleOtherXCFrameworkForIosTargets(gradleVersion: GradleVersion) {
project("appleXCFramework", gradleVersion) {
build("assembleOtherXCFramework") { build("assembleOtherXCFramework") {
assertSuccessful()
assertTasksExecuted(":shared:linkReleaseFrameworkIosArm64") assertTasksExecuted(":shared:linkReleaseFrameworkIosArm64")
assertTasksExecuted(":shared:linkReleaseFrameworkIosX64") assertTasksExecuted(":shared:linkReleaseFrameworkIosX64")
assertTasksExecuted(":shared:assembleOtherReleaseXCFramework") assertTasksExecuted(":shared:assembleOtherReleaseXCFramework")
assertFileExists("/shared/build/XCFrameworks/release/other.xcframework") assertDirectoryInProjectExists("shared/build/XCFrameworks/release/other.xcframework")
assertFileExists("/shared/build/XCFrameworks/release/other.xcframework/ios-arm64/dSYMs/shared.framework.dSYM") assertDirectoryInProjectExists("shared/build/XCFrameworks/release/other.xcframework/ios-arm64/dSYMs/shared.framework.dSYM")
assertTasksExecuted(":shared:linkDebugFrameworkIosArm64") assertTasksExecuted(":shared:linkDebugFrameworkIosArm64")
assertTasksExecuted(":shared:linkDebugFrameworkIosX64") assertTasksExecuted(":shared:linkDebugFrameworkIosX64")
assertTasksExecuted(":shared:assembleOtherDebugXCFramework") assertTasksExecuted(":shared:assembleOtherDebugXCFramework")
assertFileExists("/shared/build/XCFrameworks/debug/other.xcframework") assertDirectoryInProjectExists("shared/build/XCFrameworks/debug/other.xcframework")
assertFileExists("/shared/build/XCFrameworks/debug/other.xcframework/ios-arm64/dSYMs/shared.framework.dSYM") assertDirectoryInProjectExists("shared/build/XCFrameworks/debug/other.xcframework/ios-arm64/dSYMs/shared.framework.dSYM")
assertContains("Name of XCFramework 'other' differs from inner frameworks name 'shared'! Framework renaming is not supported yet") assertOutputContains("Name of XCFramework 'other' differs from inner frameworks name 'shared'! Framework renaming is not supported yet")
} }
} }
} }
@Test @DisplayName("XCFramework doesn't contain any framework's tasks without declaration in build script")
fun `check there aren't XCFramework tasks without declaration in build script`() { @GradleAndroidTest
with(Project("sharedAppleFramework")) { fun shouldNotContainNotDeclaredTasks(gradleVersion: GradleVersion) {
val currentGradleVersion = chooseWrapperVersionOrFinishTest() project("appleXCFramework", gradleVersion) {
val options = defaultBuildOptions().suppressDeprecationWarningsOn( build("tasks") {
"AGP uses deprecated IncrementalTaskInputs (Gradle 7.5)" assertTasksInBuildOutput(
) { options -> expectedAbsentTasks = listOf(
GradleVersion.version(currentGradleVersion) >= GradleVersion.version(TestVersions.Gradle.G_7_5) && options.safeAndroidGradlePluginVersion < AGPVersion.v7_3_0 "shared:assembleSharedDebugXCFramework",
} "shared:assembleSharedReleaseXCFramework",
build("tasks", options = options) { "shared:assembleXCFramework"
assertSuccessful() )
assertTasksNotRegistered(
":shared:assembleSharedDebugXCFramework",
":shared:assembleSharedReleaseXCFramework",
":shared:assembleXCFramework"
) )
} }
} }
} }
@Test @DisplayName("Two XCFrameworks were registered with same name")
fun `check configuration error if two XCFrameworks were registered with same name`() { @GradleTest
with(transformProjectWithPluginsDsl("appleXCFramework")) { fun shouldCheckConfigurationErrorWithTwoRegisteredXCFrameworks(gradleVersion: GradleVersion) {
with(gradleBuildScript("shared")) { project("appleXCFramework", gradleVersion) {
var text = readText() subProject("shared")
text = text.replace("XCFramework(\"other\")", "XCFramework()") .buildGradleKts
writeText(text) .replaceText("XCFramework(\"other\")", "XCFramework()")
}
build("tasks") { buildAndFail("tasks") {
assertFailed() assertOutputContains("Cannot add task 'assembleSharedReleaseXCFramework' as a task with that name already exists.")
assertContains("Cannot add task 'assembleSharedReleaseXCFramework' as a task with that name already exists.")
} }
} }
} }
@Test @DisplayName("K/N project with XCFramework, that contains frameworks with different names")
fun `check configuration error if XCFramework contains frameworks with different names`() { @GradleTest
with(transformProjectWithPluginsDsl("appleXCFramework")) { fun shouldCheckConfigurationErrorForXCFrameworkWithDifferentFrameworksNames(gradleVersion: GradleVersion) {
with(gradleBuildScript("shared")) { project("appleXCFramework", gradleVersion) {
var text = readText() subProject("shared")
text = text.replaceFirst("baseName = \"shared\"", "baseName = \"awesome\"") .buildGradleKts
writeText(text) .replaceFirst("baseName = \"shared\"", "baseName = \"awesome\"")
}
build("tasks") { buildAndFail("tasks") {
assertFailed() assertOutputContains("All inner frameworks in XCFramework 'shared' should have same names. But there are two with 'awesome' and 'shared' names")
assertContains("All inner frameworks in XCFramework 'shared' should have same names. But there are two with 'awesome' and 'shared' names")
} }
} }
} }
@Test @DisplayName("Assembling framework does not produce an error or fail when there are no sources to assemble")
fun `assemble framework does nothing when no sources rather than fail`() { @GradleTest
with(transformProjectWithPluginsDsl("appleXCFramework")) { fun shouldNotProduceErrorsWithoutSources(gradleVersion: GradleVersion) {
projectDir.resolve("shared/src").deleteRecursively() project("appleXCFramework", gradleVersion) {
projectPath.resolve("shared/src").deleteRecursively()
build(":shared:assembleXCFramework") { build(":shared:assembleXCFramework") {
assertSuccessful() assertTasksNoSource(
assertTasksSkipped(
":shared:assembleSharedDebugXCFramework", ":shared:assembleSharedDebugXCFramework",
":shared:assembleSharedReleaseXCFramework", ":shared:assembleSharedReleaseXCFramework",
) )
@@ -158,23 +139,21 @@ class XCFrameworkIT : BaseGradleIT() {
} }
} }
@Test @DisplayName("XCFramework handles dashes in its name correctly")
fun `check assemble framework handles dashes in its name correctly`() { @GradleTest
with(transformProjectWithPluginsDsl("appleXCFramework")) { fun shouldCheckDashesHandlingWithXCFramework(gradleVersion: GradleVersion) {
with(gradleBuildScript("shared")) { project("appleXCFramework", gradleVersion) {
var text = readText()
text = text.replace("baseName = \"shared\"", "baseName = \"sha-red\"") val sharedBuildGradleKts = subProject("shared").buildGradleKts
text = text.replace("XCFramework()", "XCFramework(\"sha-red\")") sharedBuildGradleKts.replaceText("baseName = \"shared\"", "baseName = \"sha-red\"")
writeText(text) sharedBuildGradleKts.replaceText("XCFramework()", "XCFramework(\"sha-red\")")
}
build(":shared:assembleSha-redXCFramework") { build(":shared:assembleSha-redXCFramework") {
assertSuccessful()
assertTasksExecuted( assertTasksExecuted(
":shared:assembleSha-redDebugXCFramework", ":shared:assembleSha-redDebugXCFramework",
":shared:assembleSha-redReleaseXCFramework", ":shared:assembleSha-redReleaseXCFramework",
) )
assertNotContains("differs from inner frameworks name") assertOutputDoesNotContain("differs from inner frameworks name")
} }
} }
} }
@@ -164,22 +164,40 @@ fun BuildResult.assertNativeTasksClasspath(
* or if any of the not-registered tasks were actually registered. * or if any of the not-registered tasks were actually registered.
*/ */
fun TestProject.buildAndAssertAllTasks( fun TestProject.buildAndAssertAllTasks(
vararg registeredTasks: String, registeredTasks: List<String> = emptyList(),
notRegisteredTasks: List<String> = emptyList() notRegisteredTasks: List<String> = emptyList()
) { ) {
build("tasks", "--all") { build("tasks", "--all") {
val allRegisteredTasks = getAllTasksFromTheOutput() assertTasksInBuildOutput(registeredTasks, notRegisteredTasks)
registeredTasks.forEach { }
assert(allRegisteredTasks.contains(it)) { }
printBuildOutput()
"Expected $it task is not registered in all tasks." /**
} * Inspects the output of the 'tasks' command and asserts that the specified
* tasks are either present or absent in the output.
*
* @param expectedPresentTasks The names of the tasks that should be present in the output,
* it could contain task paths as well, but without the first semicolon.
* @param expectedAbsentTasks The names of the tasks that should be absent from the output,
* it could contain task paths as well, but without the first semicolon.
* @throws AssertionError if any of the expected present tasks are not present in the output,
* or if any of the expected absent tasks are present in the output.
*/
fun BuildResult.assertTasksInBuildOutput(
expectedPresentTasks: List<String> = emptyList(),
expectedAbsentTasks: List<String> = emptyList()
) {
val registeredTasks = getAllTasksFromTheOutput()
expectedPresentTasks.forEach {
assert(registeredTasks.contains(it)) {
printBuildOutput()
"Expected $it task is not registered in $registeredTasks"
} }
notRegisteredTasks.forEach { }
assert(!allRegisteredTasks.contains(it)) { expectedAbsentTasks.forEach {
printBuildOutput() assert(!registeredTasks.contains(it)) {
"$it task should not be registered in all tasks." printBuildOutput()
} "$it task should not be registered in $registeredTasks"
} }
} }
} }
@@ -112,3 +112,7 @@ fun File.replaceText(oldValue: String, newValue: String) {
fun File.replaceText(regex: Regex, replacement: String) { fun File.replaceText(regex: Regex, replacement: String) {
writeText(readText().replace(regex, replacement)) writeText(readText().replace(regex, replacement))
} }
fun Path.replaceFirst(oldValue: String, newValue: String) {
writeText(readText().replaceFirst(oldValue, newValue))
}