blob: aa3c9359160374e148505f994e3d605bf3c86bca [file] [log] [blame]
// 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 -swift-version 4.2; \
// 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 -swift-version 4.2; \
// RUN: fi
// RUN: %target-codesign %t/Array && %line-directive %t/main.swift -- %target-run %t/Array
// REQUIRES: executable_test
// Requires swift-version 4
// UNSUPPORTED: swift_test_mode_optimize_none_with_implicit_dynamic
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<T>(_ 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")
.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.
// <rdar://problem/18439579> 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<Int>)/COW")
.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<Int>), 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<Element>(_ a: Array<Element>) -> Bool {
return a._hoistableIsNativeTypeChecked()
}
func isCocoaArray<Element>(_ a: Array<Element>) -> Bool {
return !isNativeArray(a)
}
func getAsImmutableNSArray(_ a: Array<Int>) -> NSArray {
var elements = a.map { TestObjCValueTy($0) as AnyObject }
return NSArray(objects: &elements, count: elements.count)
}
func getAsNSArray(_ a: Array<Int>) -> NSArray {
// Return an `NSMutableArray` to make sure that it has a unique
// pointer identity.
return getAsNSMutableArray(a)
}
func getAsNSMutableArray(_ a: Array<Int>) -> 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<AnyObject>?, 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<NSFastEnumerationState>,
objects: AutoreleasingUnsafeMutablePointer<AnyObject?>,
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<AnyObject>.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<TestObjCValueTy>
expectTrue(isCocoaArray(result))
expectType(Array<TestObjCValueTy>.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<TestBridgedValueTy>
expectTrue(isNativeArray(result))
expectType(Array<TestBridgedValueTy>.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<AnyObject>
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] as! TestObjCValueTy).value)
}
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ArrayIsCopied") {
let source = [ 10, 20, 30 ]
let nsa = getAsNSMutableArray(source)
var result = nsa as AnyObject as! Array<TestBridgedValueTy>
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 ]))
let a: Array<AnyObject> = convertNSArrayToArray(nsa)
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.NSArrayIsCopied") {
let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ]))
let a: Array<TestBridgedValueTy> = convertNSArrayToArray(nsa)
let 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<AnyObject> = 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("<rdar://problem/33926468>"))
.skip(.tvOSAny("<rdar://problem/33926468>"))
.code {
let nsa: NSArray = CustomImmutableNSArray(_privateInit: ())
CustomImmutableNSArray.timesCopyWithZoneWasCalled = 0
CustomImmutableNSArray.timesObjectAtIndexWasCalled = 0
CustomImmutableNSArray.timesCountWasCalled = 0
TestBridgedValueTy.bridgeOperations = 0
var a: Array<TestBridgedValueTy> = []
// 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)
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<Int>] {
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<AnyObject>.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<Int>] {
ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects/trap/\(indexRange)")
.crashOutputMatches("Array index out of range")
.code {
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(
numElements: 3, capacity: 16)
let buffer = UnsafeMutablePointer<AnyObject>.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<AnyObject>.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)
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)
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<Int>] {
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<AnyObject>.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<Int>] {
ArrayTestSuite.test("BridgedToObjC/Custom/getObjects/trap/\(indexRange)")
.crashOutputMatches("Array index out of range")
.code {
let a = getBridgedNSArrayOfValueTypeCustomBridged(
numElements: 3, capacity: 16)
let buffer = UnsafeMutablePointer<AnyObject>.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<AnyObject>.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)
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<AnyObject>', 'as'),
% ('Array<TestObjCValueTy>', '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<TestBridgedValueTy> = convertNSArrayToArray(nsa)
let _ = convertArrayToNSArray(a)
expectEqual(3, TestBridgedValueTy.bridgeOperations)
}
do {
TestBridgedValueTy.bridgeOperations = 0
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
let a = nsa as! Array<TestBridgedValueTy>
let _: 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()