mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Affected types: _ArrayType, Array, ArraySlice, ContiguousArray, Repeat, String (initializers from Character and UnicodeScalar)
1765 lines
52 KiB
Plaintext
1765 lines
52 KiB
Plaintext
// RUN: rm -rf %t
|
|
// RUN: mkdir -p %t
|
|
//
|
|
// RUN: %S/../../utils/gyb %s -o %t/main.swift
|
|
// RUN: %target-clang -fobjc-arc %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
|
|
// REQUIRES: executable_test
|
|
|
|
// XFAIL: linux
|
|
|
|
import Darwin
|
|
import StdlibUnittest
|
|
import StdlibUnittestFoundationExtras
|
|
import Foundation
|
|
|
|
%{
|
|
all_array_types = [ 'ContiguousArray', 'ArraySlice', 'Array' ]
|
|
}%
|
|
|
|
extension Array {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension ArraySlice {
|
|
var identity: UnsafePointer<Void> {
|
|
return self._buffer.identity
|
|
}
|
|
}
|
|
|
|
extension ContiguousArray {
|
|
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)
|
|
}
|
|
|
|
protocol TestProtocol1 {}
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
// Check that the generic parameter is called 'Element'.
|
|
extension ${array_type} where Element : TestProtocol1 {
|
|
var _elementIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
/// Returns an ${array_type} that does not share its buffer with other arrays.
|
|
func getFresh${array_type}<S : SequenceType>(sequence: S)
|
|
-> ${array_type}<S.Iterator.Element> {
|
|
var result: ${array_type}<S.Iterator.Element> = []
|
|
result.reserveCapacity(sequence.underestimateCount())
|
|
for element in sequence {
|
|
result.append(element)
|
|
}
|
|
return result
|
|
}
|
|
|
|
% end
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
struct SequenceWithCustomUnderestimateCount : SequenceType {
|
|
init(_ data: [Int]) {
|
|
self._data = MinimalSequence(elements: data.map(OpaqueValue.init))
|
|
}
|
|
|
|
func iterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
|
|
return _data.iterator()
|
|
}
|
|
|
|
func underestimateCount() -> Int {
|
|
++SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled
|
|
return _data.underestimateCount()
|
|
}
|
|
|
|
static var timesUnderestimateCountWasCalled: Int = 0
|
|
|
|
let _data: MinimalSequence<OpaqueValue<Int>>
|
|
}
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}/init(SequenceType)") {
|
|
let base = SequenceWithCustomUnderestimateCount(
|
|
[ 0, 30, 10, 90 ])
|
|
|
|
SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled = 0
|
|
|
|
let result = ${array_type}(base)
|
|
|
|
expectEqual([ 0, 30, 10, 90 ], result.map { $0.value })
|
|
|
|
expectEqual(1, SequenceWithCustomUnderestimateCount.timesUnderestimateCountWasCalled)
|
|
|
|
expectEqualSequence(
|
|
[], Array(base).map { $0.value }, "sequence should be consumed")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
/*
|
|
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}/appendNonUnique") {
|
|
var x: ${array_type}<Int> = []
|
|
x.reserveCapacity(10002)
|
|
let capacity = x.capacity
|
|
for _ in 1...10000 {
|
|
let y = x
|
|
x.append(1)
|
|
expectTrue(x.capacity == capacity)
|
|
let z = x
|
|
x.removeAtIndex(0)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/emptyAllocation") {
|
|
let arr0 = ${array_type}<Int>()
|
|
let arr1 = ${array_type}<TestValueTy>(repeating: TestValueTy(0), count: 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)
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/filter") {
|
|
if true {
|
|
let arr: ${array_type}<Int> = []
|
|
var result = arr.filter() {
|
|
(x: Int) -> Bool in
|
|
expectUnreachable()
|
|
return true
|
|
}
|
|
expectType(Array<Int>.self, &result)
|
|
expectEqual([], result)
|
|
expectEqual(0, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { (x: Int) -> Bool in true }
|
|
expectEqual([ 0, 30, 10, 90 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { (x: Int) -> Bool in false }
|
|
expectEqual([], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.filter() { $0 % 3 == 0 }
|
|
expectEqual([ 0, 30, 90 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/map") {
|
|
if true {
|
|
let arr: ${array_type}<Int> = []
|
|
var result = arr.map() {
|
|
(x: Int) -> Int16 in
|
|
expectUnreachable()
|
|
return 42
|
|
}
|
|
expectType(Array<Int16>.self, &result)
|
|
expectEqual([], result)
|
|
expectEqual(0, result.capacity)
|
|
}
|
|
if true {
|
|
let arr: ${array_type}<Int> = [ 0, 30, 10, 90 ]
|
|
let result = arr.map() { $0 + 1 }
|
|
expectEqual([ 1, 31, 11, 91 ], result)
|
|
expectGE(2 * result.count, result.capacity)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/flatMap") {
|
|
let enumerate : Int -> ${array_type}<Int> =
|
|
{ return ${array_type}(1..<($0 + 1)) }
|
|
expectEqualSequence([], ${array_type}().flatMap(enumerate))
|
|
expectEqualSequence([ 1 ], ${array_type}([ 1 ]).flatMap(enumerate))
|
|
expectEqualSequence(
|
|
[ 1, 1, 2 ],
|
|
${array_type}([ 1, 2 ]).flatMap(enumerate))
|
|
expectEqualSequence(
|
|
[ 1, 1, 1, 2 ],
|
|
${array_type}([ 1, 2 ]).flatMap(enumerate).flatMap(enumerate))
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/Mirror") {
|
|
do {
|
|
let input: ${array_type}<Int> = []
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"- 0 elements\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
do {
|
|
let input: ${array_type}<Int> = [ 10, 20, 30, 40 ]
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"▿ 4 elements\n" +
|
|
" - [0]: 10\n" +
|
|
" - [1]: 20\n" +
|
|
" - [2]: 30\n" +
|
|
" - [3]: 40\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
% if array_type == 'ArraySlice':
|
|
do {
|
|
let base = [ 10, 20, 30, 40 ]
|
|
let input: ArraySlice<Int> = base[1..<3]
|
|
var output = ""
|
|
dump(input, &output)
|
|
|
|
let expected =
|
|
"▿ 2 elements\n" +
|
|
" - [0]: 20\n" +
|
|
" - [1]: 30\n"
|
|
|
|
expectEqual(expected, output)
|
|
}
|
|
% end
|
|
}
|
|
|
|
% end
|
|
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/popLast") {
|
|
// Empty
|
|
if true {
|
|
var a = ${Kind}<Int>()
|
|
let popped = a.popLast()
|
|
expectEmpty(popped)
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
|
|
if true {
|
|
var popped = [Int]()
|
|
var a: ${Kind}<Int> = [1010, 2020, 3030]
|
|
while let element = a.popLast() {
|
|
popped.append(element)
|
|
}
|
|
expectEqualSequence([1010, 2020, 3030], popped.reverse())
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
}
|
|
% end
|
|
|
|
// Check how removeFirst() affects indices.
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/removeFirst") {
|
|
if true {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
if true {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1, 2 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
}
|
|
% end
|
|
|
|
ArrayTestSuite.test("ArraySlice/removeFirst") {
|
|
if true {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
if true {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// _withUnsafeMutableBufferPointerIfSupported()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct WithUnsafeMutableBufferPointerIfSupportedTest {
|
|
let sequence: [Int]
|
|
let loc: SourceLoc
|
|
|
|
init(
|
|
_ sequence: [Int],
|
|
file: String = __FILE__, line: UInt = __LINE__
|
|
) {
|
|
self.sequence = sequence
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
}
|
|
|
|
let withUnsafeMutableBufferPointerIfSupportedTests = [
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([]),
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([ 10 ]),
|
|
WithUnsafeMutableBufferPointerIfSupportedTest([ 10, 20, 30, 40, 50 ]),
|
|
]
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported") {
|
|
for test in withUnsafeMutableBufferPointerIfSupportedTests {
|
|
var a = getFresh${array_type}(test.sequence.map(OpaqueValue.init))
|
|
if true {
|
|
// Read.
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<[OpaqueValue<Int>]> in
|
|
let bufferPointer =
|
|
UnsafeMutableBufferPointer(start: baseAddress, count: count)
|
|
return OpaqueValue(Array(bufferPointer))
|
|
}
|
|
expectType(Optional<OpaqueValue<Array<OpaqueValue<Int>>>>.self, &result)
|
|
expectEqualSequence(test.sequence, result!.value.map { $0.value })
|
|
expectEqualSequence(test.sequence, a.map { $0.value })
|
|
}
|
|
if true {
|
|
// Read and write.
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Array<OpaqueValue<Int>>> in
|
|
let bufferPointer =
|
|
UnsafeMutableBufferPointer(start: baseAddress, count: count)
|
|
let result = OpaqueValue(Array(bufferPointer))
|
|
for i in bufferPointer.indices {
|
|
bufferPointer[i] = OpaqueValue(bufferPointer[i].value * 10)
|
|
}
|
|
return result
|
|
}
|
|
expectType(Optional<OpaqueValue<Array<OpaqueValue<Int>>>>.self, &result)
|
|
expectEqualSequence(test.sequence, result!.value.map { $0.value })
|
|
expectEqualSequence(
|
|
test.sequence.map { $0 * 10 },
|
|
a.map { $0.value })
|
|
}
|
|
}
|
|
// FIXME: tests for arrays bridged from Objective-C.
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/1") {
|
|
var a = getFresh${array_type}([ OpaqueValue(10) ])
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Int> in
|
|
// buffer = UnsafeMutableBufferPointer(start: buffer.baseAddress, count: 0)
|
|
// FIXME: does not trap since the buffer is not passed inout.
|
|
// expectCrashLater()
|
|
return OpaqueValue(42)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("${array_type}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/2") {
|
|
var a = getFresh${array_type}([ OpaqueValue(10) ])
|
|
var result = a._withUnsafeMutableBufferPointerIfSupported {
|
|
(baseAddress, count) -> OpaqueValue<Int> in
|
|
// buffer = UnsafeMutableBufferPointer(start: nil, count: 1)
|
|
// FIXME: does not trap since the buffer is not passed inout.
|
|
// expectCrashLater()
|
|
return OpaqueValue(42)
|
|
}
|
|
}
|
|
|
|
//===---
|
|
// Check that iterators traverse a snapshot of the collection.
|
|
//===---
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/store") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var g = arr.iterator()
|
|
arr[0] = 1011
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(g)))
|
|
}
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/append") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var g = arr.iterator()
|
|
arr.append(1040)
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(g)))
|
|
}
|
|
|
|
ArrayTestSuite.test(
|
|
"${array_type}/mutationDoesNotAffectIterator/subscript/replaceRange") {
|
|
var arr: ${array_type}<Int> = [ 1010, 1020, 1030 ]
|
|
var g = arr.iterator()
|
|
arr.replaceRange(1..<3, with: [ 1040, 1050, 1060 ])
|
|
expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(g)))
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// COW tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
func withInoutInt(inout x: Int, body: (inout x: Int) -> Void) {
|
|
body(x: &x)
|
|
}
|
|
|
|
func withInoutT<T>(inout x: T, body: (inout x: T) -> Void) {
|
|
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: ArraySlice<${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
|
|
|
|
// 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._getArrayPropertyIsNative()
|
|
}
|
|
|
|
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.addObject(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
|
|
override func copyWithZone(zone: NSZone) -> AnyObject {
|
|
++CustomImmutableNSArray.timesCopyWithZoneWasCalled
|
|
return self
|
|
}
|
|
|
|
@objc
|
|
override func objectAtIndex(index: Int) -> AnyObject {
|
|
++CustomImmutableNSArray.timesObjectAtIndexWasCalled
|
|
return _data[index]
|
|
}
|
|
|
|
@objc
|
|
override var count: Int {
|
|
++CustomImmutableNSArray.timesCountWasCalled
|
|
return _data.count
|
|
}
|
|
|
|
@objc
|
|
override func countByEnumeratingWithState(
|
|
state: UnsafeMutablePointer<NSFastEnumerationState>,
|
|
objects: AutoreleasingUnsafeMutablePointer<AnyObject?>,
|
|
count: Int
|
|
) -> Int {
|
|
var theState = state.memory
|
|
if theState.state == 0 {
|
|
theState.state = 1
|
|
theState.itemsPtr =
|
|
AutoreleasingUnsafeMutablePointer(_data._baseAddressIfContiguous)
|
|
theState.mutationsPtr = _fastEnumerationStorageMutationsPtr
|
|
state.memory = 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") {
|
|
if true {
|
|
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
|
|
}
|
|
}
|
|
if true {
|
|
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.removeObjectAtIndex(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! Array<TestBridgedValueTy>
|
|
expectTrue(isNativeArray(result))
|
|
|
|
// Delete the value from NSMutableArray.
|
|
expectEqual(20, (nsa[1] as! TestObjCValueTy).value)
|
|
nsa.removeObjectAtIndex(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<AnyObject> = _convertNSArrayToArray(nsa)
|
|
var bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.NSArrayIsCopied") {
|
|
let nsa = NSArray(array: getAsNSArray([ 10, 20, 30 ]))
|
|
var a: Array<TestBridgedValueTy> = _convertNSArrayToArray(nsa)
|
|
var bridgedBack: NSArray = _convertArrayToNSArray(a)
|
|
|
|
expectNotEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, 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, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedFromObjC.Nonverbatim.ImmutableArrayIsCopied") {
|
|
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, Int.self),
|
|
unsafeBitCast(bridgedBack, 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.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, UInt.self)
|
|
|
|
v = a.objectAtIndex(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAtIndex(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), 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>.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, UInt.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UInt.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, UInt.self), unsafeBitCast(copy, 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]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, 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.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UInt.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, UInt.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, 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.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, UInt.self)
|
|
|
|
v = a.objectAtIndex(1)
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a.objectAtIndex(2)
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), 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>.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, UInt.self)
|
|
|
|
v = buffer[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = buffer[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, UInt.self)
|
|
|
|
for i in 0..<3 {
|
|
expectEqual(idValue0, unsafeBitCast(a.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UInt.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, UInt.self), unsafeBitCast(copy, 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]
|
|
expectEqual(10, (v as! TestObjCValueTy).value)
|
|
let idValue0 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, 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.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), UInt.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, UInt.self)
|
|
|
|
v = a[1]
|
|
expectEqual(20, (v as! TestObjCValueTy).value)
|
|
let idValue1 = unsafeBitCast(v, UInt.self)
|
|
|
|
v = a[2]
|
|
expectEqual(30, (v as! TestObjCValueTy).value)
|
|
let idValue2 = unsafeBitCast(v, 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.objectAtIndex(0), UInt.self))
|
|
expectEqual(idValue1, unsafeBitCast(a.objectAtIndex(1), UInt.self))
|
|
expectEqual(idValue2, unsafeBitCast(a.objectAtIndex(2), 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, UInt.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, UInt.self))
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NSArray -> Array -> NSArray bridging tests.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Verbatim.RoundtripThroughSwiftArray") {
|
|
% for (MiddleType, AsCast) in [
|
|
% ('Array<AnyObject>', 'as'),
|
|
% ('Array<TestObjCValueTy>', 'as!'),
|
|
% ]:
|
|
if true {
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a: ${MiddleType} = _convertNSArrayToArray(nsa)
|
|
let bridgedBack = _convertArrayToNSArray(a)
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
if true {
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a = nsa ${AsCast} ${MiddleType}
|
|
let bridgedBack: NSArray = a as NSArray
|
|
|
|
expectEqual(
|
|
unsafeBitCast(nsa, Int.self),
|
|
unsafeBitCast(bridgedBack, Int.self))
|
|
|
|
_fixLifetime(nsa)
|
|
_fixLifetime(a)
|
|
_fixLifetime(bridgedBack)
|
|
}
|
|
% end
|
|
}
|
|
|
|
ArrayTestSuite.test("BridgedToObjC.Nonverbatim.RoundtripThroughSwiftArray") {
|
|
if true {
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a: Array<TestBridgedValueTy> = _convertNSArrayToArray(nsa)
|
|
let bridgedBack = _convertArrayToNSArray(a)
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
}
|
|
if true {
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
let nsa: NSArray = getAsImmutableNSArray([ 10, 20, 30 ])
|
|
let a = nsa as! Array<TestBridgedValueTy>
|
|
let bridgedBack: NSArray = a as NSArray
|
|
expectEqual(3, TestBridgedValueTy.bridgeOperations)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array and EvilCollection that changes its size while we are not looking
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
let evilBoundsError = "EvilCollection: index out of range"
|
|
|
|
final class EvilCollection : Collection {
|
|
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 iterator() -> CollectionDefaultIterator<EvilCollection> {
|
|
return CollectionDefaultIterator(self)
|
|
}
|
|
}
|
|
|
|
for (step, evilBoundsCheck) in [ (1, true), (-1, false), (-1, true) ] {
|
|
|
|
let message = step < 0 && evilBoundsCheck
|
|
? evilBoundsError
|
|
: "invalid Collection: count differed in successive traversals"
|
|
|
|
let constructionMessage =
|
|
/*_isStdlibInternalChecksEnabled() && !evilBoundsCheck && step <= 0
|
|
? "_UnsafePartiallyInitializedContiguousArrayBuffer has no more capacity"
|
|
:*/ message
|
|
|
|
// The invalid Collection error is a _debugPreconditon that will only fire
|
|
// in a Debug assert configuration.
|
|
let expectedToFail = (step < 0 && evilBoundsCheck) ||
|
|
_isDebugAssertConfiguration()
|
|
|
|
let natureOfEvil = step > 0 ? "Growth" : "Shrinkage"
|
|
let boundsChecked = evilBoundsCheck ? "BoundsChecked" : "NoBoundsCheck"
|
|
let testPrefix = "MemorySafety/\(boundsChecked)/Evil\(natureOfEvil)"
|
|
|
|
let t = ArrayTestSuite.test("\(testPrefix)/Infrastructure")
|
|
(evilBoundsCheck && _isDebugAssertConfiguration()
|
|
? t.crashOutputMatches(evilBoundsError) : t)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
let count0 = evil.count
|
|
let count1 = evil.count
|
|
expectNotEqual(count0, count1)
|
|
if step > 0 {
|
|
expectLE(count0, count1)
|
|
}
|
|
else {
|
|
expectGE(count0, count1)
|
|
}
|
|
if evilBoundsCheck {
|
|
expectCrashLater()
|
|
}
|
|
let x = evil[-1]
|
|
_blackHole(x)
|
|
}
|
|
|
|
let t2 = ArrayTestSuite.test("\(testPrefix)/Construction")
|
|
(_isDebugAssertConfiguration() && expectedToFail
|
|
? t2.crashOutputMatches(constructionMessage) : t2)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = Array(evil)
|
|
_blackHole(a)
|
|
}
|
|
|
|
for (op, rangeMax) in ["Grow":0, "Shrink":200] {
|
|
let t3 = ArrayTestSuite.test("\(testPrefix)/replaceRange/\(op)Unique")
|
|
(_isDebugAssertConfiguration() ? t3.crashOutputMatches(message) : t3)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { TestValueTy($0) })
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceRange(0..<rangeMax, with: evil)
|
|
}
|
|
|
|
let t4 = ArrayTestSuite.test("\(testPrefix)/replaceRange/\(op)NonUnique")
|
|
(_isDebugAssertConfiguration() ? t4.crashOutputMatches(message) : t4)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { TestValueTy($0) })
|
|
var b = a
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceRange(0..<rangeMax, with: evil)
|
|
_fixLifetime(b)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/SequenceMap")
|
|
.skip(.Custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if step < 0 {
|
|
expectCrashLater()
|
|
}
|
|
let a = AnySequence(evil).map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/CollectionMap")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = evil.map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterAll")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in true }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterNone")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in false }
|
|
_blackHole(a)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Special cases and one-off tests.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% for array_type in all_array_types:
|
|
|
|
ArrayTestSuite.test("${array_type}<Void>/map") {
|
|
// This code used to crash because it generated an array of Void with
|
|
// stride == 0.
|
|
if true {
|
|
let input: ${array_type}<Void> = [ (), (), () ]
|
|
let result = input.map { (_) -> Void in return () }
|
|
expectEqual(3, result.count)
|
|
}
|
|
|
|
if true {
|
|
let input: ${array_type}<OpaqueValue<Int>> = [
|
|
OpaqueValue(10), OpaqueValue(20), OpaqueValue(30)
|
|
]
|
|
let result = input.map { (_) -> Void in return () }
|
|
expectEqual(3, result.count)
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
ArrayTestSuite.setUp {
|
|
resetLeaksOfDictionaryKeysValues()
|
|
TestBridgedValueTy.bridgeOperations = 0
|
|
}
|
|
|
|
ArrayTestSuite.tearDown {
|
|
if _isDebugAssertConfiguration() {
|
|
// The return autorelease optimization does not happen reliable.
|
|
expectNoLeaksOfDictionaryKeysValues()
|
|
}
|
|
}
|
|
|
|
runAllTests()
|
|
|