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