/* * Copyright 2010-2020 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. */ import Foundation import Kt // -------- Tests -------- func testVals() throws { print("Values from Swift") let dbl = ValuesKt.dbl let flt = ValuesKt.flt let int = ValuesKt.integer let long = ValuesKt.longInt print(dbl) print(flt) print(int) print(long) try assertEquals(actual: dbl, expected: 3.14 as Double, "Double value isn't equal.") try assertEquals(actual: flt, expected: 2.73 as Float, "Float value isn't equal.") try assertEquals(actual: int, expected: 42) try assertEquals(actual: long, expected: 1984) } func testVars() throws { print("Variables from Swift") var intVar = ValuesKt.intVar var strVar = ValuesKt.str var strAsId = ValuesKt.strAsAny print(intVar) print(strVar) print(strAsId) try assertEquals(actual: intVar, expected: 451) try assertEquals(actual: strVar, expected: "Kotlin String") try assertEquals(actual: strAsId as! String, expected: "Kotlin String as Any") strAsId = "Swift str" ValuesKt.strAsAny = strAsId print(ValuesKt.strAsAny) try assertEquals(actual: ValuesKt.strAsAny as! String, expected: strAsId as! String) // property with custom getter/setter backed by the Kotlin's var var intProp : Int32 { get { return ValuesKt.intVar * 2 } set(value) { ValuesKt.intVar = 123 + value } } intProp += 10 print(intProp) print(ValuesKt.intVar) try assertEquals(actual: ValuesKt.intVar * 2, expected: intProp, "Property backed by var") } func testDoubles() throws { print("Doubles in Swift") let minDouble = ValuesKt.minDoubleVal as! Double let maxDouble = ValuesKt.maxDoubleVal as! NSNumber print(minDouble) print(maxDouble) print(ValuesKt.nanDoubleVal) print(ValuesKt.nanFloatVal) print(ValuesKt.infDoubleVal) print(ValuesKt.infFloatVal) try assertEquals(actual: minDouble, expected: Double.leastNonzeroMagnitude, "Min double") try assertEquals(actual: maxDouble, expected: Double.greatestFiniteMagnitude as NSNumber, "Max double") try assertTrue(ValuesKt.nanDoubleVal.isNaN, "NaN double") try assertTrue(ValuesKt.nanFloatVal.isNaN, "NaN float") try assertEquals(actual: ValuesKt.infDoubleVal, expected: Double.infinity, "Inf double") try assertEquals(actual: ValuesKt.infFloatVal, expected: -Float.infinity, "-Inf float") } func testNumbers() throws { try assertEquals(actual: KotlinBoolean(value: true).boolValue, expected: true) try assertEquals(actual: KotlinBoolean(value: false).intValue, expected: 0) try assertEquals(actual: KotlinBoolean(value: true), expected: true) try assertFalse(KotlinBoolean(value: false) as! Bool) try assertEquals(actual: KotlinByte(value: -1).int8Value, expected: -1) try assertEquals(actual: KotlinByte(value: -1).int32Value, expected: -1) try assertEquals(actual: KotlinByte(value: -1).doubleValue, expected: -1.0) try assertEquals(actual: KotlinByte(value: -1), expected: NSNumber(value: Int64(-1))) try assertFalse(KotlinByte(value: -1) == NSNumber(value: -1.5)) try assertEquals(actual: KotlinByte(value: -1), expected: -1) try assertTrue(KotlinByte(value: -1) == -1) try assertFalse(KotlinByte(value: -1) == 1) try assertEquals(actual: KotlinByte(value: -1) as! Int32, expected: -1) try assertEquals(actual: KotlinShort(value: 111).int16Value, expected: 111) try assertEquals(actual: KotlinShort(value: -15) as! Int16, expected: -15) try assertEquals(actual: KotlinShort(value: 47), expected: 47) try assertEquals(actual: KotlinInt(value: 99).int32Value, expected: 99) try assertEquals(actual: KotlinInt(value: -1) as! Int32, expected: -1) try assertEquals(actual: KotlinInt(value: 72), expected: 72) try assertEquals(actual: KotlinLong(value: 65).int64Value, expected: 65) try assertEquals(actual: KotlinLong(value: 10000000000) as! Int64, expected: 10000000000) try assertEquals(actual: KotlinLong(value: 8), expected: 8) try assertEquals(actual: KotlinUByte(value: 17).uint8Value, expected: 17) try assertEquals(actual: KotlinUByte(value: 42) as! UInt8, expected: 42) try assertEquals(actual: 88, expected: KotlinUByte(value: 88)) try assertEquals(actual: KotlinUShort(value: 40000).uint16Value, expected: 40000) try assertEquals(actual: KotlinUShort(value: 1) as! UInt16, expected: UInt16(1)) try assertEquals(actual: KotlinUShort(value: 65000), expected: 65000) try assertEquals(actual: KotlinUInt(value: 3).uint32Value, expected: 3) try assertEquals(actual: KotlinUInt(value: UInt32.max) as! UInt32, expected: UInt32.max) try assertEquals(actual: KotlinUInt(value: 2), expected: 2) try assertEquals(actual: KotlinULong(value: 55).uint64Value, expected: 55) try assertEquals(actual: KotlinULong(value: 0) as! UInt64, expected: 0) try assertEquals(actual: KotlinULong(value: 7), expected: 7) try assertEquals(actual: KotlinFloat(value: 1.0).floatValue, expected: 1.0) try assertEquals(actual: KotlinFloat(value: 22.0) as! Float, expected: 22) try assertEquals(actual: KotlinFloat(value: 41.0), expected: 41) try assertEquals(actual: KotlinFloat(value: -5.5), expected: -5.5) try assertEquals(actual: KotlinDouble(value: 0.5).doubleValue, expected: 0.5) try assertEquals(actual: KotlinDouble(value: 45.0) as! Double, expected: 45) try assertEquals(actual: KotlinDouble(value: 89.0), expected: 89) try assertEquals(actual: KotlinDouble(value: -3.7), expected: -3.7) ValuesKt.ensureEqualBooleans(actual: KotlinBoolean(value: true), expected: true) ValuesKt.ensureEqualBooleans(actual: false, expected: false) ValuesKt.ensureEqualBooleansAsAny(actual: true, expected: true) ValuesKt.ensureEqualBooleansAsAny(actual: false, expected: false) ValuesKt.ensureEqualBytes(actual: KotlinByte(value: 42), expected: 42) ValuesKt.ensureEqualBytes(actual: -11, expected: -11) ValuesKt.ensureEqualShorts(actual: KotlinShort(value: 256), expected: 256) ValuesKt.ensureEqualShorts(actual: -1, expected: -1) ValuesKt.ensureEqualInts(actual: KotlinInt(value: 100000), expected: 100000) ValuesKt.ensureEqualInts(actual: -7, expected: -7) ValuesKt.ensureEqualLongs(actual: KotlinLong(value: Int64.max), expected: Int64.max) ValuesKt.ensureEqualLongs(actual: 17, expected: 17) ValuesKt.ensureEqualUBytes(actual: KotlinUByte(value: 6), expected: 6) ValuesKt.ensureEqualUBytes(actual: 255, expected: 255) ValuesKt.ensureEqualUShorts(actual: KotlinUShort(value: 300), expected: 300) ValuesKt.ensureEqualUShorts(actual: 65535, expected: UInt16.max) ValuesKt.ensureEqualUInts(actual: KotlinUInt(value: 70000), expected: 70000) ValuesKt.ensureEqualUInts(actual: 48, expected: 48) ValuesKt.ensureEqualULongs(actual: KotlinULong(value: UInt64.max), expected: UInt64.max) ValuesKt.ensureEqualULongs(actual: 39, expected: 39) ValuesKt.ensureEqualFloats(actual: KotlinFloat(value: 36.6), expected: 36.6) ValuesKt.ensureEqualFloats(actual: 49.5, expected: 49.5) ValuesKt.ensureEqualFloats(actual: 18, expected: 18.0) ValuesKt.ensureEqualDoubles(actual: KotlinDouble(value: 12.34), expected: 12.34) ValuesKt.ensureEqualDoubles(actual: 56.78, expected: 56.78) ValuesKt.ensureEqualDoubles(actual: 3, expected: 3) func checkBox(_ value: T, _ boxFunction: (T) -> B?) throws { let box = boxFunction(value)! try assertEquals(actual: box as! T, expected: value) print(type(of: box)) print(B.self) try assertTrue(box.isKind(of: B.self)) } try checkBox(true, ValuesKt.box) try checkBox(Int8(-1), ValuesKt.box) try checkBox(Int16(-2), ValuesKt.box) try checkBox(Int32(-3), ValuesKt.box) try checkBox(Int64(-4), ValuesKt.box) try checkBox(UInt8(5), ValuesKt.box) try checkBox(UInt16(6), ValuesKt.box) try checkBox(UInt32(7), ValuesKt.box) try checkBox(UInt64(8), ValuesKt.box) try checkBox(Float(8.7), ValuesKt.box) try checkBox(Double(9.4), ValuesKt.box) } func testLists() throws { let numbersList = ValuesKt.numbersList let gold = [1, 2, 13] for i in 0.. Void { throw E() } func nothing() throws -> Void { throw E() } func any() throws -> Any { throw E() } func block() throws -> () -> KotlinInt { throw E() } } class TestThrowingConstructorRelease : Throwing { static var deinitialized = false deinit { TestThrowingConstructorRelease.deinitialized = true } } class SwiftNotThrowing : SwiftOverridableMethodsWithThrows { func unit() throws -> Void { } func nothing() throws -> Void { throw SwiftThrowing.E() } func any() throws -> Any { return 42 as Int32 } func block() throws -> () -> KotlinInt { return { 17 } } } class SwiftUnitCaller : MethodsWithThrowsUnitCaller { func call(methods: MethodsWithThrows) throws -> Void { try methods.unit() } } class SwiftThrowingWithBridge : ThrowsWithBridge { override func plusOne(x: Int32) throws -> KotlinInt { throw SwiftThrowing.E() } } class SwiftNotThrowingWithBridge : ThrowsWithBridge { override func plusOne(x: Int32) throws -> KotlinInt { return KotlinInt(value: x + 1) } } private func testThrowing(file: String = #file, line: Int = #line, _ block: () throws -> Void) throws { try assertFailsWithKotlin(MyException.self, file: file, line: line, block: block) } func testExceptions() throws { try testThrowing { try ValuesKt.throwException(error: false) } do { try ValuesKt.throwException(error: true) } catch let error as NSError { try assertTrue(error.kotlinException is MyError) } #if !NOOP_GC try assertFalse(TestThrowingConstructorRelease.deinitialized) try testThrowing { try TestThrowingConstructorRelease(doThrow: true) } ValuesKt.gc() try assertTrue(TestThrowingConstructorRelease.deinitialized) #endif try testThrowing { try Throwing(doThrow: true) } let throwing = try Throwing(doThrow: false) try testThrowing { try throwing.unit() } try testThrowing { try throwing.nothing() } try testThrowing { try throwing.nothingN() } try testThrowing { try throwing.any() } try testThrowing { try throwing.anyN() } try testThrowing { try throwing.block()() } try testThrowing { try throwing.blockN() } try testThrowing { try throwing.pointer() } try testThrowing { try throwing.pointerN() } try testThrowing { try throwing.int() } try testThrowing { try throwing.longN() } try testThrowing { try throwing.double() } let notThrowing = try NotThrowing() try notThrowing.unit() try assertEquals(actual: notThrowing.nothingN(), expected: nil) try assertTrue(notThrowing.any() is KotlinBase) try assertTrue(notThrowing.anyN() is KotlinBase) try assertEquals(actual: notThrowing.block()(), expected: 42) try assertTrue(notThrowing.blockN() == nil) try assertEquals(actual: Int(bitPattern: notThrowing.pointer()), expected: 1) try assertEquals(actual: notThrowing.pointerN(), expected: nil) try assertEquals(actual: notThrowing.int(), expected: 42) try assertEquals(actual: notThrowing.longN(), expected: nil) try assertEquals(actual: notThrowing.double(), expected: 3.14) try ValuesKt.testSwiftThrowing(methods: SwiftThrowing()) try ValuesKt.testSwiftNotThrowing(methods: SwiftNotThrowing()) do { try ValuesKt.callUnit(methods: SwiftThrowing()) } catch let e as SwiftThrowing.E { // Ok. } try ValuesKt.callUnitCaller(caller: SwiftUnitCaller(), methods: throwing) try ValuesKt.testSwiftThrowing(test: SwiftThrowingWithBridge(), flag: false) try ValuesKt.testSwiftThrowing(test: SwiftThrowingWithBridge(), flag: true) try ValuesKt.testSwiftNotThrowing(test: SwiftNotThrowingWithBridge()) } func testFuncType() throws { let s = "str" let fFunc: () -> String = { return s } try assertEquals(actual: ValuesKt.funArgument(foo: fFunc), expected: s, "Using function type arguments failed") } func testGenericsFoo() throws { let fun = { (i: Int) -> String in return "S \(i)" } // wrap lambda to workaround issue with type conversion inability: // (Int) -> String can't be cast to (Any?) -> Any? let wrapper = { (t: Any?) -> Any? in return fun(t as! Int) } let res = ValuesKt.genericFoo(t: 42, foo: wrapper) try assertEquals(actual: res as! String, expected: "S 42") } func testVararg() throws { #if NO_GENERICS let ktArray = KotlinArray(size: 3, init: { (_) -> NSNumber in return 42 }) #else let ktArray = KotlinArray(size: 3, init: { (_) -> NSNumber in return 42 }) #endif let arr: [Int] = ValuesKt.varargToList(args: ktArray) as! [Int] try assertEquals(actual: arr, expected: [42, 42, 42]) } func testStrExtFun() throws { try assertEquals(actual: ValuesKt.subExt("String", i: 2), expected: "r") try assertEquals(actual: ValuesKt.subExt("A", i: 2), expected: "nothing") } func testAnyToString() throws { try assertEquals(actual: ValuesKt.toString(nil), expected: "null") try assertEquals(actual: ValuesKt.toString(42), expected: "42") } func testAnyPrint() throws { print("BEGIN") ValuesKt.print(nil) ValuesKt.print("Print") ValuesKt.print(123456789) ValuesKt.print(3.14) ValuesKt.print([3, 2, 1]) print("END") } func testCharExtensions() throws { try assertTrue(ValuesKt.isA(ValuesKt.boxChar(65))) try assertFalse(ValuesKt.isA(ValuesKt.boxChar(66))) } func testLambda() throws { try assertEquals(actual: ValuesKt.sumLambda(3, 4), expected: 7) var blockRuns = 0 try assertTrue(ValuesKt.runUnitBlock { blockRuns += 1 }) try assertEquals(actual: blockRuns, expected: 1) let unitBlock: () -> Void = ValuesKt.asUnitBlock { blockRuns += 1 return 42 } try assertTrue(unitBlock() == Void()) try assertEquals(actual: blockRuns, expected: 2) let nothingBlock: () -> Void = { blockRuns += 1 } ValuesKt.runNothingBlock(block: nothingBlock) try assertEquals(actual: blockRuns, expected: 3) try assertTrue(ValuesKt.getNullBlock() == nil) try assertTrue(ValuesKt.isBlockNull(block: nil)) // Test dynamic conversion: let intBlocks = IntBlocksImpl() try assertEquals(actual: intBlocks.getPlusOneBlock()(1), expected: 2) try assertEquals(actual: intBlocks.callBlock(argument: 2) { KotlinInt(value: $0.int32Value + 2) }, expected: 4) // Test round trip with dynamic conversion: let coercedUnitBlock: () -> KotlinUnit = UnitBlockCoercionImpl().coerce { blockRuns += 1 } try assertTrue(coercedUnitBlock() === KotlinUnit()) try assertEquals(actual: blockRuns, expected: 4) let uncoercedUnitBlock: () -> Void = UnitBlockCoercionImpl().uncoerce { blockRuns += 1 return KotlinUnit() } try assertTrue(uncoercedUnitBlock() == Void()) try assertEquals(actual: blockRuns, expected: 5) let blockMustBeFunction0: @convention(block) () -> AnyObject? = { return nil } try assertTrue(ValuesKt.isFunction(obj: blockMustBeFunction0)) try assertTrue(ValuesKt.isFunction0(obj: blockMustBeFunction0)) try assertFalse(ValuesKt.isFunction(obj: NSObject())) try assertFalse(ValuesKt.isFunction0(obj: NSObject())) // Test no function class for dynamic conversion: let blockAsMissingFunction: @convention(block) (AnyObject?, AnyObject?, AnyObject?, AnyObject?, AnyObject?) -> AnyObject? = { return $0 ?? $1 ?? $2 ?? $3 ?? $4 } try assertTrue(ValuesKt.isFunction(obj: blockAsMissingFunction)) try assertFalse(ValuesKt.isFunction0(obj: blockAsMissingFunction)) } // -------- Tests for classes and interfaces ------- class ValIEmptyExt : I { func iFun() -> String { return "ValIEmptyExt::iFun" } } class ValIExt : I { func iFun() -> String { return "ValIExt::iFun" } } func testInterfaceExtension() throws { try assertEquals(actual: ValIEmptyExt().iFun(), expected: "ValIEmptyExt::iFun") try assertEquals(actual: ValIExt().iFun(), expected: "ValIExt::iFun") } func testClassInstances() throws { try assertEquals(actual: OpenClassI().iFun(), expected: "OpenClassI::iFun") try assertEquals(actual: DefaultInterfaceExt().iFun(), expected: "I::iFun") try assertEquals(actual: FinalClassExtOpen().iFun(), expected: "FinalClassExtOpen::iFun") try assertEquals(actual: MultiExtClass().iFun(), expected: "PI::iFun") try assertEquals(actual: MultiExtClass().piFun() as! Int, expected: 42) try assertEquals(actual: ConstrClass(i: 1, s: "str", a: "Any").iFun(), expected: "OpenClassI::iFun") try assertEquals(actual: ExtConstrClass(i: 123).iFun(), expected: "ExtConstrClass::iFun::123-String-AnyS") } func testEnum() throws { try assertEquals(actual: ValuesKt.passEnum(), expected: Enumeration.answer) try assertEquals(actual: ValuesKt.passEnum().enumValue, expected: 42) try assertEquals(actual: ValuesKt.passEnum().name, expected: "ANSWER") ValuesKt.receiveEnum(e: 1) } func testDataClass() throws { let f = "1" let s = "2" let t = "3" #if NO_GENERICS let tripleVal = TripleVals(first: f as NSString, second: s as NSString, third: t as NSString) #else let tripleVal = TripleVals(first: f as NSString, second: s as NSString, third: t as NSString) #endif try assertEquals(actual: tripleVal.first as! String, expected: f, "Data class' value") print(tripleVal) try assertEquals(actual: String(describing: tripleVal), expected: "TripleVals(first=\(f), second=\(s), third=\(t))") #if NO_GENERICS let tripleVar = TripleVars(first: f as NSString, second: s as NSString, third: t as NSString) #else let tripleVar = TripleVars(first: f as NSString, second: s as NSString, third: t as NSString) #endif try assertEquals(actual: tripleVar.first as! String, expected: f, "Data class' value") print(tripleVar) try assertEquals(actual: String(describing: tripleVar), expected: "[\(f), \(s), \(t)]") tripleVar.first = t as NSString tripleVar.second = f as NSString tripleVar.third = s as NSString try assertEquals(actual: String(describing: tripleVar), expected: "[\(t), \(f), \(s)]") } func testCompanionObj() throws { try assertEquals(actual: WithCompanionAndObject.Companion().str, expected: "String") try assertEquals(actual: ValuesKt.getCompanionObject().str, expected: "String") let namedFromCompanion = ValuesKt.getCompanionObject().named let named = ValuesKt.getNamedObject() try assertTrue(named === namedFromCompanion, "Should be the same Named object") try assertEquals(actual: ValuesKt.getNamedObjectInterface().iFun(), expected: named.iFun(), "Named object's method") } func testInlineClasses() throws { let ic1: Int32 = 42 let ic1N = ValuesKt.box(ic1: 17) let ic2 = "foo" let ic2N = "bar" #if NO_GENERICS let ic3 = TripleVals(first: 1, second: 2, third: 3) #else let ic3 = TripleVals(first: 1, second: 2, third: 3) #endif let ic3N = ValuesKt.box(ic3: nil) try assertEquals( actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: ic1N, ic2: ic2, ic2N: ic2N, ic3: ic3, ic3N: ic3N), expected: "42 17 foo bar TripleVals(first=1, second=2, third=3) null" ) try assertEquals( actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: nil, ic2: ic2, ic2N: nil, ic3: nil, ic3N: nil), expected: "42 null foo null null null" ) try assertEquals(actual: ValuesKt.getValue1(ic1), expected: 42) try assertEquals(actual: ValuesKt.getValueOrNull1(ic1N) as! Int, expected: 17) try assertEquals(actual: ValuesKt.getValue2(ic2), expected: "foo") try assertEquals(actual: ValuesKt.getValueOrNull2(ic2N), expected: "bar") try assertEquals(actual: ValuesKt.getValue3(ic3), expected: ic3) try assertEquals(actual: ValuesKt.getValueOrNull3(ic3N), expected: nil) } class TestSharedIImpl : NSObject, I { func iFun() -> String { return "TestSharedIImpl::iFun" } } func testShared() throws { if !ValuesKt.isFreezingEnabled() { return; } func assertFrozen(_ obj: AnyObject) throws { try assertTrue(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))") } func assertNotFrozen(_ obj: AnyObject) throws { try assertFalse(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))") } try assertFrozen(NSObject()) try assertFrozen(TestSharedIImpl()) try assertFrozen(ValuesKt.kotlinLambda(block: { return $0 }) as AnyObject) try assertNotFrozen(FinalClassExtOpen()) } class PureSwiftClass { } struct PureSwiftStruct { var x: Int } class PureSwiftKotlinInterfaceImpl : I { func iFun() -> String { return "pure" } } func testPureSwiftClasses() throws { let pureSwiftClass = PureSwiftClass() try assertTrue(ValuesKt.same(pureSwiftClass) as? AnyObject === pureSwiftClass) try assertEquals(actual: 123, expected: (ValuesKt.same(PureSwiftStruct(x: 123)) as? PureSwiftStruct)?.x) try assertEquals(actual: "pure", expected: ValuesKt.iFunExt(PureSwiftKotlinInterfaceImpl())) } func testNames() throws { try assertEquals(actual: ValuesKt.PROPERTY_NAME_MUST_NOT_BE_ALTERED_BY_SWIFT, expected: 111) try assertEquals(actual: Deeply.NestedType().thirtyTwo, expected: 32) #if NO_GENERICS try assertEquals(actual: WithGenericDeeply.NestedType().thirtyThree, expected: 33) #else try assertEquals(actual: WithGenericDeeplyNestedType().thirtyThree, expected: 33) #endif try assertEquals(actual: CKeywords(float: 1.0, enum : 42, goto: true).goto_, expected: true) try assertEquals(actual: TypeOuter.Type_().thirtyFour, expected: 34) try assertTrue(String(describing: DeeplyNestedIType.self).hasSuffix("DeeplyNestedIType")) } class Base123 : Base23, ExtendedBase1 { override func same(value: KotlinInt?) -> KotlinInt { return value! } } func testSwiftOverride() throws { let impl = Base123() try assertEquals(actual: ValuesKt.call(base1: impl, value: 1), expected: 1) try assertEquals(actual: ValuesKt.call(extendedBase1: impl, value: 2), expected: 2) try assertEquals(actual: ValuesKt.call(base2: impl, value: 3), expected: 3) try assertEquals(actual: ValuesKt.call(base3: impl, value: 4), expected: 4) try assertEquals(actual: ValuesKt.call(base23: impl, value: 5), expected: 5) } class TransformIntToLongCallingSuper : TransformIntToLong { override func map(value: KotlinInt) -> KotlinLong { return super.map(value: value) } } func testKotlinOverride() throws { #if NO_GENERICS try assertEquals(actual: TransformInheritingDefault().map(value: 1) as! Int32, expected: 1) #else try assertEquals(actual: TransformInheritingDefault().map(value: 1) as! Int32, expected: 1) #endif try assertEquals(actual: TransformIntToDecimalString().map(value: 2), expected: "2") try assertEquals(actual: TransformIntToDecimalString().map(intValue: 3), expected: "3") try assertEquals(actual: ValuesKt.createTransformDecimalStringToInt().map(value: "4") as! Int32, expected: 4) try assertEquals(actual: TransformIntToLongCallingSuper().map(value: 5), expected: 5) } // See https://github.com/JetBrains/kotlin-native/issues/2945 func testGH2945() throws { let gh2945 = GH2945(errno: 1) try assertEquals(actual: 1, expected: gh2945.errno) gh2945.errno = 2 try assertEquals(actual: 2, expected: gh2945.errno) try assertEquals(actual: 7, expected: gh2945.testErrnoInSelector(p: 3, errno: 4)) } // See https://github.com/JetBrains/kotlin-native/issues/2830 func testGH2830() throws { try assertTrue(GH2830().getI() is GH2830I) } // See https://github.com/JetBrains/kotlin-native/issues/2959 func testGH2959() throws { try assertEquals(actual: GH2959().getI(id: 2959)[0].id, expected: 2959) } func testKClass() throws { let test = TestKClass() let testKClass = test.getKotlinClass(clazz: TestKClass.self)! try assertTrue(test.isTestKClass(kClass: testKClass)) try assertFalse(test.isI(kClass: testKClass)) try assertEquals(actual: testKClass.simpleName, expected: "TestKClass") let iKClass = test.getKotlinClass(protocol: TestKClassI.self)! try assertFalse(test.isTestKClass(kClass: iKClass)) try assertTrue(test.isI(kClass: iKClass)) try assertEquals(actual: iKClass.simpleName, expected: "I") try assertTrue(test.getKotlinClass(clazz: NSObject.self) == nil) try assertTrue(test.getKotlinClass(clazz: PureSwiftClass.self) == nil) try assertTrue(test.getKotlinClass(clazz: PureSwiftKotlinInterfaceImpl.self) == nil) try assertTrue(test.getKotlinClass(clazz: Base123.self) == nil) try assertTrue(test.getKotlinClass(protocol: NSObjectProtocol.self) == nil) } open class TestSR10177WorkaroundBase {} class TestSR10177WorkaroundDerived : TestSR10177WorkaroundBase {} // See https://bugs.swift.org/browse/SR-10177 and https://bugs.swift.org/browse/SR-10217 func testSR10177Workaround() throws { let test = TestSR10177WorkaroundDerived() try assertTrue(String(describing: test).contains("TestSR10177WorkaroundDerived")) } func testClashes() throws { let test = TestClashesImpl() let test1: TestClashes1 = test let test2: TestClashes2 = test try assertEquals(actual: 1, expected: test1.clashingProperty) #if !DISABLE_MEMBER_NAME_MANGLING && !DISABLE_INTERFACE_METHOD_NAME_MANGLING try assertEquals(actual: 1, expected: test2.clashingProperty_ as! Int32) try assertEquals(actual: 2, expected: test2.clashingProperty__ as! Int32) #endif } func testInvalidIdentifiers() throws { let test = TestInvalidIdentifiers() try assertEquals(actual: 42, expected: test.aSdSd(S1: 13, _2: 14, _3: 15)) try assertEquals(actual: TestInvalidIdentifiers.E._4s.value, expected: 4) try assertEquals(actual: TestInvalidIdentifiers.E._5s.value, expected: 5) try assertEquals(actual: TestInvalidIdentifiers.E.__.value, expected: 6) try assertEquals(actual: TestInvalidIdentifiers.E.___.value, expected: 7) try assertEquals(actual: TestInvalidIdentifiers.CompanionS()._42, expected: 42) #if !DISABLE_MEMBER_NAME_MANGLING try assertEquals(actual: Set([test.__, test.___]), expected: Set(["_".utf16.first, "_".utf16.first])) #endif } class ImplementingHiddenSubclass : TestDeprecation.ImplementingHidden { override func effectivelyHidden() -> Int32 { return -2 } } func testDeprecation() throws { let test = TestDeprecation() try assertEquals(actual: test.openNormal(), expected: 1) let testHiddenOverride: TestDeprecation = TestDeprecation.HiddenOverride() try assertEquals(actual: testHiddenOverride.openNormal(), expected: 2) let testErrorOverride: TestDeprecation = TestDeprecation.ErrorOverride() try assertEquals(actual: testErrorOverride.openNormal(), expected: 3) let testWarningOverride: TestDeprecation = TestDeprecation.WarningOverride() try assertEquals(actual: testWarningOverride.openNormal(), expected: 4) try assertEquals(actual: test.callEffectivelyHidden(obj: ImplementingHiddenSubclass()), expected: -2) } func setAssociatedObject(object: AnyObject, value: AnyObject) { objc_setAssociatedObject( object, UnsafeRawPointer(bitPattern: 1)!, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN ) } func testWeakRefs() throws { #if !NOOP_GC try testWeakRefs0(frozen: false) try testWeakRefs0(frozen: true) #endif } func testWeakRefs0(frozen: Bool) throws { func getObj(test: TestWeakRefs) -> AnyObject { return autoreleasepool { test.getObj() as AnyObject } } func test1() throws { var test = TestWeakRefs(frozen: frozen) var obj: AnyObject? = getObj(test: test) weak var ref = getObj(test: test) ValuesKt.gc() try assertTrue(ref === getObj(test: test)) // There are both Kotlin and Swift references to the object. obj = nil ValuesKt.gc() try assertTrue(ref === getObj(test: test)) // There are only Kotlin references to the object. test.clearObj() ValuesKt.gc() try assertTrue(ref === nil) } func test2() throws { var test = TestWeakRefs(frozen: frozen) var obj: AnyObject? = getObj(test: test) weak var ref = getObj(test: test) ValuesKt.gc() try assertTrue(ref === obj!) // There are both Kotlin and Swift references to the object. test.clearObj() ValuesKt.gc() try assertTrue(ref === obj!) // There are only Swift references to the object. obj = nil ValuesKt.gc() try assertTrue(ref === nil) } func test3() throws { class Holder { static weak var ref: AnyObject? = nil static var deinitialized = false deinit { // Access weak ref to Kotlin object during its counterpart dealloc: try! assertTrue(Holder.ref === nil) Holder.deinitialized = true } } Holder.deinitialized = false Holder.ref = nil var test = TestWeakRefs(frozen: frozen) Holder.ref = getObj(test: test) // Prepare Holder() to get deinitialized along with getObj(test: test): setAssociatedObject( object: getObj(test: test), value: Holder() ) try assertFalse(Holder.ref === nil) try assertFalse(Holder.deinitialized) test.clearObj() ValuesKt.gc() try assertTrue(Holder.ref === nil) try assertTrue(Holder.deinitialized) } func test4() throws { class Holder { static weak var ref1: AnyObject? = nil static weak var ref2: AnyObject? = nil static var deinitialized: Int = 0 deinit { // Access weak ref to Kotlin object during its counterpart dealloc: try! assertTrue(Holder.ref1 === nil) try! assertTrue(Holder.ref2 === nil) Holder.deinitialized += 1 } } Holder.deinitialized = 0 Holder.ref1 = nil Holder.ref2 = nil var test = TestWeakRefs(frozen: frozen) autoreleasepool { let cycle = test.createCycle() let obj1 = cycle[0] as AnyObject let obj2 = cycle[1] as AnyObject // Prepare Holders to get deinitialized along with obj1 and obj2: setAssociatedObject(object: obj1, value: Holder()) setAssociatedObject(object: obj2, value: Holder()) Holder.ref1 = obj1 Holder.ref2 = obj2 } ValuesKt.gc() try assertTrue(Holder.ref1 === nil) try assertTrue(Holder.ref2 === nil) try assertEquals(actual: Holder.deinitialized, expected: 2) } try test1() try test2() try test3() try test4() } var falseFlag = false class TestSharedRefs { private func testLambdaSimple() throws { func getClosure() -> (() -> Void) { let lambda = autoreleasepool { SharedRefs().createLambda() } return { if falseFlag { lambda() } } } DispatchQueue.global().async(execute: getClosure()) } private static func launchInNewThread(initializeKotlinRuntime: Bool, block: @escaping () -> Void) -> pthread_t { class Closure { static var currentBlock: (() -> Void)? = nil static var initializeKotlinRuntime: Bool = false } Closure.currentBlock = block Closure.initializeKotlinRuntime = initializeKotlinRuntime var thread: pthread_t? = nil let createCode = pthread_create(&thread, nil, { _ in if Closure.initializeKotlinRuntime { let ignore = SharedRefs() // Ensures that Kotlin runtime gets initialized. } // Take the block from Closure to avoid races when block() execution triggers // calling launchInNewThread on another thread (e.g. on the finalizer thread). let block = Closure.currentBlock! Closure.currentBlock = nil block() return nil }, nil) try! assertEquals(actual: createCode, expected: 0) return thread! } private static func joinThread(thread: pthread_t) { let joinCode = pthread_join(thread, nil) try! assertEquals(actual: joinCode, expected: 0) } private static func runInNewThread(initializeKotlinRuntime: Bool, block: @escaping () -> Void) { let thread = launchInNewThread(initializeKotlinRuntime: initializeKotlinRuntime, block: block) joinThread(thread: thread) } private func runInNewThread(initializeKotlinRuntime: Bool, block: @escaping () -> Void) { return TestSharedRefs.runInNewThread(initializeKotlinRuntime: initializeKotlinRuntime, block: block) } private func testObjectPartialRelease() { let object = autoreleasepool { SharedRefs().createRegularObject() } var objectVar: AnyObject? = object runInNewThread(initializeKotlinRuntime: true) { objectVar = nil } } private func testRunRefCount( run: (@escaping () -> Void) -> Void, createObject: @escaping (SharedRefs) -> T ) throws { let refs = SharedRefs() var objectVar1: T? = autoreleasepool { createObject(refs) } var objectVar2: T? = nil try assertTrue(refs.hasAliveObjects()) run { objectVar2 = objectVar1! objectVar1 = nil } try assertTrue(refs.hasAliveObjects()) run { objectVar2 = nil } try assertFalse(refs.hasAliveObjects()) } private func testBackgroundRefCount(createObject: @escaping (SharedRefs) -> T) throws { try testRunRefCount( run: { runInNewThread(initializeKotlinRuntime: false, block: $0) }, createObject: createObject ) try testRunRefCount( run: { runInNewThread(initializeKotlinRuntime: true, block: $0) }, createObject: createObject ) } private func testReferenceOutlivesThread(releaseWithKotlinRuntime: Bool) throws { var objectVar: AnyObject? = nil weak var objectWeakVar: AnyObject? = nil var collection: AnyObject? = nil runInNewThread(initializeKotlinRuntime: false) { autoreleasepool { let refs = SharedRefs() collection = refs.createCollection() let object = refs.createRegularObject() objectVar = object objectWeakVar = object try! assertTrue(objectWeakVar === object) } } runInNewThread(initializeKotlinRuntime: releaseWithKotlinRuntime) { objectVar = nil collection = nil ValuesKt.gc() try! assertTrue(objectWeakVar === nil) } } private func testMoreWorkBeforeThreadExit() throws { class Deinit { static var object1: AnyObject? = nil static var object2: AnyObject? = nil static weak var weakVar2: AnyObject? = nil deinit { TestSharedRefs.runInNewThread(initializeKotlinRuntime: false) { Deinit.object2 = nil } } } runInNewThread(initializeKotlinRuntime: false) { autoreleasepool { let object1 = SharedRefs.MutableData() Deinit.object1 = object1 setAssociatedObject(object: object1, value: Deinit()) let object2 = SharedRefs.MutableData() Deinit.object2 = object2 Deinit.weakVar2 = object2 } TestSharedRefs.runInNewThread(initializeKotlinRuntime: false) { Deinit.object1 = nil } } // This will free `object1` and release+dealloc its associated `Deinit` which nils `Deinit.object2` ValuesKt.gc() // This will free `object2`. ValuesKt.gc() try assertTrue(Deinit.weakVar2 === nil) } func testRememberNewObject(createObject: @escaping (SharedRefs) -> AnyObject) throws { class TestImpl : TestRememberNewObject { let cleanupFinishedSemaphore = DispatchSemaphore(value: 0) let threadWaitingForCleanupSemaphore = DispatchSemaphore(value: 0) var obj: AnyObject? = nil func getObject() -> Any { return obj! } func waitForCleanup() { threadWaitingForCleanupSemaphore.signal() cleanupFinishedSemaphore.wait() } } let test = TestImpl() let refs = SharedRefs() try assertFalse(refs.hasAliveObjects()) autoreleasepool { test.obj = createObject(refs) } try assertTrue(refs.hasAliveObjects()) let thread = TestSharedRefs.launchInNewThread(initializeKotlinRuntime: false) { ValuesKt.testRememberNewObject(test: test) } test.threadWaitingForCleanupSemaphore.wait() test.obj = nil ValuesKt.gc() try assertTrue(refs.hasAliveObjects()) test.cleanupFinishedSemaphore.signal() TestSharedRefs.joinThread(thread: thread) try assertFalse(refs.hasAliveObjects()) } // Based on https://youtrack.jetbrains.com/issue/KT-49497. func testKT49497() throws { var model: KT49497Model? = nil for i in 1...10 { model = KT49497Model() // Frozen and has a reference to itself, so becomes aggregating frozen container. ValuesKt.gc() // Just in case, to ensure there are no other references except `model`. runInNewThread(initializeKotlinRuntime: false) { // Thread has no runtime initialized, so this should enqueue release ref to the original thread: model = nil } ValuesKt.gc() // Process the enqueued release ref. } } func test() throws { try testLambdaSimple() try testObjectPartialRelease() #if !NOOP_GC try testBackgroundRefCount(createObject: { $0.createLambda() }) try testBackgroundRefCount(createObject: { $0.createRegularObject() }) try testBackgroundRefCount(createObject: { $0.createCollection() }) try testBackgroundRefCount(createObject: { $0.createFrozenLambda() }) try testBackgroundRefCount(createObject: { $0.createFrozenRegularObject() }) try testBackgroundRefCount(createObject: { $0.createFrozenCollection() }) try testReferenceOutlivesThread(releaseWithKotlinRuntime: false) try testReferenceOutlivesThread(releaseWithKotlinRuntime: true) try testMoreWorkBeforeThreadExit() try testRememberNewObject(createObject: { $0.createFrozenRegularObject() }) try testRememberNewObject(createObject: { $0.createFrozenCollection() }) #endif try testKT49497() usleep(300 * 1000) } } // See https://github.com/JetBrains/kotlin-native/issues/2931 func testGH2931() throws { for i in 0..<50000 { let holder = GH2931.Holder() let queue = DispatchQueue.global(qos: .background) let group = DispatchGroup() for j in 0..<2 { group.enter() queue.async { autoreleasepool { holder.data } group.leave() } } group.wait() } } class ClassForTypeCheckInheritor : ClassForTypeCheck { } func testClassTypeCheck() throws { try assertTrue(ValuesKt.testClassTypeCheck(x: ClassForTypeCheckInheritor())) } class ClassForInterfaceTypeCheckInheritor1 : InterfaceForTypeCheck { } class ClassForInterfaceTypeCheckInheritor2 : Base23, InterfaceForTypeCheck { } class ClassForInterfaceTypeCheckInheritor3 : Base23, ExtendedBase1, InterfaceForTypeCheck { } class ClassForInterfaceTypeCheck_Fail : Base23 { } func testInterfaceTypeCheck() throws { try assertTrue(ValuesKt.testInterfaceTypeCheck(x: ClassForInterfaceTypeCheckInheritor1())) try assertTrue(ValuesKt.testInterfaceTypeCheck(x: ClassForInterfaceTypeCheckInheritor2())) try assertTrue(ValuesKt.testInterfaceTypeCheck(x: ClassForInterfaceTypeCheckInheritor3())) try assertFalse(ValuesKt.testInterfaceTypeCheck(x: ClassForInterfaceTypeCheck_Fail())) } class AbstractInterface : AbstractInterfaceBase { override func bar() -> Int32 { return 42 } } // See https://github.com/JetBrains/kotlin-native/issues/3503 func testGH3503_1() throws { try assertEquals(actual: ValuesKt.testAbstractInterfaceCall(x: AbstractInterface()), expected: 42) } class AbstractInterface2 : AbstractInterfaceBase2 { } func testGH3503_2() throws { try assertEquals(actual: ValuesKt.testAbstractInterfaceCall2(x: AbstractInterface2()), expected: 42) } class AbstractInterface3 : AbstractInterfaceBase3 { override func foo() -> Int32 { return 42 } } func testGH3503_3() throws { try assertEquals(actual: ValuesKt.testAbstractInterfaceCall(x: AbstractInterface3()), expected: 42) } func testGH3525() throws { try assertEquals(actual: ValuesKt.gh3525BaseInitCount, expected: 0) try assertEquals(actual: ValuesKt.gh3525InitCount, expected: 0) let gh3525_1 = GH3525() try assertTrue(gh3525_1 is GH3525) try assertEquals(actual: ValuesKt.gh3525BaseInitCount, expected: 1) try assertEquals(actual: ValuesKt.gh3525InitCount, expected: 1) let gh3525_2 = GH3525() try assertTrue(gh3525_2 is GH3525) try assertEquals(actual: ValuesKt.gh3525BaseInitCount, expected: 1) try assertEquals(actual: ValuesKt.gh3525InitCount, expected: 1) try assertTrue(gh3525_1 === gh3525_2) } func testStringConversion() throws { func test1() throws { let test = TestStringConversion() let buffer = NSMutableString() buffer.append("a") test.str = buffer buffer.append("b") try assertEquals(actual: buffer, expected: "ab") // Ensure test.str isn't affected by buffer mutation: try assertEquals(actual: test.str as! NSString, expected: "a") } func ensureNoCopy(nsStr: NSString) throws { let test = TestStringConversion() test.str = nsStr let nsStr2 = test.str as! NSString // Ensure no additional NSString created on both conversions: try assertTrue(nsStr === nsStr2) } func test2() throws { var str = "a" str += NSObject().description try ensureNoCopy(nsStr: str as NSString) try ensureNoCopy(nsStr: NSString("abc")) try ensureNoCopy(nsStr: NSString(format: "%d%d%d", 3, 2, 1)) } try test1() try test2() } class GH3825SwiftImpl : GH3825 { class E : Error {} func call0(callback: () -> KotlinBoolean) throws { if callback().boolValue { throw E() } } func call1(doThrow: Bool, callback: () -> Void) throws { if doThrow { throw E() } callback() } func call2(callback: () -> Void, doThrow: Bool) throws { if doThrow { throw E() } callback() } } func testGH3825() throws { try ValuesKt.testGH3825(gh3825: GH3825SwiftImpl()) let test = GH3825KotlinImpl() var count = 0 try testThrowing { try test.call0 { true } } try test.call0 { count += 1 return false } try assertEquals(actual: count, expected: 1) try testThrowing { try test.call1(doThrow: true) { count += 1 } } try test.call1(doThrow: false) { count += 1 } try assertEquals(actual: count, expected: 2) try testThrowing { try test.call2(callback: { count += 1 }, doThrow: true)} try test.call2(callback: { count += 1 }, doThrow: false) try assertEquals(actual: count, expected: 3) } func testMapsExport() throws { // Original reproducer failed in different way for MutableMap (iOS 11) and Map (MacOS 10.14, iOS 13) try assertEquals(actual: ValuesKt.mapBoolean2String()[true], expected: "true") try assertEquals(actual: ValuesKt.mapByte2Short()[-1], expected: 2) try assertEquals(actual: ValuesKt.mapShort2Byte()[-2], expected: 1) try assertEquals(actual: ValuesKt.mapInt2Long()[-4], expected: 8) try assertEquals(actual: ValuesKt.mapLong2Long()[-8], expected: 8) try assertEquals(actual: ValuesKt.mapUByte2Boolean()[128], expected: true) try assertEquals(actual: ValuesKt.mapUShort2Byte()[0x8000], expected: 1) try assertEquals(actual: ValuesKt.mapUInt2Long()[0x7FFFFFFF], expected: 7) // the following samples require explicit cast to KotlinUInt or KotlinULong try assertEquals(actual: ValuesKt.mapUInt2Long()[KotlinUInt(-0x8000_0000)], expected: 8) _ = ValuesKt.mapULong2Long() as! [KotlinULong: KotlinLong] // test cast var u64: UInt64 = 0x8000_0000_0000_0000 try assertEquals(actual: ValuesKt.mapULong2Long()[KotlinULong(value: u64)], expected: 8) _ = ValuesKt.mapFloat2Float() as! [KotlinFloat: KotlinFloat] // test cast try assertEquals(actual: ValuesKt.mapFloat2Float()[3.14], expected: 100.0) try assertEquals(actual: ValuesKt.mapDouble2String()[2.718281828459045], expected: "2.718281828459045") // test also explicit cast to [:] of primitiva types, e.g. [Int: Int] try assertEquals(actual: (ValuesKt.mutBoolean2String() as! [Bool: String])[true], expected: "true") try assertEquals(actual: (ValuesKt.mutByte2Short() as! [Int8: Int16])[-1], expected: 2) try assertEquals(actual: (ValuesKt.mutShort2Byte() as! [Int16: Int8])[-2], expected: 1) try assertEquals(actual: (ValuesKt.mutInt2Long() as! [Int: Int64])[-4], expected: 8) try assertEquals(actual: (ValuesKt.mutLong2Long() as! [Int64: Int64])[-8], expected: 8) try assertEquals(actual: (ValuesKt.mutUByte2Boolean() as! [UInt8: Bool])[128], expected: true) try assertEquals(actual: (ValuesKt.mutUShort2Byte() as! [UInt16: Int8])[0x8000], expected: 1) // the following samples require explicit cast to KotlinUInt or KotlinULong try assertEquals(actual: (ValuesKt.mutUInt2Long() as! [UInt: Int64])[UInt(0x8000_0000)], expected: 8) try assertEquals(actual: (ValuesKt.mutULong2Long() as! [UInt64: Int64])[u64], expected: 8) try assertEquals(actual: (ValuesKt.mutFloat2Float() as! [Float: Float])[3.14], expected: 100.0) try assertEquals(actual: (ValuesKt.mutDouble2String() as! [Double: String])[2.718281828459045], expected: "2.718281828459045") } class Baz_FakeOverrideInInterface : Bar_FakeOverrideInInterface { func foo(t: Any?) {} } func testFakeOverrideInInterface() throws { ValuesKt.callFoo_FakeOverrideInInterface(obj: Baz_FakeOverrideInInterface()) } // -------- Execution of the test -------- class ValuesTests : SimpleTestProvider { override init() { super.init() test("TestValues", testVals) test("TestVars", testVars) test("TestDoubles", testDoubles) test("TestNumbers", testNumbers) test("TestLists", testLists) test("TestLazyValues", testLazyVal) test("TestDelegatedProperties", testDelegatedProp) test("TestGetterDelegate", testGetterDelegate) test("TestNulls", testNulls) test("TestAnyVar", testAnyVar) test("TestFunctions", testFunctions) test("TestExceptions", testExceptions) test("TestFuncType", testFuncType) test("TestGenericsFoo", testGenericsFoo) test("TestVararg", testVararg) test("TestStringExtension", testStrExtFun) test("TestAnyToString", testAnyToString) test("TestAnyPrint", testAnyPrint) test("TestCharExtensions", testCharExtensions) test("TestLambda", testLambda) test("TestInterfaceExtension", testInterfaceExtension) test("TestClassInstances", testClassInstances) test("TestEnum", testEnum) test("TestDataClass", testDataClass) test("TestCompanionObj", testCompanionObj) test("TestInlineClasses", testInlineClasses) test("TestShared", testShared) test("TestPureSwiftClasses", testPureSwiftClasses) test("TestNames", testNames) test("TestSwiftOverride", testSwiftOverride) test("TestKotlinOverride", testKotlinOverride) test("TestGH2945", testGH2945) test("TestGH2830", testGH2830) test("TestGH2959", testGH2959) test("TestKClass", testKClass) test("TestSR10177Workaround", testSR10177Workaround) test("TestClashes", testClashes) test("TestInvalidIdentifiers", testInvalidIdentifiers) test("TestDeprecation", testDeprecation) test("TestWeakRefs", testWeakRefs) test("TestSharedRefs", TestSharedRefs().test) test("TestClassTypeCheck", testClassTypeCheck) test("TestInterfaceTypeCheck", testInterfaceTypeCheck) test("TestGH3503_1", testGH3503_1) test("TestGH3503_2", testGH3503_2) test("TestGH3503_3", testGH3503_3) test("TestGH3525", testGH3525) test("TestStringConversion", testStringConversion) test("TestGH3825", testGH3825) test("TestMapsExport", testMapsExport) test("TestFakeOverrideInInterface", testFakeOverrideInInterface) // Stress test, must remain the last one: test("TestGH2931", testGH2931) } }