| % # This template was extracted from the Arrays.swift.gyb in order to split |
| % # that file into multiple to parallelize test execution. |
| % |
| % # Template caller should define the following context: |
| % # - Suite -- an identifier for the test suite to append tests to. |
| % # - ArrayType -- the type being tested. |
| |
| |
| extension ${ArrayType} { |
| typealias _BufferID = UnsafeRawPointer? |
| var _bufferID: _BufferID { |
| return unsafeBitCast(_owner, to: _BufferID.self) |
| } |
| } |
| |
| protocol TestProtocol1 {} |
| |
| extension ${ArrayType} where Element : TestProtocol1 { |
| var _elementIsTestProtocol1: Bool { |
| fatalError("not implemented") |
| } |
| } |
| |
| /// Returns an ${ArrayType} that does not share its buffer with other arrays. |
| func getFresh${ArrayType}<S : Sequence>(_ sequence: S) |
| -> ${ArrayType}<S.Iterator.Element> { |
| var result: ${ArrayType}<S.Iterator.Element> = [] |
| result.reserveCapacity(sequence.underestimatedCount) |
| for element in sequence { |
| result.append(element) |
| } |
| return result |
| } |
| |
| struct SequenceWithCustomUnderestimatedCount : Sequence { |
| init(_ data: [Int]) { |
| self._data = MinimalSequence(elements: data.map(OpaqueValue.init)) |
| } |
| |
| func makeIterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator { |
| return _data.makeIterator() |
| } |
| |
| var underestimatedCount: Int { |
| SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled += 1 |
| return _data.underestimatedCount |
| } |
| |
| static var timesUnderestimatedCountWasCalled: Int = 0 |
| |
| let _data: MinimalSequence<OpaqueValue<Int>> |
| } |
| |
| ${Suite}.test("${ArrayType}/init(Sequence)") { |
| let base = SequenceWithCustomUnderestimatedCount( |
| [ 0, 30, 10, 90 ]) |
| |
| SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled = 0 |
| |
| let result = ${ArrayType}(base) |
| |
| expectEqual([ 0, 30, 10, 90 ], result.map { $0.value }) |
| |
| expectEqual(1, SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled) |
| |
| expectEqualSequence( |
| [], Array(base).map { $0.value }, "sequence should be consumed") |
| } |
| |
| 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 |
| } |
| } |
| |
| ${Suite}.test("${ArrayType}/Sliceable/Enums") { |
| typealias E = EnumWithoutPayloads |
| |
| do { |
| let expected = [E.A, E.B, E.C, E.D] |
| let sliceable = ${ArrayType}(expected) |
| checkBidirectionalCollection(expected, sliceable) |
| } |
| |
| /* |
| FIXME: add this test when Array<T> can be conditionally Equatable. |
| do { |
| let expected = [[E.A, E.B], [E.B, E.C], [E.D], [E.A, E.B, E.D]] |
| let sliceable = ${ArrayType}(expected) |
| checkBidirectionalCollection( |
| expected, sliceable, SourceLocStack().withCurrentLoc()) |
| } |
| */ |
| } |
| |
| ${Suite}.test("${ArrayType}/appendNonUnique") { |
| var x: ${ArrayType}<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.remove(at: 0) |
| } |
| } |
| |
| ${Suite}.test("${ArrayType}/appendUndercountedCollection") { |
| // test that the array safely handles a |
| // collection that understates its count |
| var i = 0 |
| let l = repeatElement(42, count: 10_000).lazy |
| // capture i by reference and change behavior |
| // between first pass (for count) and second |
| .filter { _ in i += 1; return i > 10_000 } |
| var a: ${ArrayType}<Int> = [] |
| a.append(contentsOf: l) |
| } |
| |
| ${Suite}.test("${ArrayType}/emptyAllocation") { |
| let arr0 = ${ArrayType}<Int>() |
| let arr1 = ${ArrayType}<LifetimeTracked>(repeating: LifetimeTracked(0), count: 0) |
| // Empty arrays all use the same buffer |
| expectEqual(arr0._bufferID, arr1._bufferID) |
| |
| let arr2: ${ArrayType}<LifetimeTracked> = [] |
| let emptyLiteralsShareBuffer = arr0._bufferID == arr2._bufferID |
| expectTrue(emptyLiteralsShareBuffer) |
| } |
| |
| ${Suite}.test("${ArrayType}/filter") { |
| do { |
| let arr: ${ArrayType}<Int> = [] |
| var result = arr.filter() { |
| (x: Int) -> Bool in |
| expectUnreachable() |
| return true |
| } |
| expectType(Array<Int>.self, &result) |
| expectEqual([], result) |
| expectEqual(0, result.capacity) |
| } |
| do { |
| let arr: ${ArrayType}<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) |
| } |
| do { |
| let arr: ${ArrayType}<Int> = [ 0, 30, 10, 90 ] |
| let result = arr.filter() { (x: Int) -> Bool in false } |
| expectEqual([], result) |
| expectGE(2 * result.count, result.capacity) |
| } |
| do { |
| let arr: ${ArrayType}<Int> = [ 0, 30, 10, 90 ] |
| let result = arr.filter() { $0 % 3 == 0 } |
| expectEqual([ 0, 30, 90 ], result) |
| expectGE(2 * result.count, result.capacity) |
| } |
| } |
| |
| ${Suite}.test("${ArrayType}/map") { |
| do { |
| let arr: ${ArrayType}<Int> = [] |
| var result = arr.map() { |
| (x: Int) -> Int16 in |
| expectUnreachable() |
| return 42 |
| } |
| expectType(Array<Int16>.self, &result) |
| expectEqual([], result) |
| expectEqual(0, result.capacity) |
| } |
| do { |
| let arr: ${ArrayType}<Int> = [ 0, 30, 10, 90 ] |
| let result = arr.map() { $0 + 1 } |
| expectEqual([ 1, 31, 11, 91 ], result) |
| expectGE(2 * result.count, result.capacity) |
| } |
| } |
| |
| ${Suite}.test("${ArrayType}/flatMap") { |
| let enumerate : (Int) -> ${ArrayType}<Int> = |
| { return ${ArrayType}(1..<($0 + 1)) } |
| expectEqualSequence([], ${ArrayType}().flatMap(enumerate)) |
| expectEqualSequence([ 1 ], ${ArrayType}([ 1 ]).flatMap(enumerate)) |
| expectEqualSequence( |
| [ 1, 1, 2 ], |
| ${ArrayType}([ 1, 2 ]).flatMap(enumerate)) |
| expectEqualSequence( |
| [ 1, 1, 1, 2 ], |
| ${ArrayType}([ 1, 2 ]).flatMap(enumerate).flatMap(enumerate)) |
| } |
| |
| ${Suite}.test("${ArrayType}/Mirror") { |
| do { |
| let input: ${ArrayType}<Int> = [] |
| var output = "" |
| dump(input, to: &output) |
| |
| let expected = |
| "- 0 elements\n" |
| |
| expectEqual(expected, output) |
| } |
| do { |
| let input: ${ArrayType}<Int> = [ 10, 20, 30, 40 ] |
| var output = "" |
| dump(input, to: &output) |
| |
| let expected = |
| "â–¿ 4 elements\n" + |
| " - 10\n" + |
| " - 20\n" + |
| " - 30\n" + |
| " - 40\n" |
| |
| expectEqual(expected, output) |
| } |
| % if ArrayType == 'ArraySlice': |
| do { |
| let base = [ 10, 20, 30, 40 ] |
| let input: ArraySlice<Int> = base[1..<3] |
| var output = "" |
| dump(input, to: &output) |
| |
| let expected = |
| "â–¿ 2 elements\n" + |
| " - 20\n" + |
| " - 30\n" |
| |
| expectEqual(expected, output) |
| } |
| % end |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // _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 ]), |
| ] |
| |
| ${Suite}.test("${ArrayType}/_withUnsafeMutableBufferPointerIfSupported") { |
| for test in withUnsafeMutableBufferPointerIfSupportedTests { |
| var a = getFresh${ArrayType}(test.sequence.map(OpaqueValue.init)) |
| do { |
| // 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 }) |
| } |
| do { |
| // 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. |
| } |
| |
| ${Suite}.test("${ArrayType}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/1") { |
| var a = getFresh${ArrayType}([ 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) |
| } |
| } |
| |
| ${Suite}.test("${ArrayType}/_withUnsafeMutableBufferPointerIfSupported/ReplacingTheBufferTraps/2") { |
| var a = getFresh${ArrayType}([ 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) |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // withUnsafeMutableBytes |
| //===----------------------------------------------------------------------===// |
| |
| // Test the uniqueness of the raw buffer. |
| ${Suite}.test("${ArrayType}/withUnsafeMutableBytes") { |
| var a = getFresh${ArrayType}([UInt8](repeating: 10, count: 1)) |
| let b = a |
| a.withUnsafeMutableBytes { bytes in |
| bytes[0] = 42 |
| } |
| expectEqual(42, a[0]) |
| expectEqual(10, b[0]) |
| } |
| |
| //===--- |
| // Check that iterators traverse a snapshot of the collection. |
| //===--- |
| |
| ${Suite}.test( |
| "${ArrayType}/mutationDoesNotAffectIterator/subscript/store") { |
| var arr: ${ArrayType}<Int> = [ 1010, 1020, 1030 ] |
| var iter = arr.makeIterator() |
| arr[0] = 1011 |
| expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter))) |
| } |
| |
| ${Suite}.test( |
| "${ArrayType}/mutationDoesNotAffectIterator/subscript/append") { |
| var arr: ${ArrayType}<Int> = [ 1010, 1020, 1030 ] |
| var iter = arr.makeIterator() |
| arr.append(1040) |
| expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter))) |
| } |
| |
| ${Suite}.test( |
| "${ArrayType}/mutationDoesNotAffectIterator/subscript/replaceSubrange") { |
| var arr: ${ArrayType}<Int> = [ 1010, 1020, 1030 ] |
| var iter = arr.makeIterator() |
| arr.replaceSubrange(1..<3, with: [ 1040, 1050, 1060 ]) |
| expectEqual([ 1010, 1020, 1030 ], Array(IteratorSequence(iter))) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Special cases and one-off tests. |
| //===----------------------------------------------------------------------===// |
| |
| ${Suite}.test("${ArrayType}<Void>/map") { |
| // This code used to crash because it generated an array of Void with |
| // stride == 0. |
| do { |
| let input: ${ArrayType}<Void> = [ (), (), () ] |
| let result = input.map { (_) -> Void in return () } |
| expectEqual(3, result.count) |
| } |
| |
| do { |
| let input: ${ArrayType}<OpaqueValue<Int>> = [ |
| OpaqueValue(10), OpaqueValue(20), OpaqueValue(30) |
| ] |
| let result = input.map { (_) -> Void in return () } |
| expectEqual(3, result.count) |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // MutableCollectionType and RangeReplaceableCollectionType conformance tests. |
| //===----------------------------------------------------------------------===// |
| |
| ${Suite}.test("${ArrayType}/AssociatedTypes") { |
| typealias Collection = ${ArrayType}<OpaqueValue<Int>> |
| typealias CollectionSlice = ArraySlice<OpaqueValue<Int>> |
| expectCollectionAssociatedTypes( |
| collectionType: Collection.self, |
| iteratorType: IndexingIterator<Collection>.self, |
| subSequenceType: CollectionSlice.self, |
| indexType: Int.self, |
| indexDistanceType: Int.self, |
| indicesType: CountableRange<Int>.self) |
| } |