From 690eb1bc78d0160ad7d6d5e2d55961f2f43a283c Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 5 Aug 2024 12:10:58 +0200 Subject: [PATCH] Update --- .../multiplatform/gradle/SentryPlugin.kt | 17 ++- .../gradle/DerivedDataPathTest.kt | 109 ++++++++++++++++++ .../multiplatform/gradle/SentryPluginTest.kt | 36 ++++++ 3 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/DerivedDataPathTest.kt diff --git a/sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt b/sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt index f59bdb4e..edf96df4 100644 --- a/sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt +++ b/sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt @@ -122,7 +122,6 @@ internal fun Project.installSentryForCocoapods( } @Suppress("CyclomaticComplexMethod") -// todo: write test internal fun Project.configureLinkingOptions(linkerExtension: LinkerExtension) { val kmpExtension = extensions.findByName(KOTLIN_EXTENSION_NAME) if (kmpExtension !is KotlinMultiplatformExtension || kmpExtension.targets.isEmpty() || !HostManager.hostIsMac) { @@ -137,8 +136,6 @@ internal fun Project.configureLinkingOptions(linkerExtension: LinkerExtension) { derivedDataPath = findDerivedDataPath(customXcodeprojPath) } - logger.warn("framework path: $frameworkPath") - kmpExtension.appleTargets().all { target -> val frameworkArchitecture = target.toSentryFrameworkArchitecture() ?: run { logger.warn("Skipping target ${target.name} - unsupported architecture.") @@ -148,18 +145,18 @@ internal fun Project.configureLinkingOptions(linkerExtension: LinkerExtension) { val dynamicFrameworkPath: String val staticFrameworkPath: String - if (frameworkPath?.isNotEmpty() == false) { + if (frameworkPath?.isNotEmpty() == true) { dynamicFrameworkPath = frameworkPath staticFrameworkPath = frameworkPath } else { @Suppress("MaxLineLength") dynamicFrameworkPath = "$derivedDataPath/SourcePackages/artifacts/sentry-cocoa/Sentry-Dynamic/Sentry-Dynamic.xcframework/$frameworkArchitecture" + @Suppress("MaxLineLength") staticFrameworkPath = "$derivedDataPath/SourcePackages/artifacts/sentry-cocoa/Sentry/Sentry.xcframework/$frameworkArchitecture" } - assert(frameworkPath == "haha") val dynamicFrameworkExists = File(dynamicFrameworkPath).exists() val staticFrameworkExists = File(staticFrameworkPath).exists() @@ -172,13 +169,13 @@ internal fun Project.configureLinkingOptions(linkerExtension: LinkerExtension) { target.binaries.all binaries@{ binary -> if (binary is TestExecutable) { // both dynamic and static frameworks will work for tests - val frameworkPath = + val finalFrameworkPath = if (dynamicFrameworkExists) dynamicFrameworkPath else staticFrameworkPath - binary.linkerOpts("-rpath", frameworkPath, "-F$frameworkPath") + binary.linkerOpts("-rpath", finalFrameworkPath, "-F$finalFrameworkPath") } if (binary is Framework) { - val frameworkPath = when { + val finalFrameworkPath = when { binary.isStatic && staticFrameworkExists -> staticFrameworkPath !binary.isStatic && dynamicFrameworkExists -> dynamicFrameworkPath else -> { @@ -186,8 +183,8 @@ internal fun Project.configureLinkingOptions(linkerExtension: LinkerExtension) { return@binaries } } - binary.linkerOpts("-F$frameworkPath") - logger.info("Linked framework from $frameworkPath") + binary.linkerOpts("-F$finalFrameworkPath") + logger.info("Linked framework from $finalFrameworkPath") } } } diff --git a/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/DerivedDataPathTest.kt b/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/DerivedDataPathTest.kt new file mode 100644 index 00000000..7e6007e9 --- /dev/null +++ b/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/DerivedDataPathTest.kt @@ -0,0 +1,109 @@ +package io.sentry.kotlin.multiplatform.gradle + +import io.mockk.every +import io.mockk.mockk +import org.gradle.api.Action +import org.gradle.api.GradleException +import org.gradle.process.ExecOperations +import org.gradle.process.ExecResult +import org.gradle.process.ExecSpec +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.io.ByteArrayOutputStream + +class DerivedDataPathTest { + + private lateinit var valueSource: DerivedDataPathValueSource + private lateinit var execOperations: ExecOperations + private lateinit var parameters: DerivedDataPathValueSource.Parameters + + @BeforeEach + fun setup() { + execOperations = mockk() + parameters = mockk() + + valueSource = object : DerivedDataPathValueSource() { + override val execOperations: ExecOperations = this@DerivedDataPathTest.execOperations + override fun getParameters(): Parameters { + return this@DerivedDataPathTest.parameters + } + } + } + + @Test + fun `obtain should return correct derived data path`() { + val xcodebuildOutput = """ + Build settings for action build and target MyTarget: + BUILD_DIR = /DerivedData/Example/Build/Products + """.trimIndent() + + every { parameters.xcodeprojPath } returns mockk { + every { get() } returns "/path/to/project.xcodeproj" + } + + every { execOperations.exec(any()) } answers { + val execSpecLambda = it.invocation.args[0] as Action + val mockExecSpec = mockk(relaxed = true) + + val buildDirOutput = ByteArrayOutputStream() + buildDirOutput.write(xcodebuildOutput.toByteArray()) + + var capturedOutputStream: ByteArrayOutputStream? = null + every { mockExecSpec.commandLine }.returns(listOf()) + every { mockExecSpec.setStandardOutput(any()) } answers { + capturedOutputStream = firstArg() + mockExecSpec + } + + execSpecLambda.execute(mockExecSpec) + + capturedOutputStream?.write(xcodebuildOutput.toByteArray()) + + mockk { + every { exitValue } returns 0 + } + } + + val result = valueSource.obtain() + + assertEquals("/DerivedData/Example", result) + } + + @Test + fun `obtain should throw GradleException when BUILD_DIR is not found`() { + val xcodebuildOutput = "Some output without BUILD_DIR" + + every { parameters.xcodeprojPath } returns mockk { + every { get() } returns "/path/to/project.xcodeproj" + } + + every { execOperations.exec(any()) } answers { + val execSpecLambda = it.invocation.args[0] as Action + val mockExecSpec = mockk(relaxed = true) + + val buildDirOutput = ByteArrayOutputStream() + buildDirOutput.write(xcodebuildOutput.toByteArray()) + + var capturedOutputStream: ByteArrayOutputStream? = null + every { mockExecSpec.commandLine }.returns(listOf()) + every { mockExecSpec.setStandardOutput(any()) } answers { + capturedOutputStream = firstArg() + mockExecSpec + } + + execSpecLambda.execute(mockExecSpec) + + capturedOutputStream?.write(xcodebuildOutput.toByteArray()) + + mockk { + every { exitValue } returns 0 + } + } + + assertThrows { + valueSource.obtain() + } + } +} diff --git a/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/SentryPluginTest.kt b/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/SentryPluginTest.kt index 7810e95d..8bd7bdfc 100644 --- a/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/SentryPluginTest.kt +++ b/sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/SentryPluginTest.kt @@ -2,11 +2,14 @@ package io.sentry.kotlin.multiplatform.gradle import org.gradle.api.plugins.ExtensionAware import org.gradle.testfixtures.ProjectBuilder +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.io.File class SentryPluginTest { @Test @@ -102,4 +105,37 @@ class SentryPluginTest { assertNotNull(commonMainConfiguration) assertTrue(commonMainConfiguration!!.dependencies.contains(sentryDependency)) } + + @Test + fun `configureLinkingOptions sets up linker options for apple targets`(@TempDir tempDir: File) { + val project = ProjectBuilder.builder().build() + + project.pluginManager.apply { + apply("org.jetbrains.kotlin.multiplatform") + apply("io.sentry.kotlin.multiplatform.gradle") + } + + val kmpExtension = project.extensions.getByName("kotlin") as KotlinMultiplatformExtension + kmpExtension.apply { + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { + it.binaries.framework { + baseName = "shared" + isStatic = false + } + } + } + + val file = + tempDir.resolve("test/path") + file.mkdirs() + + val linkerExtension = project.extensions.getByName("linker") as LinkerExtension + linkerExtension.frameworkPath.set(file.absolutePath) + + project.configureLinkingOptions(linkerExtension) + } }