// RUN: %empty-directory(%t) // // RUN: %gyb %s -o %t/main.swift // RUN: if [ %target-runtime == "objc" ]; then \ // RUN: %target-clang -fobjc-arc %S/Inputs/SlurpFastEnumeration/SlurpFastEnumeration.m -c -o %t/SlurpFastEnumeration.o; \ // RUN: %line-directive %t/main.swift -- %target-build-swift %S/Inputs/DictionaryKeyValueTypes.swift %S/Inputs/DictionaryKeyValueTypesObjC.swift %t/main.swift -I %S/Inputs/SlurpFastEnumeration/ -Xlinker %t/SlurpFastEnumeration.o -o %t/Array -Xfrontend -disable-access-control; \ // RUN: else \ // RUN: %line-directive %t/main.swift -- %target-build-swift %S/Inputs/DictionaryKeyValueTypes.swift %t/main.swift -o %t/Array -Xfrontend -disable-access-control; \ // RUN: fi // RUN: %line-directive %t/main.swift -- %target-run %t/Array // REQUIRES: executable_test import StdlibUnittest import StdlibCollectionUnittest %{ all_array_types = ['ContiguousArray', 'ArraySlice', 'Array'] }% %for Self in all_array_types: extension ${Self} { typealias _BufferID = UnsafeRawPointer? var _bufferID: _BufferID { return unsafeBitCast(_owner, to: _BufferID.self) } } %end var ArrayTestSuite = TestSuite("Array") //===----------------------------------------------------------------------===// // COW tests // FIXME: incomplete. //===----------------------------------------------------------------------===// func withInoutInt(_ x: inout Int, body: (_ x: inout Int) -> Void) { body(&x) } func withInoutT(_ x: inout T, body: (_ x: inout T) -> Void) { body(&x) } % for element_type in ['TestValueTy', 'TestBridgedValueTy']: % for array_type in all_array_types: % if element_type == 'TestBridgedValueTy': #if _runtime(_ObjC) % end ArrayTestSuite.test("${array_type}<${element_type}>/subscript(_: Int)/COW") .xfail(.custom({ _isStdlibDebugConfiguration() && "${array_type}" == "ArraySlice" }, reason: "rdar://33358110")) .code { var a: ${array_type}<${array_type}<${element_type}>> = [[ ${element_type}(10), ${element_type}(20), ${element_type}(30), ${element_type}(40), ${element_type}(50), ${element_type}(60), ${element_type}(70) ]] let identityOuter = a._bufferID var identityInner = a[0]._bufferID func checkIdentity(_ stackTrace: SourceLocStack) { % if element_type == 'TestValueTy': // Does not reallocate storage because we changed a property based on a // reference; array storage was not changed. Writeback of the inner array // does not happen. expectEqual(identityOuter, a._bufferID, stackTrace: stackTrace) expectEqual(identityInner, a[0]._bufferID, stackTrace: stackTrace) % else: expectEqual(identityOuter, a._bufferID, stackTrace: stackTrace) // Should not reallocate storage. expectEqual(identityInner, a[0]._bufferID, stackTrace: stackTrace) % end } // Mutating through a subscript expression. a[0][0] = ${element_type}(1010) checkIdentity(SourceLocStack().withCurrentLoc()) a[0][1].value = 1020 checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a) { (x: inout ${array_type}<${array_type}<${element_type}>>) in x[0][2].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0]) { (x: inout ${array_type}<${element_type}>) in x[3].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) // This will reallocate storage unless Array uses addressors for subscript. //withInoutT(&a[0][4]) { // (x: inout ${element_type}) in // x.value += 1000 //} // FIXME: both of these lines crash the compiler. // Passing an expression based on addressors as // 'inout' crashes SILGen //withInoutT(&a[0][5].value, { $0 += 1000 }) //withInoutInt(&a[0][6].value, { $0 += 1000 }) // Don't change the last element. expectEqual(1010, a[0][0].value) expectEqual(1020, a[0][1].value) expectEqual(1030, a[0][2].value) expectEqual(1040, a[0][3].value) expectEqual(50, a[0][4].value) expectEqual(60, a[0][5].value) expectEqual(70, a[0][6].value) } ArrayTestSuite.test("${array_type}<${element_type}>/subscript(_: Range)/COW") .xfail(.custom({ _isStdlibDebugConfiguration() && "${array_type}" == "ArraySlice" }, reason: "rdar://33358110")) .code { var a: ${array_type}<${array_type}<${element_type}>> = [[ ${element_type}(10), ${element_type}(20), ${element_type}(30), ${element_type}(40), ${element_type}(50), ${element_type}(60), ${element_type}(70), ${element_type}(80), ${element_type}(90), ]] let identityOuter = a._bufferID var identityInner = a[0]._bufferID func checkIdentity(_ stackTrace: SourceLocStack) { % if element_type == 'TestValueTy': // Does not reallocate storage because we changed a property based on a // reference; array storage was not changed. expectEqual(identityOuter, a._bufferID, stackTrace: stackTrace) expectEqual(identityInner, a[0]._bufferID, stackTrace: stackTrace) % else: expectEqual(identityOuter, a._bufferID, stackTrace: stackTrace) // Writeback happens in subscript(Range), but array notices that the new // value did not change. // Another writeback happens in Array.subscript(Int), but this is not what we // want. expectNotEqual(identityInner, a[0]._bufferID, stackTrace: stackTrace) identityInner = a[0]._bufferID % end } // Mutating through a subscript expression. a[0..<1][0][0] = ${element_type}(1010) // Reallocates storage because of the writeback in Array.subscript(Int). expectEqual(identityOuter, a._bufferID) expectNotEqual(identityInner, a[0]._bufferID) identityInner = a[0]._bufferID a[0..<1][0][1].value = 1020 checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a) { (x: inout ${array_type}<${array_type}<${element_type}>>) in x[0..<1][0][2].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1]) { (x: inout ArraySlice<${array_type}<${element_type}>>) in x[0][3].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1][0]) { (x: inout ${array_type}<${element_type}>) in x[4].value += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutT(&a[0..<1][0][5]) { (x: inout ${element_type}) in x.value += 1000 } // Reallocates storage because of the writeback in Array.subscript(Int) // (writeback is being requested for the array element even though it is not // needed). expectEqual(identityOuter, a._bufferID) expectNotEqual(identityInner, a[0]._bufferID) identityInner = a[0]._bufferID withInoutT(&a[0..<1][0][6].value) { (x: inout Int) in x += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) withInoutInt(&a[0..<1][0][7].value) { (x: inout Int) in x += 1000 } checkIdentity(SourceLocStack().withCurrentLoc()) // Don't change the last element. expectEqual(1010, a[0][0].value) expectEqual(1020, a[0][1].value) expectEqual(1030, a[0][2].value) expectEqual(1040, a[0][3].value) expectEqual(1050, a[0][4].value) expectEqual(1060, a[0][5].value) expectEqual(1070, a[0][6].value) expectEqual(1080, a[0][7].value) expectEqual(90, a[0][8].value) } % if element_type == 'TestBridgedValueTy': #endif // _runtime(_ObjC) % end % end % end #if _runtime(_ObjC) import Darwin import StdlibUnittestFoundationExtras import Foundation // FIXME: all the tests below are applicable to ArraySlice, too. //===----------------------------------------------------------------------===// // NSArray -> Array bridging tests // FIXME: incomplete. //===----------------------------------------------------------------------===// func isNativeArray(_ a: Array) -> Bool { return a._hoistableIsNativeTypeChecked() } func isCocoaArray(_ a: Array) -> Bool { return !isNativeArray(a) } func getAsImmutableNSArray(_ a: Array) -> NSArray { var elements = a.map { TestObjCValueTy($0) as AnyObject } return NSArray(objects: &elements, count: elements.count) } func getAsNSArray(_ a: Array) -> NSArray { // Return an `NSMutableArray` to make sure that it has a unique // pointer identity. return getAsNSMutableArray(a) } func getAsNSMutableArray(_ a: Array) -> NSMutableArray { let result = NSMutableArray() for element in a { result.add(TestObjCValueTy(element)) } return result } @objc class CustomImmutableNSArray : NSArray { init(_privateInit: ()) { super.init() } override init() { expectUnreachable() super.init() } override init(objects: UnsafePointer?, count: Int) { super.init(objects: objects, count: count) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) not implemented by CustomImmutableNSArray") } @objc(copyWithZone:) override func copy(with zone: NSZone?) -> Any { CustomImmutableNSArray.timesCopyWithZoneWasCalled += 1 return self } @objc override func object(at index: Int) -> Any { CustomImmutableNSArray.timesObjectAtIndexWasCalled += 1 return _data[index] } @objc override var count: Int { CustomImmutableNSArray.timesCountWasCalled += 1 return _data.count } @objc override func countByEnumerating( with state: UnsafeMutablePointer, objects: AutoreleasingUnsafeMutablePointer, count: Int ) -> Int { var theState = state.pointee if theState.state == 0 { theState.state = 1 theState.itemsPtr = AutoreleasingUnsafeMutablePointer(_data._baseAddressIfContiguous) theState.mutationsPtr = _fastEnumerationStorageMutationsPtr state.pointee = theState return _data.count } return 0 } let _data = [ 10, 20, 30 ].map { TestObjCValueTy($0) } static var timesCopyWithZoneWasCalled = 0 static var timesObjectAtIndexWasCalled = 0 static var timesCountWasCalled = 0 } ArrayTestSuite.test("BridgedFromObjC.Verbatim.BridgeUsingAs") { do { let source = [ 10, 20, 30 ] let nsa = getAsNSArray(source) var result = nsa as Array expectTrue(isCocoaArray(result)) expectType(Array.self, &result) checkSequence(source.map { TestObjCValueTy($0) as AnyObject }, result) { ($0 as! TestObjCValueTy).value == ($1 as! TestObjCValueTy).value } } do { let source = [ 10, 20, 30 ] let nsa = getAsNSArray(source) var result = nsa as! Array expectTrue(isCocoaArray(result)) expectType(Array.self, &result) checkSequence(source.map { TestObjCValueTy($0) }, result) { $0.value == $1.value } } } ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.BridgeUsingAs") { let source = [ 10, 20, 30 ] let nsa = getAsNSArray(source) var result = nsa as! Array expectTrue(isNativeArray(result)) expectType(Array.self, &result) checkSequence(source.map { TestBridgedValueTy($0) }, result) { $0.value == $1.value } } ArrayTestSuite.test("BridgedFromObjC.Verbatim.ArrayIsCopied") { let source = [ 10, 20, 30 ] let nsa = getAsNSMutableArray(source) let result = nsa as Array expectTrue(isCocoaArray(result)) // Delete the value from NSMutableArray. expectEqual(20, (nsa[1] as! TestObjCValueTy).value) nsa.removeObject(at: 1) expectEqual(30, (nsa[1] as! TestObjCValueTy).value) // Check that the Array is not affected. expectEqual(20, result[1].value) } ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ArrayIsCopied") { let source = [ 10, 20, 30 ] let nsa = getAsNSMutableArray(source) var result = nsa as AnyObject as! Array expectTrue(isNativeArray(result)) // Delete the value from NSMutableArray. expectEqual(20, (nsa[1] as! TestObjCValueTy).value) nsa.removeObject(at: 1) expectEqual(30, (nsa[1] as! TestObjCValueTy).value) // Check that the Array is not affected. expectEqual(20, result[1].value) } ArrayTestSuite.test("BridgedFromObjC.Verbatim.NSArrayIsRetained") { let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ])) var a: Array = convertNSArrayToArray(nsa) var bridgedBack: NSArray = convertArrayToNSArray(a) expectEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.NSArrayIsCopied") { let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ])) var a: Array = convertNSArrayToArray(nsa) var bridgedBack: NSArray = convertArrayToNSArray(a) expectNotEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } ArrayTestSuite.test("BridgedFromObjC.Verbatim.ImmutableArrayIsRetained") { let nsa: NSArray = CustomImmutableNSArray(_privateInit: ()) CustomImmutableNSArray.timesCopyWithZoneWasCalled = 0 CustomImmutableNSArray.timesObjectAtIndexWasCalled = 0 CustomImmutableNSArray.timesCountWasCalled = 0 let a: Array = convertNSArrayToArray(nsa) expectEqual(1, CustomImmutableNSArray.timesCopyWithZoneWasCalled) expectEqual(0, CustomImmutableNSArray.timesObjectAtIndexWasCalled) expectEqual(0, CustomImmutableNSArray.timesCountWasCalled) let bridgedBack: NSArray = convertArrayToNSArray(a) expectEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ImmutableArrayIsCopied") .skip(.iOSAny("")) .skip(.tvOSAny("")) .code { let nsa: NSArray = CustomImmutableNSArray(_privateInit: ()) CustomImmutableNSArray.timesCopyWithZoneWasCalled = 0 CustomImmutableNSArray.timesObjectAtIndexWasCalled = 0 CustomImmutableNSArray.timesCountWasCalled = 0 TestBridgedValueTy.bridgeOperations = 0 var a: Array = [] // FIXME: bridging shouldn't dump array contents into the autorelease pool. autoreleasepoolIfUnoptimizedReturnAutoreleased { a = convertNSArrayToArray(nsa) expectEqual(1, CustomImmutableNSArray.timesCopyWithZoneWasCalled) expectEqual(3, CustomImmutableNSArray.timesObjectAtIndexWasCalled) expectNotEqual(0, CustomImmutableNSArray.timesCountWasCalled) expectEqual(3, TestBridgedValueTy.bridgeOperations) } let bridgedBack: NSArray = convertArrayToNSArray(a) expectNotEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } // FIXME: test API calls on the BridgedFromObjC arrays. //===----------------------------------------------------------------------===// // Array -> NSArray bridging tests // // Element is bridged verbatim. // // FIXME: incomplete. //===----------------------------------------------------------------------===// ArrayTestSuite.test("BridgedToObjC.Verbatim.BridgeUsingAs") { let source = [ 10, 20, 30 ].map { TestObjCValueTy($0) } let result = source as NSArray expectTrue(isNativeNSArray(result)) expectEqual(3, result.count) autoreleasepoolIfUnoptimizedReturnAutoreleased { expectEqual(10, (result[0] as! TestObjCValueTy).value) expectEqual(20, (result[1] as! TestObjCValueTy).value) expectEqual(30, (result[2] as! TestObjCValueTy).value) } } ArrayTestSuite.test("BridgedToObjC/Verbatim/count/empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) expectEqual(0, a.count) } ArrayTestSuite.test("BridgedToObjC/Verbatim/count") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged() expectEqual(3, a.count) } for index in [ -100, -1, 0, 1, 100 ] { ArrayTestSuite.test( "BridgedToObjC/Verbatim/objectAtIndex/empty/trap/\(index)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) expectCrashLater() a.object(at: index) } } for index in [ -100, -1, 3, 4, 100 ] { ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex/trap/\(index)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) expectCrashLater() a.object(at: index) } } ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) var v: AnyObject = a.object(at: 0) as AnyObject expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = a.object(at: 1) as AnyObject expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = a.object(at: 2) as AnyObject expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) } expectAutoreleasedKeysAndValues(unopt: (0, 3)) } for indexRange in [ -2..<(-2), 1..<1, 0..<4, -2..<(-1), -1..<2, 0..<1, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/empty/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged( numElements: 0, capacity: 16) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0)) expectCrashLater() a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } for indexRange in [ 0..<4, -2..<(-1), -1..<2, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfRefTypeVerbatimBridged( numElements: 3, capacity: 16) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) expectCrashLater() a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) var v: AnyObject = buffer[0] expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = buffer[1] expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = buffer[2] expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) } buffer.deallocate() _fixLifetime(a) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/copyWithZone") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) let copy: AnyObject = a.copy(with: nil) as AnyObject expectEqual( unsafeBitCast(a, to: UInt.self), unsafeBitCast(copy, to: UInt.self)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/3") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromSwift/7") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 7) checkArrayFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70 ], a, { a }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromObjC/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromObjC( [], a, { a }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromSwift/Partial") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 9) checkArrayEnumeratorPartialFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ], a, maxFastEnumerationItems: 5, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/ObjectEnumerator/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) } ArrayTestSuite.test("BridgedToObjC/Verbatim/BridgeBack/Reallocate") { let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) var v: AnyObject = a[0] as AnyObject expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = a[1] as AnyObject expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = a[2] as AnyObject expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) // Bridge back to native array. var native: [TestObjCValueTy] = convertNSArrayToArray(a) native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) native.append(TestObjCValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Verbatim/BridgeBack/Adopt") { // Bridge back to native array. var native: [TestObjCValueTy] = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3) as! Array let identity1 = unsafeBitCast(native, to: UInt.self) // Mutate elements, but don't change count. native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) // Expect no reallocations. expectEqual(identity1, unsafeBitCast(native, to: UInt.self)) } //===----------------------------------------------------------------------===// // Array -> NSArray bridging tests // // Element is bridged non-verbatim. // // FIXME: incomplete. //===----------------------------------------------------------------------===// ArrayTestSuite.test("BridgedToObjC.Nonverbatim.BridgeUsingAs") { let source = [ 10, 20, 30 ].map { TestBridgedValueTy($0) } var result = source as NSArray expectTrue(isNativeNSArray(result)) expectEqual(3, result.count) autoreleasepoolIfUnoptimizedReturnAutoreleased { expectEqual(10, (result[0] as! TestBridgedValueTy).value) expectEqual(20, (result[1] as! TestBridgedValueTy).value) expectEqual(30, (result[2] as! TestBridgedValueTy).value) } } ArrayTestSuite.test("BridgedToObjC/Custom/count/empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) expectEqual(0, a.count) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/count") { let a = getBridgedNSArrayOfValueTypeCustomBridged() expectEqual(3, a.count) expectEqual(0, TestBridgedValueTy.bridgeOperations) } for index in [ -100, -1, 0, 1, 100 ] { ArrayTestSuite.test( "BridgedToObjC/Custom/objectAtIndex/empty/trap/\(index)") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) expectCrashLater() a.object(at: index) } } for index in [ -100, -1, 3, 4, 100 ] { ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex/trap/\(index)") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) expectCrashLater() a.object(at: index) } } ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a.object(at: 0) as AnyObject expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = a.object(at: 1) as AnyObject expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = a.object(at: 2) as AnyObject expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) } expectEqual(3, TestBridgedValueTy.bridgeOperations) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } for indexRange in [ -2..<(-2), 1..<1, 0..<4, -2..<(-1), -1..<2, 0..<1, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/empty/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfValueTypeCustomBridged( numElements: 0, capacity: 16) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0)) expectCrashLater() a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } for indexRange in [ 0..<4, -2..<(-1), -1..<2, 2..<4, 4..<5 ] as [Range] { ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/trap/\(indexRange)") .crashOutputMatches("Array index out of range") .code { let a = getBridgedNSArrayOfValueTypeCustomBridged( numElements: 3, capacity: 16) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) expectCrashLater() a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange)) } } ArrayTestSuite.test("BridgedToObjC/Custom/getObjects") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) let buffer = UnsafeMutablePointer.allocate(capacity: 16) a.available_getObjects( AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3)) var v: AnyObject = buffer[0] expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = buffer[1] expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = buffer[2] expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) for i in 0..<3 { expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) } buffer.deallocate() _fixLifetime(a) expectEqual(3, TestBridgedValueTy.bridgeOperations) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/copyWithZone") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) let copy: AnyObject = a.copy(with: nil) as AnyObject expectEqual( unsafeBitCast(a, to: UInt.self), unsafeBitCast(copy, to: UInt.self)) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a }, { ($0 as! TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/3") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a }, { ($0 as! TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromSwift/7") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 7) checkArrayFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70 ], a, { a }, { ($0 as! TestObjCValueTy).value }) expectEqual(7, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromObjC/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromObjC( [], a, { a }, { ($0 as! TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a }, { ($0 as! TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift/Empty") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 0) checkArrayFastEnumerationFromSwift( [], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) expectEqual(0, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromSwift( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromSwift/Partial") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 9) checkArrayEnumeratorPartialFastEnumerationFromSwift( [ 10, 20, 30, 40, 50, 60, 70, 80, 90 ], a, maxFastEnumerationItems: 5, { ($0 as! TestObjCValueTy).value }) expectEqual(9, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/ObjectEnumerator/FastEnumeration/UseFromObjC") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) checkArrayFastEnumerationFromObjC( [ 10, 20, 30 ], a, { a.objectEnumerator() }, { ($0 as! TestObjCValueTy).value }) expectEqual(3, TestBridgedValueTy.bridgeOperations) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Cast") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a[0] as AnyObject expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = a[1] as AnyObject expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = a[2] as AnyObject expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) // Bridge back to native array with a cast. var native: [TestObjCValueTy] = convertNSArrayToArray(a) native[0] = TestObjCValueTy(110) native[1] = TestObjCValueTy(120) native[2] = TestObjCValueTy(130) native.append(TestObjCValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Reallocate") { let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3) var v: AnyObject = a[0] as AnyObject expectEqual(10, (v as! TestObjCValueTy).value) let idValue0 = unsafeBitCast(v, to: UInt.self) v = a[1] as AnyObject expectEqual(20, (v as! TestObjCValueTy).value) let idValue1 = unsafeBitCast(v, to: UInt.self) v = a[2] as AnyObject expectEqual(30, (v as! TestObjCValueTy).value) let idValue2 = unsafeBitCast(v, to: UInt.self) // Bridge back to native array. var native: [TestBridgedValueTy] = convertNSArrayToArray(a) native[0] = TestBridgedValueTy(110) native[1] = TestBridgedValueTy(120) native[2] = TestBridgedValueTy(130) native.append(TestBridgedValueTy(140)) // Ensure that the compiler does not elide mutation of the native array. _blackHole(native) // Check that mutating the native array did not affect the bridged array. expectEqual(3, a.count) expectEqual(idValue0, unsafeBitCast(a.object(at: 0) as AnyObject, to: UInt.self)) expectEqual(idValue1, unsafeBitCast(a.object(at: 1) as AnyObject, to: UInt.self)) expectEqual(idValue2, unsafeBitCast(a.object(at: 2) as AnyObject, to: UInt.self)) expectAutoreleasedKeysAndValues(unopt: (0, 3)) } ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Adopt") { // Bridge back to native array. var native: [TestBridgedValueTy] = convertNSArrayToArray( getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)) let identity1 = unsafeBitCast(native, to: UInt.self) // Mutate elements, but don't change count. native[0] = TestBridgedValueTy(110) native[1] = TestBridgedValueTy(120) native[2] = TestBridgedValueTy(130) // Expect no reallocations. expectEqual(identity1, unsafeBitCast(native, to: UInt.self)) } //===----------------------------------------------------------------------===// // NSArray -> Array -> NSArray bridging tests. //===----------------------------------------------------------------------===// ArrayTestSuite.test("BridgedToObjC.Verbatim.RoundtripThroughSwiftArray") { % for (MiddleType, AsCast) in [ % ('Array', 'as'), % ('Array', 'as!'), % ]: do { let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ]) let a: ${MiddleType} = convertNSArrayToArray(nsa) let bridgedBack = convertArrayToNSArray(a) expectEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } do { let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ]) let a = nsa ${AsCast} ${MiddleType} let bridgedBack: NSArray = a as NSArray expectEqual( unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) _fixLifetime(nsa) _fixLifetime(a) _fixLifetime(bridgedBack) } % end } ArrayTestSuite.test("BridgedToObjC.Nonverbatim.RoundtripThroughSwiftArray") { do { TestBridgedValueTy.bridgeOperations = 0 let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ]) let a: Array = convertNSArrayToArray(nsa) let bridgedBack = convertArrayToNSArray(a) expectEqual(3, TestBridgedValueTy.bridgeOperations) } do { TestBridgedValueTy.bridgeOperations = 0 let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ]) let a = nsa as! Array let bridgedBack: NSArray = a as NSArray expectEqual(3, TestBridgedValueTy.bridgeOperations) } } ArrayTestSuite.setUp { resetLeaksOfDictionaryKeysValues() resetLeaksOfObjCDictionaryKeysValues() TestBridgedValueTy.bridgeOperations = 0 } ArrayTestSuite.tearDown { if _isDebugAssertConfiguration() { // The return autorelease optimization does not happen reliable. expectNoLeaksOfDictionaryKeysValues() expectNoLeaksOfObjCDictionaryKeysValues() } } #endif // _runtime(_ObjC) runAllTests()