mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
...into the validation suite. This is the wrong solution but at least the bots will continue to run all the tests and we won't regress. Swift SVN r24934
1013 lines
31 KiB
Plaintext
1013 lines
31 KiB
Plaintext
// RUN: rm -rf %t
|
|
// RUN: mkdir -p %t
|
|
//
|
|
// FIXME: -fobjc-abi-version=2 is a band-aid fix for for rdar://16946936
|
|
//
|
|
// RUN: %S/../../utils/gyb %s -o %t/main.swift
|
|
// RUN: xcrun -sdk %target-sdk-name clang++ -fobjc-arc -fobjc-abi-version=2 -arch %target-cpu %S/Inputs/SlurpFastEnumeration/SlurpFastEnumeration.m -c -o %t/SlurpFastEnumeration.o
|
|
// RUN: %S/../../utils/line-directive %t/main.swift -- %target-build-swift %S/Inputs/DictionaryKeyValueTypes.swift %t/main.swift -I %S/Inputs/SlurpFastEnumeration/ -Xlinker %t/SlurpFastEnumeration.o -o %t/Array -Xfrontend -disable-access-control
|
|
// RUN: %S/../../utils/line-directive %t/main.swift -- %target-run %t/Array
|
|
|
|
// XFAIL: linux
|
|
|
|
import Darwin
|
|
import StdlibUnittest
|
|
import Foundation
|
|
|
|
%{
|
|
all_array_types = [ 'ContiguousArray', 'Slice', 'Array', '_UnitTestArray' ]
|
|
}%
|
|
|
|
extension Array {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension Slice {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension ContiguousArray {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension _UnitTestArray {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
var ArrayTestSuite = TestSuite("Array")
|
|
|
|
ArrayTestSuite.test("sizeof") {
|
|
var a = [ 10, 20, 30 ]
|
|
#if arch(i386) || arch(arm)
|
|
expectEqual(4, sizeofValue(a))
|
|
#else
|
|
expectEqual(8, sizeofValue(a))
|
|
#endif
|
|
}
|
|
|
|
ArrayTestSuite.test("valueDestruction") {
|
|
var a = [TestValueTy]()
|
|
for i in 100...110 {
|
|
a.append(TestValueTy(i))
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Native array tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("Native/count/empty") {
|
|
let a = [TestValueTy]()
|
|
expectEqual(0, a.count)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/count") {
|
|
let a = [ TestValueTy(10), TestValueTy(20), TestValueTy(30) ]
|
|
expectEqual(3, a.count)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/isEmpty/empty") {
|
|
let a = [TestValueTy]()
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/isEmpty") {
|
|
let a = [ TestValueTy(10), TestValueTy(20), TestValueTy(30) ]
|
|
expectFalse(a.isEmpty)
|
|
}
|
|
|
|
enum EnumWithoutPayloads : Equatable {
|
|
case A, B, C, D
|
|
}
|
|
|
|
func == (lhs: EnumWithoutPayloads, rhs: EnumWithoutPayloads) -> Bool {
|
|
switch (lhs, rhs) {
|
|
case (.A, .A), (.B, .B), (.C, .C), (.D, .D):
|
|
return true
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}/Sliceable/Enums") {
|
|
typealias E = EnumWithoutPayloads
|
|
|
|
if true {
|
|
let expected = [ E.A, E.B, E.C, E.D ]
|
|
let sliceable = ${array_type}(expected)
|
|
checkSliceableWithBidirectionalIndex(
|
|
expected, sliceable, SourceLocStack().withCurrentLoc())
|
|
}
|
|
|
|
/*
|
|
FIXME: add this test when Array<T> can be conditionally Equatable.
|
|
if true {
|
|
let expected = [ [ E.A, E.B ], [ E.B, E.C ], [ E.D ], [ E.A, E.B, E.D ] ]
|
|
let sliceable = ${array_type}(expected)
|
|
checkSliceableWithBidirectionalIndex(
|
|
expected, sliceable, SourceLocStack().withCurrentLoc())
|
|
}
|
|
*/
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/emptyAllocation") {
|
|
|
|
let arr0 = ${array_type}<Int>()
|
|
let arr1 = ${array_type}<TestValueTy>(count: 0, repeatedValue: TestValueTy(0))
|
|
// Empty arrays all use the same buffer
|
|
expectEqual(arr0._buffer.identity, arr1._buffer.identity)
|
|
|
|
let hasNilBuffer = arr1.identity == nil
|
|
expectFalse(hasNilBuffer)
|
|
|
|
let arr2: ${array_type}<TestValueTy> = []
|
|
let emptyLiteralsShareBuffer = arr0._buffer.identity == arr2._buffer.identity
|
|
expectTrue(emptyLiteralsShareBuffer)
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// COW tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
func withInoutInt(inout x: Int, body: (inout x: Int) -> ()) {
|
|
body(x: &x)
|
|
}
|
|
|
|
func withInoutT<T>(inout x: T, body: (inout x: T) -> ()) {
|
|
body(x: &x)
|
|
}
|
|
|
|
% for element_type in [ 'TestValueTy', 'TestBridgedValueTy' ]:
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}<${element_type}>/subscript(_: Int)/COW") {
|
|
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.identity
|
|
var identityInner = a[0].identity
|
|
|
|
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.identity, stackTrace: stackTrace)
|
|
expectEqual(identityInner, a[0].identity, stackTrace: stackTrace)
|
|
% else:
|
|
expectEqual(identityOuter, a.identity, stackTrace: stackTrace)
|
|
|
|
// Should not reallocate storage.
|
|
expectEqual(identityInner, a[0].identity, 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) {
|
|
(inout x: ${array_type}<${array_type}<${element_type}>>) in
|
|
x[0][2].value += 1000
|
|
}
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutT(&a[0]) {
|
|
(inout x: ${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]) {
|
|
// (inout x: ${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") {
|
|
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.identity
|
|
var identityInner = a[0].identity
|
|
|
|
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.identity, stackTrace: stackTrace)
|
|
expectEqual(identityInner, a[0].identity, stackTrace: stackTrace)
|
|
% else:
|
|
expectEqual(identityOuter, a.identity, 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].identity, stackTrace: stackTrace)
|
|
identityInner = a[0].identity
|
|
% 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.identity)
|
|
expectNotEqual(identityInner, a[0].identity)
|
|
identityInner = a[0].identity
|
|
|
|
a[0..<1][0][1].value = 1020
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutT(&a) {
|
|
(inout x: ${array_type}<${array_type}<${element_type}>>) in
|
|
x[0..<1][0][2].value += 1000
|
|
}
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutT(&a[0..<1]) {
|
|
(inout x: Slice<${array_type}<${element_type}>>) in
|
|
x[0][3].value += 1000
|
|
}
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutT(&a[0..<1][0]) {
|
|
(inout x: ${array_type}<${element_type}>) in
|
|
x[4].value += 1000
|
|
}
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutT(&a[0..<1][0][5]) {
|
|
(inout x: ${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.identity)
|
|
expectNotEqual(identityInner, a[0].identity)
|
|
identityInner = a[0].identity
|
|
|
|
withInoutT(&a[0..<1][0][6].value) {
|
|
(inout x: Int) in
|
|
x += 1000
|
|
}
|
|
|
|
checkIdentity(SourceLocStack().withCurrentLoc())
|
|
|
|
withInoutInt(&a[0..<1][0][7].value) {
|
|
(inout x: 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)
|
|
}
|
|
|
|
% end
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NSArray -> Array bridging tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array -> NSArray bridging tests
|
|
//
|
|
// Key and Value are bridged verbatim.
|
|
//
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
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.objectAtIndex(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.objectAtIndex(index)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/objectAtIndex") {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)
|
|
|
|
var v: AnyObject = a.objectAtIndex(0)
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a.objectAtIndex(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a.objectAtIndex(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.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>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0))
|
|
expectCrashLater()
|
|
a.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>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3))
|
|
expectCrashLater()
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange))
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/getObjects") {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)
|
|
let buffer = UnsafeMutablePointer<AnyObject>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3))
|
|
|
|
var v: AnyObject = buffer[0]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self))
|
|
}
|
|
|
|
buffer.dealloc(3)
|
|
_fixLifetime(a)
|
|
|
|
expectAutoreleasedKeysAndValues(unopt: (0, 3))
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/copyWithZone") {
|
|
let a = getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3)
|
|
let copy: AnyObject = a.copyWithZone(nil)
|
|
expectEqual(unsafeBitCast(a, UWord.self), unsafeBitCast(copy, UWord.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]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.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.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self))
|
|
|
|
expectAutoreleasedKeysAndValues(unopt: (0, 3))
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Verbatim/BridgeBack/Adopt") {
|
|
// Bridge back to native array.
|
|
var native: [TestObjCValueTy] = _convertNSArrayToArray(
|
|
getBridgedNSArrayOfRefTypeVerbatimBridged(numElements: 3))
|
|
let identity1 = unsafeBitCast(native, UWord.self)
|
|
|
|
// Mutate elements, but don't change length.
|
|
native[0] = TestObjCValueTy(110)
|
|
native[1] = TestObjCValueTy(120)
|
|
native[2] = TestObjCValueTy(130)
|
|
|
|
// Expect no reallocations.
|
|
expectEqual(identity1, unsafeBitCast(native, UWord.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array -> NSArray bridging tests
|
|
//
|
|
// Key and Value are bridged non-verbatim.
|
|
//
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
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.objectAtIndex(index)
|
|
}
|
|
}
|
|
|
|
for index in [ -100, -1, 3, 4, 100 ] {
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex/trap/\(index)") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
expectCrashLater()
|
|
a.objectAtIndex(index)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/objectAtIndex") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
|
|
var v: AnyObject = a.objectAtIndex(0)
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a.objectAtIndex(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a.objectAtIndex(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.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>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<0))
|
|
expectCrashLater()
|
|
a.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>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3))
|
|
expectCrashLater()
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(indexRange))
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/getObjects") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
let buffer = UnsafeMutablePointer<AnyObject>.alloc(16)
|
|
a.getObjects(
|
|
AutoreleasingUnsafeMutablePointer(buffer), range: NSRange(0..<3))
|
|
|
|
var v: AnyObject = buffer[0]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self))
|
|
}
|
|
|
|
buffer.dealloc(3)
|
|
_fixLifetime(a)
|
|
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
expectAutoreleasedKeysAndValues(unopt: (0, 3))
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/copyWithZone") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
let copy: AnyObject = a.copyWithZone(nil)
|
|
expectEqual(unsafeBitCast(a, UWord.self), unsafeBitCast(copy, UWord.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]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.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.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.self))
|
|
|
|
expectAutoreleasedKeysAndValues(unopt: (0, 3))
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC/Custom/BridgeBack/Reallocate") {
|
|
let a = getBridgedNSArrayOfValueTypeCustomBridged(numElements: 3)
|
|
|
|
var v: AnyObject = a[0]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UWord.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UWord.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.objectAtIndex(0), UWord.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UWord.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UWord.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, UWord.self)
|
|
|
|
// Mutate elements, but don't change length.
|
|
native[0] = TestBridgedValueTy(110)
|
|
native[1] = TestBridgedValueTy(120)
|
|
native[2] = TestBridgedValueTy(130)
|
|
|
|
// Expect no reallocations.
|
|
expectEqual(identity1, unsafeBitCast(native, UWord.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array and EvilCollection that changes its size while we are not looking
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
let evilBoundsError = "EvilCollection: index out of range"
|
|
|
|
final class EvilCollection : CollectionType {
|
|
init(_ growth: Int, boundsChecked: Bool) {
|
|
self.growth = growth
|
|
self.boundsChecked = boundsChecked
|
|
}
|
|
|
|
var growth: Int
|
|
var count: Int = 20
|
|
var boundsChecked: Bool
|
|
|
|
var startIndex : Int {
|
|
count += growth
|
|
return 0
|
|
}
|
|
|
|
var endIndex : Int {
|
|
return count
|
|
}
|
|
|
|
subscript(i: Int) -> TestValueTy {
|
|
if boundsChecked {
|
|
precondition(i >= 0 && i < count, evilBoundsError)
|
|
}
|
|
return TestValueTy(i)
|
|
}
|
|
|
|
func generate() -> IndexingGenerator<EvilCollection> {
|
|
return IndexingGenerator(self)
|
|
}
|
|
}
|
|
|
|
for (step, evilBoundsCheck) in [ (1, true), (-1, false), (-1, true) ] {
|
|
|
|
let message = step < 0 && evilBoundsCheck
|
|
? evilBoundsError
|
|
: "invalid CollectionType: count differed in successive traversals"
|
|
|
|
let natureOfEvil = step > 0 ? "Growth" : "Shrinkage"
|
|
let boundsChecked = evilBoundsCheck ? "BoundsChecked" : "NoBoundsCheck"
|
|
let testPrefix = "MemorySafety/\(boundsChecked)/Evil\(natureOfEvil)"
|
|
|
|
let t = ArrayTestSuite.test("\(testPrefix)/Infrastructure")
|
|
(evilBoundsCheck ? t.crashOutputMatches(evilBoundsError) : t).code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
let count0 = count(evil)
|
|
let count1 = count(evil)
|
|
expectNotEqual(count0, count1)
|
|
if step > 0 {
|
|
expectLE(count0, count1)
|
|
}
|
|
else {
|
|
expectGE(count0, count1)
|
|
}
|
|
if evilBoundsCheck {
|
|
expectCrashLater()
|
|
}
|
|
let x = evil[-1]
|
|
}
|
|
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/Construction")
|
|
.crashOutputMatches(message)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
expectCrashLater()
|
|
let a = Array(evil)
|
|
}
|
|
|
|
for (op, rangeMax) in ["Grow":0, "Shrink":200] {
|
|
ArrayTestSuite.test("\(testPrefix)/replaceRange/\(op)Unique")
|
|
.crashOutputMatches(message)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array(lazy(0..<200).map { TestValueTy($0) })
|
|
expectCrashLater()
|
|
a.replaceRange(0..<rangeMax, with: evil)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/replaceRange/\(op)NonUnique")
|
|
.crashOutputMatches(message)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array(lazy(0..<200).map { TestValueTy($0) })
|
|
var b = a
|
|
expectCrashLater()
|
|
a.replaceRange(0..<rangeMax, with: evil)
|
|
_fixLifetime(b)
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.setUp {
|
|
resetLeaksOfDictionaryKeysValues()
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
}
|
|
|
|
ArrayTestSuite.tearDown {
|
|
expectNoLeaksOfDictionaryKeysValues()
|
|
}
|
|
|
|
runAllTests()
|
|
|