[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
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/friendly_dealloc.h
linkerOpts = -lfriendly_dealloc
@@ -0,0 +1,11 @@
#include <inttypes.h>
#include <objc/NSObject.h>
@interface OnDestroyHook: NSObject
-(instancetype)init:(void(^)(uintptr_t))onDestroy;
-(uintptr_t)identity;
@end
void retain(uintptr_t);
void release(uintptr_t);
void autorelease(uintptr_t);
@@ -0,0 +1,135 @@
/*
* 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(kotlin.experimental.ExperimentalNativeApi::class)
import friendly_dealloc.*
import platform.objc.*
import platform.Foundation.*
import kotlin.concurrent.*
import kotlin.native.concurrent.*
import kotlin.native.internal.test.testLauncherEntryPoint
import kotlin.system.exitProcess
import kotlin.test.*
import kotlin.time.*
import kotlin.time.Duration.Companion.seconds
import kotlinx.cinterop.*
val timeout = 10.seconds
fun <T> allocCollectable(ctor: () -> T): T = autoreleasepool {
ctor()
}
class Event() : NSObject() {
@Volatile
private var triggered = false
fun isTriggered() = triggered
@ObjCAction
fun trigger() {
assertFalse(isTriggered())
triggered = true;
}
}
val trigerSelector = sel_registerName("trigger")
fun waitTriggered(event: Event) {
val timeoutMark = TimeSource.Monotonic.markNow() + timeout
kotlin.native.internal.GC.collect()
while (true) {
if (event.isTriggered()) {
return
}
assertFalse(timeoutMark.hasPassedNow(), "Timed out")
}
}
// All the tests are run on a secondary (non main) thread in order to prevent `objcDisposeOnMain` hacks from messing things up
@Test
fun testAutorelease() {
val event = withWorker {
execute(TransferMode.SAFE, {}) {
val event = Event()
assertFalse(event.isTriggered())
val victimId = allocCollectable {
val v = OnDestroyHook {
event.trigger()
}
retain(v.identity())
v.identity()
}
allocCollectable {
OnDestroyHook {
autorelease(victimId)
}.identity()
}
event
}.result
}
waitTriggered(event)
}
@Test
fun testTimer() {
val event = Event()
withWorker {
execute(TransferMode.SAFE, { event }) { event ->
allocCollectable {
OnDestroyHook {
assertFalse(event.isTriggered())
NSTimer.scheduledTimerWithTimeInterval(0.0, target=event, selector=trigerSelector, userInfo=null, repeats=false)
}.identity()
}
}
}
waitTriggered(event)
}
@Test
fun testSelector() {
val event = Event()
withWorker {
execute(TransferMode.SAFE, { event }) { event ->
allocCollectable {
OnDestroyHook {
assertFalse(event.isTriggered())
NSRunLoop.currentRunLoop().performSelector(trigerSelector, target=event, argument=null, order=0, modes=listOf(NSDefaultRunLoopMode))
}.identity()
}
}
}
waitTriggered(event)
}
@Test
fun testPerformBlock() {
val event = Event()
withWorker {
execute(TransferMode.SAFE, { event }) { event ->
allocCollectable {
OnDestroyHook {
NSRunLoop.currentRunLoop().performBlock({
assertFalse(event.isTriggered())
event.trigger()
});
}.identity()
}
}
}
waitTriggered(event)
}
@@ -0,0 +1,36 @@
#include "friendly_dealloc.h"
@implementation OnDestroyHook {
void (^_onDestroy)(uintptr_t);
}
-(uintptr_t)identity {
return (uintptr_t)self;
}
-(instancetype)init:(void (^)(uintptr_t))onDestroy {
if (self = [super init]) {
_onDestroy = [onDestroy retain];
}
return self;
}
-(void)dealloc {
_onDestroy([self identity]);
[_onDestroy release];
[super dealloc];
}
@end
void retain(uintptr_t obj) {
[((id) obj) retain];
}
void release(uintptr_t obj) {
[((id) obj) release];
}
void autorelease(uintptr_t obj) {
[((id) obj) autorelease];
}