| // RUN: %target-run-simple-swiftgyb |
| // REQUIRES: executable_test |
| |
| import StdlibUnittest |
| import StdlibCollectionUnittest |
| |
| // Tests |
| |
| struct SubscriptGetTest { |
| // SubscriptGetTest operates on a `(end - start)` sized buffer containing |
| // monotonically increasing integers from `start` to `end - 1`. |
| static let start = 0 |
| static let end = 20 |
| let rangeSelection: RangeSelection |
| /// The values that should be expected by slicing the UBP, or `nil` if the |
| /// test is expected to crash. |
| let expectedValues: [Int]? |
| /// Same as `expectedValues`, but for closed ranges. `nil` if no difference. |
| let expectedClosedValues: [Int]? |
| let loc: SourceLoc |
| |
| static var elementCount = (end - start) |
| |
| % for SelfType in ['UnsafeBufferPointer', 'UnsafeMutableBufferPointer']: |
| /// Create and populate an `${SelfType}` for use with unit tests. |
| /// PRECONDITION: `memory` must be allocated with space for |
| /// `SubscriptGetTest.elementCount` elements. |
| func create${SelfType}(from memory: UnsafeMutablePointer<OpaqueValue<Int>>) |
| -> ${SelfType}<OpaqueValue<Int>> |
| { |
| for i in SubscriptGetTest.start..<SubscriptGetTest.end { |
| memory[i] = OpaqueValue(i) |
| } |
| return ${SelfType}(start: memory, count: SubscriptGetTest.elementCount) |
| } |
| % end |
| |
| init( |
| rangeSelection: RangeSelection, expectedValues: [Int]? = nil, |
| expectedClosedValues: [Int]? = nil, |
| file: String = #file, line: UInt = #line |
| ) { |
| self.rangeSelection = rangeSelection |
| self.expectedValues = expectedValues |
| self.expectedClosedValues = expectedClosedValues ?? expectedValues |
| self.loc = SourceLoc(file, line, comment: "test data") |
| } |
| } |
| |
| let subscriptGetTests : [SubscriptGetTest] = [ |
| // Valid, empty. |
| SubscriptGetTest(rangeSelection: .emptyRange, expectedValues: []), |
| |
| // Valid, edges. |
| SubscriptGetTest(rangeSelection: .leftEdge, |
| expectedValues: [], |
| expectedClosedValues: [0]), |
| SubscriptGetTest(rangeSelection: .rightEdge, |
| expectedValues: [], |
| expectedClosedValues: [19]), |
| |
| // Valid, internal. |
| SubscriptGetTest(rangeSelection: .leftHalf, |
| expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), |
| SubscriptGetTest(rangeSelection: .rightHalf, |
| expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), |
| SubscriptGetTest(rangeSelection: .middle, |
| expectedValues: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), |
| SubscriptGetTest(rangeSelection: .full, |
| expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), |
| SubscriptGetTest(rangeSelection: .offsets(2, 4), |
| expectedValues: [2, 3], |
| expectedClosedValues: [2, 3, 4]), |
| SubscriptGetTest(rangeSelection: .offsets(16, 19), |
| expectedValues: [16, 17, 18], |
| expectedClosedValues: [16, 17, 18, 19]), |
| |
| // Invalid, bottom out of bounds. |
| SubscriptGetTest(rangeSelection: .offsets(-1, -1)), |
| SubscriptGetTest(rangeSelection: .offsets(-1, 0)), |
| SubscriptGetTest(rangeSelection: .offsets(-100, 5)), |
| |
| // Invalid, top out of bounds. |
| SubscriptGetTest(rangeSelection: .offsets(20, 20)), |
| SubscriptGetTest(rangeSelection: .offsets(19, 20)), |
| SubscriptGetTest(rangeSelection: .offsets(5, 100)), |
| |
| // Invalid, both out of bounds. |
| SubscriptGetTest(rangeSelection: .offsets(-1, 20)), |
| SubscriptGetTest(rangeSelection: .offsets(-100, 100)), |
| ] |
| |
| struct SubscriptSetTest { |
| // SubscriptSetTest operates on a `(end - start)` sized buffer containing |
| // monotonically increasing integers from `start` to `end - 1`. |
| static let start = 0 |
| static let end = 10 |
| |
| let rangeSelection: RangeSelection |
| |
| let replacementValues: [OpaqueValue<Int>] |
| let replacementValuesClosed: [OpaqueValue<Int>] |
| |
| /// The values that should be expected by slicing the UBP, or `nil` if the |
| /// test is expected to crash. |
| let expectedValues: [Int]? |
| let expectedValuesClosed: [Int]? |
| |
| let loc: SourceLoc |
| |
| static var elementCount = (end - start) |
| |
| /// Create and populate an `UnsafeMutableBufferPointer` for use with unit |
| /// tests. |
| /// PRECONDITION: `memory` must be allocated with space for |
| /// `SubscriptSetTest.elementCount` elements. |
| func createUnsafeMutableBufferPointer( |
| from memory: UnsafeMutablePointer<OpaqueValue<Int>> |
| ) -> UnsafeMutableBufferPointer<OpaqueValue<Int>> |
| { |
| for i in SubscriptSetTest.start..<SubscriptSetTest.end { |
| memory[i] = OpaqueValue(i) |
| } |
| return UnsafeMutableBufferPointer( |
| start: memory, |
| count: SubscriptSetTest.elementCount) |
| } |
| |
| /// Create and populate a mutable buffer pointer slice for use with unit |
| /// tests. |
| /// PRECONDITION: `memory` must be allocated with space for |
| /// `replacementValues.count` elements. |
| func replacementValuesSlice( |
| from memory: UnsafeMutablePointer<OpaqueValue<Int>>, |
| replacementValues: [OpaqueValue<Int>] |
| ) -> MutableRandomAccessSlice<UnsafeMutableBufferPointer<OpaqueValue<Int>>> |
| { |
| for (i, value) in replacementValues.enumerated() { |
| memory[i] = value |
| } |
| let buffer = UnsafeMutableBufferPointer( |
| start: memory, |
| count: replacementValues.count) |
| let fullRange = RangeSelection.full.range(in: buffer) |
| return buffer[fullRange] |
| } |
| |
| init( |
| rangeSelection: RangeSelection, |
| replacementValues: [Int], |
| replacementValuesClosed: [Int]? = nil, |
| expectedValues: [Int]? = nil, |
| expectedValuesClosed: [Int]? = nil, |
| file: String = #file, line: UInt = #line |
| ) { |
| self.rangeSelection = rangeSelection |
| self.replacementValues = replacementValues.map { OpaqueValue($0) } |
| if let replacements = replacementValuesClosed { |
| self.replacementValuesClosed = replacements.map { OpaqueValue($0) } |
| } else { |
| self.replacementValuesClosed = self.replacementValues |
| } |
| self.expectedValues = expectedValues |
| self.expectedValuesClosed = expectedValuesClosed ?? expectedValues |
| self.loc = SourceLoc(file, line, comment: "test data") |
| } |
| } |
| |
| let subscriptSetTests : [SubscriptSetTest] = [ |
| // Valid, empty. |
| SubscriptSetTest( |
| rangeSelection: .emptyRange, |
| replacementValues: [], |
| expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), |
| |
| // Valid, edges. |
| SubscriptSetTest( |
| rangeSelection: .leftEdge, |
| replacementValues: [], |
| replacementValuesClosed: [9001], |
| expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], |
| expectedValuesClosed: [9001, 1, 2, 3, 4, 5, 6, 7, 8, 9]), |
| SubscriptSetTest( |
| rangeSelection: .rightEdge, |
| replacementValues: [], |
| replacementValuesClosed: [9001], |
| expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], |
| expectedValuesClosed: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9001]), |
| |
| // Valid, internal. |
| SubscriptSetTest( |
| rangeSelection: .leftHalf, |
| replacementValues: [10, 11, 12, 13, 14], |
| expectedValues: [10, 11, 12, 13, 14, 5, 6, 7, 8, 9]), |
| SubscriptSetTest( |
| rangeSelection: .rightHalf, |
| replacementValues: [10, 11, 12, 13, 14], |
| expectedValues: [0, 1, 2, 3, 4, 10, 11, 12, 13, 14]), |
| SubscriptSetTest( |
| rangeSelection: .middle, |
| replacementValues: [10, 11, 12, 13, 14, 15], |
| expectedValues: [0, 1, 10, 11, 12, 13, 14, 15, 8, 9]), |
| SubscriptSetTest( |
| rangeSelection: .full, |
| replacementValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], |
| expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), |
| |
| // Invalid, range and replacement count mismatch. |
| SubscriptSetTest( |
| rangeSelection: .leftEdge, |
| replacementValues: [], |
| replacementValuesClosed: [9]), |
| SubscriptSetTest( |
| rangeSelection: .leftEdge, |
| replacementValues: [9, 9], |
| replacementValuesClosed: [9, 9, 9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(1, 2), |
| replacementValues: [], |
| replacementValuesClosed: [9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(1, 2), |
| replacementValues: [9, 9], |
| replacementValuesClosed: [9, 9, 9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(2, 5), |
| replacementValues: [9, 9], |
| replacementValuesClosed: [9, 9, 9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(2, 5), |
| replacementValues: [9, 9, 9, 9], |
| replacementValuesClosed: [9, 9, 9, 9, 9]), |
| |
| // Invalid, bottom out of bounds. |
| SubscriptSetTest( |
| rangeSelection: .offsets(-1, -1), |
| replacementValues: []), |
| SubscriptSetTest( |
| rangeSelection: .offsets(-1, 0), |
| replacementValues: [9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(-3, 5), |
| replacementValues: [9, 9, 9, 9, 9, 9, 9, 9]), |
| |
| // Invalid, top out of bounds. |
| SubscriptSetTest( |
| rangeSelection: .offsets(10, 10), |
| replacementValues: []), |
| SubscriptSetTest( |
| rangeSelection: .offsets(9, 10), |
| replacementValues: [9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(8, 15), |
| replacementValues: [9, 9, 9, 9, 9, 9, 9]), |
| |
| // Invalid, both out of bounds. |
| SubscriptSetTest( |
| rangeSelection: .offsets(-1, 10), |
| replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]), |
| SubscriptSetTest( |
| rangeSelection: .offsets(-2, 11), |
| replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]), |
| ] |
| |
| |
| // Test Suites |
| |
| var UnsafeBufferPointerTestSuite = TestSuite("UnsafeBufferPointer") |
| var UnsafeMutableBufferPointerTestSuite = TestSuite("UnsafeMutableBufferPointer") |
| |
| % for (SelfName, IsMutable, SelfType, PointerType) in [ |
| % ('UnsafeBufferPointer', False, 'UnsafeBufferPointer<Float>', 'UnsafePointer<Float>'), |
| % ('UnsafeMutableBufferPointer', True, 'UnsafeMutableBufferPointer<Float>', 'UnsafeMutablePointer<Float>') |
| % ]: |
| |
| ${SelfName}TestSuite.test("AssociatedTypes") { |
| typealias Subject = ${SelfName}<OpaqueValue<Int>> |
| expectRandomAccessCollectionAssociatedTypes( |
| collectionType: Subject.self, |
| iteratorType: IndexingIterator<Subject>.self, |
| subSequenceType: ${'Mutable' if IsMutable else ''}RandomAccessSlice<Subject>.self, |
| indexType: Int.self, |
| indexDistanceType: Int.self, |
| indicesType: CountableRange<Int>.self) |
| |
| expect${'Mutable' if IsMutable else ''}CollectionType(Subject.self) |
| } |
| |
| ${SelfName}TestSuite.test("nilBaseAddress") { |
| let emptyBuffer = ${SelfType}(start: nil, count: 0) |
| expectEmpty(emptyBuffer.baseAddress) |
| expectEqual(0, emptyBuffer.count) |
| expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex) |
| |
| var iter = emptyBuffer.makeIterator() |
| expectEmpty(iter.next()) |
| |
| expectEqualSequence([], emptyBuffer) |
| } |
| |
| ${SelfName}TestSuite.test("nonNilButEmpty") { |
| let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0) |
| defer { emptyAllocated.deallocate(capacity: 0) } |
| |
| let emptyBuffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: 0) |
| expectEqual(emptyAllocated, emptyBuffer.baseAddress) |
| expectEqual(0, emptyBuffer.count) |
| expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex) |
| |
| var iter = emptyBuffer.makeIterator() |
| expectEmpty(iter.next()) |
| |
| expectEqualSequence([], emptyBuffer) |
| } |
| |
| ${SelfName}TestSuite.test("nonNilNonEmpty") { |
| let count = 4 |
| let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count) |
| defer { allocated.deallocate(capacity: count) } |
| allocated.initialize(to: 1.0, count: count) |
| allocated[count - 1] = 2.0 |
| |
| let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1) |
| expectEqual(allocated, buffer.baseAddress) |
| expectEqual(count - 1, buffer.count) |
| expectEqual(count - 1, buffer.endIndex - buffer.startIndex) |
| |
| allocated[1] = 0.0 |
| expectEqual(1.0, buffer[0]) |
| expectEqual(0.0, buffer[1]) |
| expectEqual(1.0, buffer[2]) |
| |
| var iter = buffer.makeIterator() |
| expectEqual(1.0, iter.next()) |
| expectEqual(0.0, iter.next()) |
| expectEqual(1.0, iter.next()) |
| expectEmpty(iter.next()) |
| |
| expectEqualSequence([1.0, 0.0, 1.0], buffer) |
| |
| expectEqual(2.0, allocated[count-1]) |
| } |
| |
| ${SelfName}TestSuite.test("badCount") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .code { |
| expectCrashLater() |
| |
| let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0) |
| defer { emptyAllocated.deallocate(capacity: 0) } |
| |
| let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: -1) |
| _ = buffer |
| } |
| |
| ${SelfName}TestSuite.test("badNilCount") |
| .skip(.custom( |
| { _isFastAssertConfiguration() }, |
| reason: "this trap is not guaranteed to happen in -Ounchecked")) |
| .code { |
| expectCrashLater() |
| |
| let buffer = ${SelfType}(start: nil, count: 1) |
| _ = buffer |
| } |
| |
| % for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']: |
| ${SelfName}TestSuite.test("subscript/${RangeName}/get").forEach(in: subscriptGetTests) { |
| (test) in |
| |
| let expectedValues: [Int]? |
| % if 'closed' in RangeName.lower(): |
| if test.rangeSelection.isEmpty { |
| return |
| } |
| expectedValues = test.expectedClosedValues |
| % else: |
| expectedValues = test.expectedValues |
| % end |
| |
| let elementCount = SubscriptGetTest.elementCount |
| |
| var memory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate(capacity: elementCount) |
| let buffer = test.create${SelfName}(from: memory) |
| defer { memory.deallocate(capacity: elementCount) } |
| |
| let range = test.rangeSelection.${RangeName}(in: buffer) |
| |
| if expectedValues == nil { expectCrashLater() } |
| let slice = buffer[range] |
| expectEqual( |
| expectedValues!, |
| slice.map { $0.value }, |
| stackTrace: SourceLocStack().with(test.loc) |
| ) |
| } |
| % end |
| |
| % end |
| |
| % for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']: |
| UnsafeMutableBufferPointerTestSuite.test("subscript/${RangeName}/set") |
| .forEach(in: subscriptSetTests) { (test) in |
| |
| let expectedValues: [Int]? |
| let replacementValues: [OpaqueValue<Int>] |
| % if 'closed' in RangeName.lower(): |
| if test.rangeSelection.isEmpty { |
| return |
| } |
| expectedValues = test.expectedValuesClosed |
| replacementValues = test.replacementValuesClosed |
| % else: |
| expectedValues = test.expectedValues |
| replacementValues = test.replacementValues |
| % end |
| |
| let elementCount = SubscriptSetTest.elementCount |
| |
| var memory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate( |
| capacity: elementCount) |
| var sliceMemory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate( |
| capacity: replacementValues.count) |
| var buffer = test.createUnsafeMutableBufferPointer(from: memory) |
| defer { |
| memory.deallocate(capacity: elementCount) |
| sliceMemory.deallocate(capacity: replacementValues.count) |
| } |
| |
| let range = test.rangeSelection.${RangeName}(in: buffer) |
| let replacementSlice = test.replacementValuesSlice( |
| from: sliceMemory, |
| replacementValues: replacementValues) |
| |
| if expectedValues == nil { expectCrashLater() } |
| buffer[range] = replacementSlice |
| expectEqual( |
| expectedValues!, |
| buffer.map { $0.value }, |
| stackTrace: SourceLocStack().with(test.loc) |
| ) |
| } |
| % end |
| |
| UnsafeMutableBufferPointerTestSuite.test("changeElementViaBuffer") { |
| let count = 4 |
| let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count) |
| defer { allocated.deallocate(capacity: count) } |
| allocated.initialize(to: 1.0, count: count) |
| allocated[count-1] = -1.0 |
| |
| var buffer = UnsafeMutableBufferPointer(start: allocated, count: count - 1) |
| |
| buffer[1] = 0.0 |
| expectEqual(1.0, buffer[0]) |
| expectEqual(0.0, buffer[1]) |
| expectEqual(1.0, buffer[2]) |
| |
| expectEqual(1.0, allocated[0]) |
| expectEqual(0.0, allocated[1]) |
| expectEqual(1.0, allocated[2]) |
| expectEqual(-1.0, allocated[count-1]) |
| |
| buffer.sort() |
| expectEqual(0.0, buffer[0]) |
| expectEqual(1.0, buffer[1]) |
| expectEqual(1.0, buffer[2]) |
| |
| expectEqual(0.0, allocated[0]) |
| expectEqual(1.0, allocated[1]) |
| expectEqual(1.0, allocated[2]) |
| expectEqual(-1.0, allocated[count-1]) |
| } |
| |
| runAllTests() |