// RUN: %target-run-simple-swiftgyb // REQUIRES: executable_test import StdlibUnittest import StdlibCollectionUnittest let CopyToNativeArrayBufferTests = TestSuite("CopyToNativeArrayBufferTests") CopyToNativeArrayBufferTests.test("Sequence._copyToContiguousArray()") { do { // Call from a static context. let s = MinimalSequence(elements: LifetimeTracked(10)..() let popped = a.popLast() expectNil(popped) expectTrue(a.isEmpty) } do { var popped = [Int]() var a: ${Kind} = [1010, 2020, 3030] while let element = a.popLast() { popped.append(element) } expectEqualSequence([1010, 2020, 3030], popped.reversed()) expectTrue(a.isEmpty) } } % end // Check how append affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/append") { do { var a: ${Kind}> = ${Kind}([ 2 ].map(OpaqueValue.init)) let v = OpaqueValue(1) a.append(v) expectEqual(0, a.startIndex) expectEqual(2, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 2 ].map(OpaqueValue.init)) let v = OpaqueValue(1) a.append(v) expectEqual(0, a.startIndex) expectEqual(2, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/append") .xfail(.custom({true}, reason: "")).code { do { let a: [OpaqueValue] = [ 42, 2525, 3535, 42 ].map(OpaqueValue.init) var s = a[1..<2] let v = OpaqueValue(1515) s.append(v) expectEqual(1, s.startIndex) expectEqual(3, s.endIndex) } } // Check how insert(_:at:) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/insert") { do { var a: ${Kind}> = ${Kind}([ 2 ].map(OpaqueValue.init)) let v = OpaqueValue(1) a.insert(v, at: 0) expectEqual(0, a.startIndex) expectEqual(2, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 2 ].map(OpaqueValue.init)) let v = OpaqueValue(1) a.insert(v, at: 1) expectEqual(0, a.startIndex) expectEqual(2, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/insert") { do { let a: [OpaqueValue] = [ 42, 2525, 3535, 42 ].map(OpaqueValue.init) var s = a[1..<2] let v = OpaqueValue(1515) s.insert(v, at: 1) expectEqual(1, s.startIndex) expectEqual(3, s.endIndex) } } // Check how partition(by:) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/partition") { do { var a: ${Kind}> = ${Kind}([ 10, 2, -33, 44, -5 ].map(OpaqueValue.init)) a.partition(by: { $0.value > 0 }) expectEqual(0, a.startIndex) expectEqual(5, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 10, 2, -33, 44, -5 ].map(OpaqueValue.init)) a.partition(by: { $0.value > 100 }) expectEqual(0, a.startIndex) expectEqual(5, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 10, 2, -33, 44, -5 ].map(OpaqueValue.init)) a.partition(by: { $0.value > 100 }) expectEqual(0, a.startIndex) expectEqual(5, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/partition") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeFirst() expectEqual(2, s.startIndex) expectEqual(2, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeFirst() expectEqual(2, s.startIndex) expectEqual(3, s.endIndex) } } // Check how removeLast() affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeLast") { do { var a: ${Kind}> = ${Kind}([ 1 ].map(OpaqueValue.init)) a.removeLast() expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeLast() expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeLast") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeLast() expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeLast() expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } } // Check how remove(at:) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/remove(at:)") { do { var a: ${Kind}> = ${Kind}([ 1 ].map(OpaqueValue.init)) a.remove(at: 0) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.remove(at: 1) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/remove(at:)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.remove(at: 1) expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.remove(at: 1) expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } } // Check how removeAll(keepingCapacity:) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeAll(keepingCapacity:)") { do { var a: ${Kind}> = ${Kind}([ 1, 2, 3, ].map(OpaqueValue.init)) a.removeAll(keepingCapacity: true) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeAll(keepingCapacity: false) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeAll(keepingCapacity:)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeAll(keepingCapacity: true) expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeAll(keepingCapacity: false) expectEqual(0, s.endIndex) expectEqual(0, s.endIndex) } } // Check how removeFirst() affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeFirst") { do { var a: ${Kind}> = ${Kind}([ 1 ].map(OpaqueValue.init)) a.removeFirst() expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeFirst() expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeFirst") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeFirst() expectEqual(2, s.startIndex) expectEqual(2, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeFirst() expectEqual(2, s.startIndex) expectEqual(3, s.endIndex) } } // Check how removeFirst(_:) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeFirst(_:)") { do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeFirst(2) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3, 4 ].map(OpaqueValue.init)) a.removeFirst(2) expectEqual(0, a.startIndex) expectEqual(2, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeFirst(_:)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1...2] s.removeFirst(2) expectEqual(3, s.startIndex) expectEqual(3, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1...3] s.removeFirst(2) expectEqual(3, s.startIndex) expectEqual(4, s.endIndex) } } // Check how removeLast() affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeLast") { do { var a: ${Kind}> = ${Kind}([ 1 ].map(OpaqueValue.init)) a.removeLast() expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeLast() expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeLast") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeLast() expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeLast() expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } } // Check how removeSubrange(_:ClosedRange) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeSubrange(_:ClosedRange)") { do { var a: ${Kind}> = ${Kind}([ 1 ].map(OpaqueValue.init)) a.removeSubrange(0..<1) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(0..<2) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(1..<3) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeSubrange(_:ClosedRange)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<2] s.removeSubrange(1..<2) expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeLast() expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } } // Check how removeSubrange(_:Range) affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeSubrange(_:Range)") { do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeSubrange(0...1) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(0...1) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(1...2) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeSubrange(_:Range)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeSubrange(1...2) expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99, 44 ].map(OpaqueValue.init) var s = a[1..<4] s.removeSubrange(2...3) expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99, 44 ].map(OpaqueValue.init) var s = a[1..<4] s.removeSubrange(1...2) expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } } // Check how filter() affects indices. % for Kind in ['Array', 'ContiguousArray']: ArrayTestSuite.test("${Kind}/removeSubrange(_:Range)") { do { var a: ${Kind}> = ${Kind}([ 1, 2 ].map(OpaqueValue.init)) a.removeSubrange(0...1) expectEqual(0, a.startIndex) expectEqual(0, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(0...1) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } do { var a: ${Kind}> = ${Kind}([ 1, 2, 3 ].map(OpaqueValue.init)) a.removeSubrange(1...2) expectEqual(0, a.startIndex) expectEqual(1, a.endIndex) } } % end ArrayTestSuite.test("ArraySlice/removeSubrange(_:Range)") { do { let a: [OpaqueValue] = [ 99, 1010, 99 ].map(OpaqueValue.init) var s = a[1..<3] s.removeSubrange(1...2) expectEqual(1, s.startIndex) expectEqual(1, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99, 44 ].map(OpaqueValue.init) var s = a[1..<4] s.removeSubrange(2...3) expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } do { let a: [OpaqueValue] = [ 99, 1010, 2020, 99, 44 ].map(OpaqueValue.init) var s = a[1..<4] s.removeSubrange(1...2) expectEqual(1, s.startIndex) expectEqual(2, s.endIndex) } } //===----------------------------------------------------------------------===// // Array and EvilCollection that changes its size while we are not looking //===----------------------------------------------------------------------===// let evilBoundsError = "EvilCollection: index out of range" final class EvilSequence : Sequence { init(_ growth: Int) { self.growth = growth } var growth: Int var _count: Int = 20 var underestimatedCount: Int { defer { _count += growth } return _count } func makeIterator() -> AnyIterator { var i = 0 return AnyIterator { if i >= self._count { return nil } let result = LifetimeTracked(i) i += 1 return result } } } final class EvilCollection : Collection { func index(after i: Int) -> Int { return i + 1 } 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) -> LifetimeTracked { if boundsChecked { precondition(i >= 0 && i < _count, evilBoundsError) } return LifetimeTracked(i) } // Default implementation will call _failEarlyRangeCheck, // passing in a startIndex that will grow _count faster than // necessary. func formIndex(after i: inout Int) { i += 1 } } 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)" ArrayTestSuite.test("\(testPrefix)/Infrastructure/EvilSequence") { let evil = EvilSequence(step) let count0 = evil.underestimatedCount let count1 = evil.underestimatedCount expectNotEqual(count0, count1) if step > 0 { expectLE(count0, count1) } else { expectGE(count0, count1) } } let t1 = ArrayTestSuite.test("\(testPrefix)/Infrastructure/EvilCollection") (evilBoundsCheck && _isDebugAssertConfiguration() ? t1.crashOutputMatches(evilBoundsError) : t1) .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)/replaceSubrange/\(op)Unique") (_isDebugAssertConfiguration() ? t3.crashOutputMatches(message) : t3) .code { let evil = EvilCollection(step, boundsChecked: evilBoundsCheck) var a = Array((0..<200).lazy.map { LifetimeTracked($0) }) if expectedToFail { expectCrashLater() } a.replaceSubrange(0..