[K/N][Tests] Migrate dylib-interop-exe tests

^KT-61259
This commit is contained in:
Vladimir Sukharev
2024-02-15 13:57:30 +01:00
committed by Space Team
parent 83d851dd61
commit 2b2c685827
56 changed files with 278 additions and 397 deletions
@@ -963,73 +963,6 @@ createInterop("workerSignals") {
}
if (PlatformInfo.isAppleTarget(project)) {
createInterop("objcSmoke") {
it.defFile 'interop/objc/objcSmoke.def'
it.headers "$projectDir/interop/objc/smoke.h"
}
createInterop("objcTests") {
it.defFile 'interop/objc/objcTests.def'
it.headers fileTree("$projectDir/interop/objc/tests") { include '**/*.h' }
}
createInterop("objcMisc") {
it.defFile 'interop/objc_with_initializer/objc_misc.def'
it.headers "$projectDir/interop/objc_with_initializer/objc_misc.h"
}
createInterop("objcMessaging") {
it.defFile 'interop/objc/msg_send/messaging.def'
it.headers "$projectDir/interop/objc/msg_send/messaging.h"
}
createInterop("foreignException") {
it.defFile 'interop/objc/foreignException/objc_wrap.def'
it.headers "$projectDir/interop/objc/foreignException/objc_wrap.h"
}
createInterop("foreignExceptionMode_default") {
it.defFile 'interop/objc/foreignException/objcExceptionMode.def'
it.headers "$projectDir/interop/objc/foreignException/objc_wrap.h"
}
createInterop("foreignExceptionMode_wrap") {
it.defFile 'interop/objc/foreignException/objcExceptionMode.def'
it.headers "$projectDir/interop/objc/foreignException/objc_wrap.h"
it.extraOpts '-Xforeign-exception-mode', "objc-wrap"
}
createInterop("objcKt43517") {
it.defFile 'framework/kt43517/kt43517.def'
}
createInterop("objc_kt42172") {
it.defFile 'interop/objc/kt42172/objclib.def'
it.headers "$projectDir/interop/objc/kt42172/objclib.h"
}
createInterop("objc_kt55938") {
it.defFile 'interop/objc/kt55938/objclib.def'
it.headers "$projectDir/interop/objc/kt55938/objclib.h"
}
createInterop("objc_include_categories") {
it.defFile 'interop/objc/include_categories/objc_include_categories.def'
it.headers "$projectDir/interop/objc/include_categories/objc_include_categories.h"
}
createInterop("frameworkForwardDeclarations") {
it.defFile 'framework/forwardDeclarations/clib.def'
}
createInterop("objc_kt56402") {
it.defFile 'interop/objc/kt56402/objclib.def'
it.headers "$projectDir/interop/objc/kt56402/objclib.h"
}
createInterop("objc_friendly_dealloc") {
it.defFile 'interop/objc/objc_friendly_dealloc/objclib.def'
it.headers "$projectDir/interop/objc/objc_friendly_dealloc/objclib.h"
}
createInterop("objCAction") {
it.defFile 'interop/objc/objCAction/objclib.def'
it.headers "$projectDir/interop/objc/objCAction/objclib.h"
}
createInterop("kt63423_dispose_on_main_stress") {
it.defFile 'interop/objc/kt63423_dispose_on_main_stress/objclib.def'
it.headers "$projectDir/interop/objc/kt63423_dispose_on_main_stress/objclib.h"
@@ -1157,160 +1090,6 @@ if (PlatformInfo.isAppleTarget(project)) {
UtilsKt.dependsOnPlatformLibs(it)
}
interopTest("interop_objc_global_initializer") {
useGoldenData = true
source = "interop/objc_with_initializer/objc_test.kt"
interop = 'objcMisc'
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcmisc.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc_with_initializer/objc_misc.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_msg_send") {
source = "interop/objc/msg_send/main.kt"
interop = 'objcMessaging'
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcmessaging.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/msg_send/messaging.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_foreignException") {
source = "interop/objc/foreignException/objc_wrap.kt"
interop = 'foreignException'
UtilsKt.dependsOnPlatformLibs(it)
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcexception.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/foreignException/objc_wrap.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_foreignExceptionMode_wrap") {
source = "interop/objc/foreignException/objcExceptionMode_wrap.kt"
interop = 'foreignExceptionMode_wrap'
useGoldenData = true
UtilsKt.dependsOnPlatformLibs(it)
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcexception.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/foreignException/objc_wrap.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_foreignExceptionMode_default") {
source = "interop/objc/foreignException/objcExceptionMode_default.kt"
interop = 'foreignExceptionMode_default'
useGoldenData = true
UtilsKt.dependsOnPlatformLibs(it)
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcexception.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/foreignException/objc_wrap.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_kt42172") {
enabled = !isNoopGC
source = "interop/objc/kt42172/main.kt"
interop = "objc_kt42172"
flags = ['-opt-in=kotlin.native.internal.InternalForKotlinNative']
useGoldenData = true
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjc_kt42172.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/kt42172/objclib.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_kt55938") {
source = "interop/objc/kt55938/main.kt"
lib = "interop/objc/kt55938/lib.kt"
interop = "objc_kt55938"
useGoldenData = true
enabled = cacheTesting != null
flags = [
"-Xauto-cache-from=$testOutputRoot/local/objc_kt55938",
"-Xauto-cache-from=$testOutputRoot/local/interop_objc_kt55938",
"-Xauto-cache-dir=$testOutputRoot/local/interop_objc_kt55938/cache",
"-Xsuppress-version-warnings", // suppresses warning about experimental language version, otherwise test fails with K2 due to -Werror
"-Werror" // to forbid retry with auto-cache disabled
]
UtilsKt.findKonanBuildTask(project, "objc_kt55938", target).configure {
it.doFirst {
def cacheDir = new File("$testOutputRoot/local/interop_objc_kt55938/cache")
cacheDir.deleteDir()
mkdir(cacheDir)
}
}
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjc_kt55938.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/kt55938/objclib.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
standaloneTest("objc_arc_contract") {
def bcFile = project.layout.buildDirectory.file("objc_arc_contract.bc").get().asFile
doBeforeBuild {
@@ -1325,24 +1104,6 @@ if (PlatformInfo.isAppleTarget(project)) {
flags = ["-native-library", bcFile.toString()]
}
interopTest("interop_objc_include_categories") {
useGoldenData = true
source = "interop/objc/include_categories/main.kt"
interop = "objc_include_categories"
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjcincludecategories.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/include_categories/objc_include_categories.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
standaloneTest("interop_kt55653") {
// Test depends on macOS-specific AppKit
enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null)
@@ -1359,70 +1120,6 @@ if (PlatformInfo.isAppleTarget(project)) {
UtilsKt.dependsOnPlatformLibs(it)
}
interopTest("interop_objc_kt56402") {
// Test depends on macOS-specific AppKit
enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null)
&& !isNoopGC // requires some GC
source = 'interop/objc/kt56402/main.kt'
interop = "objc_kt56402"
flags = ["-tr", "-e", "runAllTests"] // Generate test suites, but use custom entrypoint.
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjc_kt56402.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/kt56402/objclib.m"
args "-g"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
args '-framework', 'AppKit'
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
}
interopTest("interop_objc_friendly_dealloc") {
enabled = !isNoopGC // requires some GC
source = 'interop/objc/objc_friendly_dealloc/main.kt'
interop = "objc_friendly_dealloc"
flags = ["-tr"]
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjc_friendly_dealloc.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/objc_friendly_dealloc/objclib.m"
args "-lobjc", '-fno-objc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
UtilsKt.dependsOnPlatformLibs(it)
}
interopTest("interop_objCAction") {
source = 'interop/objc/objCAction/main.kt'
interop = "objCAction"
flags = ["-tr"]
doBeforeBuild {
def dylibFile = project.layout.buildDirectory.file("libobjCAction.dylib").get().asFile
mkdir(dylibFile.parentFile)
project.extensions.execClang.execClangForCompilerTests(project.target) {
args "$projectDir/interop/objc/objCAction/objclib.m"
args "-lobjc", '-fobjc-arc'
args '-fPIC', '-shared', '-o', dylibFile.toString()
}
if (UtilsKt.isSimulatorTarget(project, project.target)) {
UtilsKt.codesign(project, dylibFile.toString())
}
}
UtilsKt.dependsOnPlatformLibs(it)
}
interopTest("interop_objc_kt63423_dispose_on_main_stress") {
// Test depends on macOS-specific AppKit
enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null)
@@ -1 +0,0 @@
OK: Ends with uncaught exception handler
@@ -1 +0,0 @@
OK: ForeignException
@@ -1,10 +0,0 @@
3.0
3.14
6.0
3
6
6.0
3.0
600.0
@@ -1,4 +0,0 @@
language = Objective-C
headerFilter = **/objc_include_categories.h
linkerOpts = -lobjcincludecategories
objcClassesIncludingCategories = BaseClass DerivedClass
@@ -1 +0,0 @@
Executed finalizer
@@ -1,3 +0,0 @@
language = Objective-C
headerFilter = **/objclib.h
linkerOpts = -lobjc_kt42172
@@ -1,11 +0,0 @@
/*
* 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.
*/
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
package kt55938lib
import objclib.*
inline fun foo() = ObjCClass.foo()
@@ -1,10 +0,0 @@
/*
* 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.
*/
import kt55938lib.*
fun main() {
print("foo() call result is ${foo()}")
}
@@ -1 +0,0 @@
foo() call result is 42
@@ -1,3 +0,0 @@
language = Objective-C
headerFilter = **/objclib.h
linkerOpts = -lobjc_kt55938
@@ -1,5 +0,0 @@
#import <Foundation/Foundation.h>
@interface ObjCClass : NSObject
+ (int)foo;
@end
@@ -1,11 +0,0 @@
#include "objclib.h"
@implementation ObjCClass {
}
+ (int)foo {
return 42;
}
@end
@@ -1,3 +0,0 @@
language = Objective-C
headerFilter = **/objclib.h
linkerOpts = -lobjc_kt56402
@@ -1,3 +0,0 @@
language = Objective-C
headerFilter = **/objclib.h
linkerOpts = -lobjc_friendly_dealloc
@@ -1,5 +0,0 @@
language = Objective-C
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h
headerFilter = **/objc_misc.h Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h
linkerOpts = -lobjcmisc
@@ -0,0 +1,40 @@
// TARGET_BACKEND: NATIVE
// MODULE: cinterop
// FILE: kt55938.def
language = Objective-C
headers = kt55938.h
// FILE: kt55938.h
#import <Foundation/Foundation.h>
@interface ObjCClass : NSObject
+ (int)foo;
@end
// FILE: kt55938.m
#include "kt55938.h"
@implementation ObjCClass {
}
+ (int)foo {
return 42;
}
@end
// MODULE: lib(cinterop)
// FILE: lib.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
package kt55938lib
import kt55938.*
inline fun foo() = ObjCClass.foo()
// MODULE: main(lib, cinterop)
// FILE: main.kt
import kt55938lib.*
fun box(): String {
val foo = foo()
if (foo != 42) return "FAIL $foo"
return "OK"
}
@@ -1,3 +1,3 @@
language = Objective-C
headerFilter = **/objc_wrap.h
linkerOpts = -lobjcexception
linkerOpts = -lforeignException
@@ -1,4 +1,4 @@
language = Objective-C
headerFilter = **/objc_wrap.h
linkerOpts = -lobjcexception
linkerOpts = -lforeignException
foreignExceptionMode = objc-wrap
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/friendly_dealloc.h
linkerOpts = -lfriendly_dealloc
@@ -4,7 +4,7 @@
*/
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
import objclib.*
import friendly_dealloc.*
import platform.objc.*
import platform.Foundation.*
@@ -15,7 +15,6 @@ import kotlin.system.exitProcess
import kotlin.test.*
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Duration.Companion.minutes
import kotlinx.cinterop.*
val timeout = 10.seconds
@@ -1,4 +1,4 @@
#include "objclib.h"
#include "friendly_dealloc.h"
@implementation OnDestroyHook {
void (^_onDestroy)(uintptr_t);
@@ -0,0 +1,4 @@
language = Objective-C
headerFilter = **/include_categories.h
linkerOpts = -linclude_categories
objcClassesIncludingCategories = BaseClass DerivedClass
@@ -2,7 +2,7 @@
* 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.
*/
import objc_include_categories.*
import include_categories.*
class KotlinDerived : BaseClass() {
override fun multiplyBy(value: Int): Float {
@@ -1,4 +1,4 @@
#include "objc_include_categories.h"
#include "include_categories.h"
@implementation BaseClass
-(id) init {
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/kt42172.h
linkerOpts = -lkt42172
@@ -1,6 +1,6 @@
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
import objclib.*
import kt42172.*
import kotlin.native.concurrent.*
import kotlinx.cinterop.*
@@ -1,4 +1,4 @@
#include "objclib.h"
#include "kt42172.h"
@implementation WithFinalizer {
Finalizer finalizer_;
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/kt56402.h
linkerOpts = -lkt56402
@@ -4,7 +4,7 @@
*/
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
import objclib.*
import kt56402.*
import kotlin.concurrent.AtomicInt
import kotlin.native.concurrent.*
@@ -185,7 +185,7 @@ fun testProtocolOnSecondaryThread() {
waitDestruction(id)
}
fun runAllTests(args: Array<String>) = startApp {
fun main(args: Array<String>) = startApp {
val exitCode = testLauncherEntryPoint(args)
if (exitCode != 0) {
exitProcess(exitCode)
@@ -1,4 +1,4 @@
#include "objclib.h"
#include "kt56402.h"
#include <assert.h>
#include <dispatch/dispatch.h>
@@ -1,3 +1,3 @@
language = Objective-C
headerFilter = **/messaging.h
linkerOpts = -lobjcmessaging
linkerOpts = -lmessaging
@@ -1,3 +1,3 @@
language = Objective-C
headerFilter = **/objclib.h
headerFilter = **/objCAction.h
linkerOpts = -lobjCAction
@@ -5,7 +5,7 @@
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
import objclib.*
import objCAction.*
import platform.Foundation.*
import kotlin.test.*
@@ -1,4 +1,4 @@
#include "objclib.h"
#include "objCAction.h"
void performSelector0(id target, NSString* selectorName) {
NSLog(@"performSelector0(%@, %@)", target, selectorName);
@@ -0,0 +1,5 @@
language = Objective-C
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h
headerFilter = **/with_initializer.h Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h
linkerOpts = -lwith_initializer
@@ -1,6 +1,6 @@
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
import objc_misc.*
import with_initializer.*
import kotlin.native.Platform
val a = B.giveC()!! as C
@@ -1,5 +1,5 @@
#import <Foundation/Foundation.h>
#include "objc_misc.h"
#include "with_initializer.h"
@implementation A
@end
@@ -927,6 +927,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox
runTest("native/native.tests/testData/codegen/cinterop/kt54284_fmodules.kt");
}
@Test
@TestMetadata("kt55938.kt")
public void testKt55938() {
runTest("native/native.tests/testData/codegen/cinterop/kt55938.kt");
}
@Test
@TestMetadata("kt57640.kt")
public void testKt57640() {
@@ -905,6 +905,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes
runTest("native/native.tests/testData/codegen/cinterop/kt54284_fmodules.kt");
}
@Test
@TestMetadata("kt55938.kt")
public void testKt55938() {
runTest("native/native.tests/testData/codegen/cinterop/kt55938.kt");
}
@Test
@TestMetadata("kt57640.kt")
public void testKt57640() {
@@ -22,12 +22,14 @@ import org.jetbrains.kotlin.konan.test.blackbox.support.settings.*
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Timeouts
import org.jetbrains.kotlin.konan.test.blackbox.support.util.ClangDistribution
import org.jetbrains.kotlin.konan.test.blackbox.support.util.compileWithClang
import org.jetbrains.kotlin.native.executors.RunProcessResult
import org.jetbrains.kotlin.native.executors.runProcess
import org.jetbrains.kotlin.test.TestMetadata
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.time.Duration
@@ -205,6 +207,192 @@ abstract class ComplexCInteropTestBase : AbstractNativeSimpleTest() {
runExecutableAndVerify(testCase, testExecutable)
}
@Test
@TestMetadata("with_initializer")
fun testObjCWithGlobalInitializer() {
val execResult = testDylibCinteropExe("with_initializer")
assertEquals("OK", execResult.stdout)
}
@Test
@TestMetadata("messaging")
fun testMessaging() {
testDylibCinteropExe("messaging")
}
@Test
@TestMetadata("kt42172")
fun testKt42172() {
Assumptions.assumeFalse(testRunSettings.get<GCType>() == GCType.NOOP)
val execResult = testDylibCinteropExe("kt42172")
assertEquals("Executed finalizer", execResult.stdout)
}
@Test
@TestMetadata("include_categories")
fun testInclude_categories() {
val execResult = testDylibCinteropExe("include_categories")
assertEquals("""
3.0
3.14
6.0
3
6
6.0
3.0
600.0
""".trimIndent(), execResult.stdout)
}
@Test
@TestMetadata("kt56402")
fun testKt56402() {
// Test depends on macOS-specific AppKit and some GC
Assumptions.assumeTrue(targets.testTarget.family == Family.OSX)
Assumptions.assumeFalse(testRunSettings.get<GCType>() == GCType.NOOP)
val execResult = testDylibCinteropExe(
"kt56402",
extraClangOpts = listOf("-framework", "AppKit", "-fobjc-arc"),
extraCompilerOpts = listOf("-tr"),
)
assertTrue(execResult.stdout.contains("[ PASSED ] 8 tests"))
}
@Test
@TestMetadata("friendly_dealloc")
fun testFriendly_dealloc() {
Assumptions.assumeFalse(testRunSettings.get<GCType>() == GCType.NOOP)
val execResult = testDylibCinteropExe(
"friendly_dealloc",
extraClangOpts = listOf("-fno-objc-arc"),
extraCompilerOpts = listOf("-tr", "-XXLanguage:+ImplicitSignedToUnsignedIntegerConversion"),
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT),
)
assertTrue(execResult.stdout.contains("[ PASSED ] 4 tests"))
}
@Test
@TestMetadata("objCAction")
fun testObjCAction() {
val execResult = testDylibCinteropExe(
"objCAction",
extraCompilerOpts = listOf("-tr"),
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT),
)
assertTrue(execResult.stdout.contains("[ PASSED ] 5 tests"))
}
@Test
@TestMetadata("foreignException")
fun testForeignException() {
val res = testDylibCinteropExe(
"foreignException",
"objc_wrap.h",
"objc_wrap.m",
"objc_wrap.def",
"objc_wrap.kt",
)
assertEquals("", res.stdout)
assertEquals("", res.stderr)
}
@Test
@TestMetadata("foreignException")
fun testForeignExceptionMode_default() {
val res = testDylibCinteropExe(
"foreignException",
"objc_wrap.h",
"objc_wrap.m",
"objcExceptionMode.def",
"objcExceptionMode_wrap.kt",
)
assertEquals("OK: Ends with uncaught exception handler", res.stdout)
assertEquals("", res.stderr)
}
@Test
@TestMetadata("foreignException")
fun testForeignExceptionMode_wrap() {
val res = testDylibCinteropExe(
"foreignException",
"objc_wrap.h",
"objc_wrap.m",
"objcExceptionMode.def",
"objcExceptionMode_wrap.kt",
extraCinteropArgs = listOf("-Xforeign-exception-mode", "objc-wrap")
)
assertEquals("OK: ForeignException", res.stdout)
assertEquals("", res.stderr)
}
private fun testDylibCinteropExe(
testName: String,
extraClangOpts: List<String> = listOf("-fobjc-arc"),
extraCompilerOpts: List<String> = emptyList(),
extras: TestCase.Extras = TestCase.NoTestRunnerExtras("main"),
): RunProcessResult {
return testDylibCinteropExe(
testName,
hFile = "$testName.h",
mFile = "$testName.m",
defFile = "$testName.def",
ktFile = "$testName.kt",
extraClangOpts = extraClangOpts,
extraCompilerOpts = extraCompilerOpts,
extras = extras,
)
}
private fun testDylibCinteropExe(
testName: String,
hFile: String,
mFile: String,
defFile: String,
ktFile: String,
extraCinteropArgs: List<String> = emptyList(),
extraClangOpts: List<String> = listOf("-fobjc-arc"),
extraCompilerOpts: List<String> = emptyList(),
extras: TestCase.Extras = TestCase.NoTestRunnerExtras("main"),
): RunProcessResult {
Assumptions.assumeTrue(targets.testTarget.family.isAppleFamily)
val srcDir = interopObjCDir.resolve(testName)
val dylib = compileDylib(testName, listOf(srcDir.resolve(mFile)), extraClangOpts)
if (testRunSettings.configurables.targetTriple.isSimulator)
codesign(dylib.resultingArtifact.path)
val cinteropKlib = cinteropToLibrary(
targets = targets,
defFile = srcDir.resolve(defFile),
outputDir = buildDir,
freeCompilerArgs = TestCompilerArgs(
compilerArgs = emptyList(),
cinteropArgs = extraCinteropArgs + listOf("-header", srcDir.resolve(hFile).absolutePath)
)
).assertSuccess().resultingArtifact
val testKind = when (extras) {
is TestCase.NoTestRunnerExtras -> TestKind.STANDALONE_NO_TR
is TestCase.WithTestRunnerExtras -> TestKind.STANDALONE
}
val testCase = generateTestCaseWithSingleFile(
sourceFile = srcDir.resolve(ktFile),
moduleName = testName,
testKind = testKind,
extras = extras,
freeCompilerArgs = TestCompilerArgs(
"-opt-in=kotlinx.cinterop.ExperimentalForeignApi",
"-opt-in=kotlin.native.internal.InternalForKotlinNative",
"-linker-option", "-L${buildDir.absolutePath}",
*extraCompilerOpts.toTypedArray()
)
)
val success = compileToExecutable(testCase, cinteropKlib.asLibraryDependency()).assertSuccess()
return testRunSettings.executor.runProcess(success.resultingArtifact.executableFile.absolutePath)
}
@Test
@TestMetadata("withSpaces.kt")
fun testWithSpaces() {
@@ -255,7 +443,7 @@ abstract class ComplexCInteropTestBase : AbstractNativeSimpleTest() {
assertTrue(mapfile.exists())
}
private fun compileDylib(name: String, mSources: List<File>): TestCompilationResult.Success<out TestCompilationArtifact.Executable> {
private fun compileDylib(name: String, mSources: List<File>, extraClangOpts: List<String> = listOf("-fobjc-arc")): TestCompilationResult.Success<out TestCompilationArtifact.Executable> {
val clangResult = compileWithClang(
clangDistribution = ClangDistribution.Llvm,
sourceFiles = mSources,
@@ -263,8 +451,8 @@ abstract class ComplexCInteropTestBase : AbstractNativeSimpleTest() {
outputFile = buildDir.resolve("lib$name.dylib"),
libraryDirectories = emptyList(),
libraries = emptyList(),
additionalClangFlags = listOf(
"-DNS_FORMAT_ARGUMENT(A)=", "-lobjc", "-fobjc-arc", "-fPIC", "-shared",
additionalClangFlags = extraClangOpts + listOf(
"-DNS_FORMAT_ARGUMENT(A)=", "-lobjc", "-fPIC", "-shared",
// Enable ARC optimizations to prevent some objects from leaking in Obj-C code due to exceptions:
"-O2"
),