Files
kotlin-fork/native/native.tests/testData/interop/objc/smoke.kt
T
2024-02-22 22:41:37 +00:00

242 lines
7.5 KiB
Kotlin
Vendored

/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class)
import kotlinx.cinterop.*
import objcSmoke.*
import kotlin.native.concurrent.*
import kotlin.native.ref.*
import kotlin.test.*
fun main(args: Array<String>) {
// Test relies on full deinitialization at shutdown.
kotlin.native.runtime.Debugging.forceCheckedShutdown = true
autoreleasepool {
run()
}
}
fun run() {
// TODO: migrate remaining tests to interop/objc/tests/
testTypeOps()
testCustomRetain()
testExportObjCClass()
testLocalizedStrings()
assertEquals(2, ForwardDeclaredEnum.TWO.value)
println(
getSupplier(
invoke1(42) { it * 2 }
)!!()
)
val foo = Foo()
val classGetter = getClassGetter(foo)
invoke2 { println(classGetter()) }
foo.hello()
foo.name = "everybody"
foo.helloWithPrinter(object : NSObject(), PrinterProtocol {
override fun print(string: CPointer<ByteVar>?) {
println("Kotlin says: " + string?.toKString())
}
})
Bar().hello()
val pair = MutablePairImpl(42, 17)
replacePairElements(pair, 1, 2)
pair.swap()
println("${pair.first}, ${pair.second}")
val defaultPair = MutablePairImpl()
assertEquals(defaultPair.first(), 123)
assertEquals(defaultPair.second(), 321)
// equals and hashCode (virtually):
val map = mapOf(foo to pair, pair to foo)
// equals (directly):
if (!foo.equals(pair)) {
// toString (directly):
println(map[pair].toString() + map[foo].toString() == foo.description() + pair.description())
}
// hashCode (directly):
// hash() returns value of NSUInteger type.
val hash = if (sizeOf<NSUIntegerVar>() == 4L) {
foo.hash().toInt()
} else {
foo.hash().let { it.toInt() xor (it shr 32).toInt() }
}
if (foo.hashCode() == hash) {
// toString (virtually):
if (Platform.memoryModel == MemoryModel.STRICT)
println(map.keys.map { it.toString() }.minOrNull() == foo.description())
else
// TODO: hack until proper cycle collection in maps.
println(true)
}
println(globalString)
autoreleasepool {
globalString = "Another global string"
}
println(globalString)
println(globalObject)
globalObject = object : NSObject() {
override fun description() = "global object"
}
println(globalObject)
globalObject = null // Prevent Kotlin object above from leaking.
println(formatStringLength("%d %d", 42, 17))
println(STRING_MACRO)
println(CFSTRING_MACRO)
// Ensure that overriding method bridge has retain-autorelease sequence:
createObjectWithFactory(object : NSObject(), ObjectFactoryProtocol {
override fun create() = autoreleasepool { NSObject() }
})
}
fun MutablePairProtocol.swap() {
update(0, add = second)
update(1, sub = first)
update(0, add = second)
update(1, sub = second*2)
}
class Bar : Foo() {
override fun helloWithPrinter(printer: PrinterProtocol?) = memScoped {
printer!!.print("Hello from Kotlin".cstr.getPointer(memScope))
}
}
@Suppress("CONFLICTING_OBJC_OVERLOADS", "CONFLICTING_OVERLOADS")
class MutablePairImpl(first: Int, second: Int) : NSObject(), MutablePairProtocol {
private var elements = intArrayOf(first, second)
override fun first() = elements.first()
override fun second() = elements.last()
override fun update(index: Int, add: Int) {
elements[index] += add
}
override fun update(index: Int, sub: Int) {
elements[index] -= sub
}
constructor() : this(123, 321)
}
interface Zzz
fun testTypeOps() {
assertTrue(99.asAny() is NSNumber)
assertTrue(null.asAny() is NSNumber?)
assertFalse(null.asAny() is NSNumber)
assertFalse("".asAny() is NSNumber)
assertTrue("bar".asAny() is NSString)
assertTrue(Foo.asAny() is FooMeta)
assertFalse(Foo.asAny() is Zzz)
assertTrue(Foo.asAny() is NSObjectMeta)
assertTrue(Foo.asAny() is NSObject)
assertFalse(Foo.asAny() is Foo)
assertTrue(NSString.asAny() is NSCopyingProtocolMeta)
assertFalse(NSString.asAny() is NSCopyingProtocol)
assertTrue(NSValue.asAny() is NSObjectProtocolMeta)
assertFalse(NSValue.asAny() is NSObjectProtocol) // Must be true, but not implemented properly yet.
assertFalse(Any() is ObjCClass)
assertFalse(Any() is ObjCClassOf<*>)
assertFalse(NSObject().asAny() is ObjCClass)
assertFalse(NSObject().asAny() is ObjCClassOf<*>)
assertTrue(NSObject.asAny() is ObjCClass)
assertTrue(NSObject.asAny() is ObjCClassOf<*>)
assertFalse(Any() is ObjCProtocol)
assertTrue(getPrinterProtocolRaw() is ObjCProtocol)
val printerProtocol = getPrinterProtocol()!!
assertTrue(printerProtocol.asAny() is ObjCProtocol)
assertEquals(3u, ("foo" as NSString).length())
assertEquals(4u, ((1..4).joinToString("") as NSString).length())
assertEquals(2u, (listOf(0, 1) as NSArray).count())
assertEquals(42L, (42 as NSNumber).longLongValue())
assertFails { "bar" as NSNumber }
assertFails { 42 as NSArray }
assertFails { listOf(1) as NSString }
assertFails { NSObject() as Bar }
assertFails { NSObject() as NSValue }
MutablePairImpl(1, 2).asAny() as MutablePairProtocol
assertFails { MutablePairImpl(1, 2).asAny() as Foo }
}
private lateinit var retainedMustNotBeDeallocated: MustNotBeDeallocated
fun testCustomRetain() {
fun test() {
useCustomRetainMethods(object : Foo(), CustomRetainMethodsProtocol {
override fun returnRetained(obj: Any?) = obj
override fun consume(obj: Any?) {}
override fun consumeSelf() {}
override fun returnRetainedBlock(block: (() -> Unit)?) = block
})
CustomRetainMethodsImpl().let {
it.returnRetained(Any())
retainedMustNotBeDeallocated = MustNotBeDeallocated() // Retain to detect possible over-release.
it.consume(retainedMustNotBeDeallocated)
it.consumeSelf()
it.returnRetainedBlock({})!!()
}
}
autoreleasepool {
test()
kotlin.native.runtime.GC.collect()
}
assertFalse(unexpectedDeallocation)
}
private const val TestExportObjCClass1Name = "TestExportObjCClass"
@ExportObjCClass(TestExportObjCClass1Name) class TestExportObjCClass1 : NSObject()
@ExportObjCClass class TestExportObjCClass2 : NSObject()
const val TestExportObjCClass34Name = "TestExportObjCClass34"
@ExportObjCClass(TestExportObjCClass34Name) class TestExportObjCClass3 : NSObject()
@ExportObjCClass(TestExportObjCClass34Name) class TestExportObjCClass4 : NSObject()
fun testExportObjCClass() {
assertEquals(TestExportObjCClass1Name, TestExportObjCClass1().objCClassName)
assertEquals("TestExportObjCClass2", TestExportObjCClass2().objCClassName)
assertTrue((TestExportObjCClass3().objCClassName == TestExportObjCClass34Name)
xor (TestExportObjCClass4().objCClassName == TestExportObjCClass34Name))
}
fun testLocalizedStrings() {
val key = "screen_main_plural_string"
val localizedString = NSBundle.mainBundle.localizedStringForKey(key, value = "", table = "Localizable")
val string = NSString.localizedStringWithFormat(localizedString, 5)
assertEquals("Plural: 5 apples", string)
}
private val Any.objCClassName: String
get() = object_getClassName(this)!!.toKString()
fun Any?.asAny(): Any? = this