blob: 00843b09b0a2d66b7893fb9cefb6e9bd5f2ee1a5 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import StdlibUnittest
internal var checksAdded: Set<String> = []
public struct SubscriptRangeTest {
public let expected: [OpaqueValue<Int>]
public let collection: [OpaqueValue<Int>]
public let bounds: Range<Int>
public let count: Int
public let loc: SourceLoc
public var isEmpty: Bool { return count == 0 }
public func bounds<C : Collection>(in c: C) -> Range<C.Index> {
let i = c.startIndex
return c.index(i, offsetBy: numericCast(bounds.lowerBound)) ..<
c.index(i, offsetBy: numericCast(bounds.upperBound))
}
public init(
expected: [Int], collection: [Int], bounds: Range<Int>,
count: Int,
file: String = #file, line: UInt = #line
) {
self.expected = expected.map(OpaqueValue.init)
self.collection = collection.map(OpaqueValue.init)
self.bounds = bounds
self.count = count
self.loc = SourceLoc(file, line, comment: "test data")
}
}
public struct PrefixThroughTest {
public var collection: [Int]
public let position: Int
public let expected: [Int]
public let loc: SourceLoc
init(
collection: [Int], position: Int, expected: [Int],
file: String = #file, line: UInt = #line
) {
self.collection = collection
self.position = position
self.expected = expected
self.loc = SourceLoc(file, line, comment: "prefix(through:) test data")
}
}
public struct PrefixUpToTest {
public var collection: [Int]
public let end: Int
public let expected: [Int]
public let loc: SourceLoc
public init(
collection: [Int], end: Int, expected: [Int],
file: String = #file, line: UInt = #line
) {
self.collection = collection
self.end = end
self.expected = expected
self.loc = SourceLoc(file, line, comment: "prefix(upTo:) test data")
}
}
internal struct RemoveFirstNTest {
let collection: [Int]
let numberToRemove: Int
let expectedCollection: [Int]
let loc: SourceLoc
init(
collection: [Int], numberToRemove: Int, expectedCollection: [Int],
file: String = #file, line: UInt = #line
) {
self.collection = collection
self.numberToRemove = numberToRemove
self.expectedCollection = expectedCollection
self.loc = SourceLoc(file, line, comment: "removeFirst(n: Int) test data")
}
}
public struct SuffixFromTest {
public var collection: [Int]
public let start: Int
public let expected: [Int]
public let loc: SourceLoc
init(
collection: [Int], start: Int, expected: [Int],
file: String = #file, line: UInt = #line
) {
self.collection = collection
self.start = start
self.expected = expected
self.loc = SourceLoc(file, line, comment: "suffix(from:) test data")
}
}
public let subscriptRangeTests = [
// Slice an empty collection.
SubscriptRangeTest(
expected: [],
collection: [],
bounds: 0..<0,
count: 0),
// Slice to the full extent.
SubscriptRangeTest(
expected: [1010],
collection: [1010],
bounds: 0..<1,
count: 1),
SubscriptRangeTest(
expected: [1010, 2020, 3030],
collection: [1010, 2020, 3030],
bounds: 0..<3,
count: 3),
SubscriptRangeTest(
expected: [1010, 2020, 3030, 4040, 5050],
collection: [1010, 2020, 3030, 4040, 5050],
bounds: 0..<5,
count: 5),
// Slice an empty prefix.
SubscriptRangeTest(
expected: [],
collection: [1010, 2020, 3030],
bounds: 0..<0,
count: 3),
// Slice a prefix.
SubscriptRangeTest(
expected: [1010, 2020],
collection: [1010, 2020, 3030],
bounds: 0..<2,
count: 3),
SubscriptRangeTest(
expected: [1010, 2020],
collection: [1010, 2020, 3030, 4040, 5050],
bounds: 0..<2,
count: 5),
// Slice an empty suffix.
SubscriptRangeTest(
expected: [],
collection: [1010, 2020, 3030],
bounds: 3..<3,
count: 3),
// Slice a suffix.
SubscriptRangeTest(
expected: [2020, 3030],
collection: [1010, 2020, 3030],
bounds: 1..<3,
count: 3),
SubscriptRangeTest(
expected: [4040, 5050],
collection: [1010, 2020, 3030, 4040, 5050],
bounds: 3..<5,
count: 5),
// Slice an empty range in the middle.
SubscriptRangeTest(
expected: [],
collection: [1010, 2020, 3030],
bounds: 1..<1,
count: 3),
SubscriptRangeTest(
expected: [],
collection: [1010, 2020, 3030],
bounds: 2..<2,
count: 3),
// Slice the middle part.
SubscriptRangeTest(
expected: [2020],
collection: [1010, 2020, 3030],
bounds: 1..<2,
count: 3),
SubscriptRangeTest(
expected: [3030],
collection: [1010, 2020, 3030, 4040],
bounds: 2..<3,
count: 4),
SubscriptRangeTest(
expected: [2020, 3030, 4040],
collection: [1010, 2020, 3030, 4040, 5050, 6060],
bounds: 1..<4,
count: 6),
]
public let prefixUpToTests = [
PrefixUpToTest(
collection: [],
end: 0,
expected: []
),
PrefixUpToTest(
collection: [1010, 2020, 3030, 4040, 5050],
end: 3,
expected: [1010, 2020, 3030]
),
PrefixUpToTest(
collection: [1010, 2020, 3030, 4040, 5050],
end: 5,
expected: [1010, 2020, 3030, 4040, 5050]
),
]
public let prefixThroughTests = [
PrefixThroughTest(
collection: [1010, 2020, 3030, 4040, 5050],
position: 0,
expected: [1010]
),
PrefixThroughTest(
collection: [1010, 2020, 3030, 4040, 5050],
position: 2,
expected: [1010, 2020, 3030]
),
PrefixThroughTest(
collection: [1010, 2020, 3030, 4040, 5050],
position: 4,
expected: [1010, 2020, 3030, 4040, 5050]
),
]
public let suffixFromTests = [
SuffixFromTest(
collection: [],
start: 0,
expected: []
),
SuffixFromTest(
collection: [1010, 2020, 3030, 4040, 5050],
start: 0,
expected: [1010, 2020, 3030, 4040, 5050]
),
SuffixFromTest(
collection: [1010, 2020, 3030, 4040, 5050],
start: 3,
expected: [4040, 5050]
),
SuffixFromTest(
collection: [1010, 2020, 3030, 4040, 5050],
start: 5,
expected: []
),
]
let removeFirstTests: [RemoveFirstNTest] = [
RemoveFirstNTest(
collection: [1010],
numberToRemove: 0,
expectedCollection: [1010]
),
RemoveFirstNTest(
collection: [1010],
numberToRemove: 1,
expectedCollection: []
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 0,
expectedCollection: [1010, 2020, 3030, 4040, 5050]
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 1,
expectedCollection: [2020, 3030, 4040, 5050]
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 2,
expectedCollection: [3030, 4040, 5050]
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 3,
expectedCollection: [4040, 5050]
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 4,
expectedCollection: [5050]
),
RemoveFirstNTest(
collection: [1010, 2020, 3030, 4040, 5050],
numberToRemove: 5,
expectedCollection: []
),
]
extension Collection {
public func nthIndex(_ offset: Int) -> Index {
return self.index(self.startIndex, offsetBy: numericCast(offset))
}
}
public struct DistanceFromToTest {
public let startOffset: Int
public let endOffset: Int
public var expectedDistance : Int { return endOffset - startOffset }
public let loc: SourceLoc
public init(
start: Int, end: Int,
file: String = #file, line: UInt = #line
) {
self.startOffset = start
self.endOffset = end
self.loc = SourceLoc(file, line, comment: "distance(from:to:) test data")
}
}
public struct IndexOffsetByTest {
public let startOffset: Int
public let distance: Int
public let limit: Int?
public let expectedOffset: Int?
public let loc: SourceLoc
public init(
startOffset: Int, distance: Int, expectedOffset: Int?,
limitedBy limit: Int? = nil,
file: String = #file, line: UInt = #line
) {
self.startOffset = startOffset
self.distance = distance
self.expectedOffset = expectedOffset
self.limit = limit
self.loc = SourceLoc(file, line, comment: "index(_:offsetBy:) test data")
}
}
public let distanceFromToTests = [
// 0 - 1: no distance.
DistanceFromToTest(start: 0, end: 0),
DistanceFromToTest(start: 10, end: 10),
// 2 - 3: forward distance.
DistanceFromToTest(start: 10, end: 13),
DistanceFromToTest(start: 7, end: 10),
// 4 - 6: backward distance.
DistanceFromToTest(start: 12, end: 4),
DistanceFromToTest(start: 8, end: 2),
DistanceFromToTest(start: 19, end: 0)
]
public let indexOffsetByTests = [
IndexOffsetByTest(startOffset: 0, distance: 0, expectedOffset: 0),
IndexOffsetByTest(startOffset: 7, distance: 0, expectedOffset: 7),
IndexOffsetByTest(startOffset: 0, distance: -1, expectedOffset: -1),
IndexOffsetByTest(startOffset: 4, distance: -9, expectedOffset: -5),
IndexOffsetByTest(startOffset: 8, distance: -2, expectedOffset: 6),
IndexOffsetByTest(startOffset: 4, distance: -4, expectedOffset: 0),
IndexOffsetByTest(startOffset: 3, distance: 12, expectedOffset: 15),
IndexOffsetByTest(startOffset: 9, distance: 1, expectedOffset: 10),
IndexOffsetByTest(startOffset: 2, distance: 4, expectedOffset: 6),
IndexOffsetByTest(startOffset: 0, distance: 9, expectedOffset: 9),
IndexOffsetByTest(
startOffset: 0, distance: 0, expectedOffset: 0, limitedBy: 0),
IndexOffsetByTest(
startOffset: 0, distance: 0, expectedOffset: 0, limitedBy: 10),
IndexOffsetByTest(
startOffset: 0, distance: 10, expectedOffset: nil, limitedBy: 0),
IndexOffsetByTest(
startOffset: 0, distance: -10, expectedOffset: nil, limitedBy: 0),
IndexOffsetByTest(
startOffset: 0, distance: 10, expectedOffset: 10, limitedBy: 10),
IndexOffsetByTest(
startOffset: 0, distance: 20, expectedOffset: nil, limitedBy: 10),
IndexOffsetByTest(
startOffset: 10, distance: -20, expectedOffset: nil, limitedBy: 0),
IndexOffsetByTest(
startOffset: 5, distance: 5, expectedOffset: 10, limitedBy: 2),
IndexOffsetByTest(
startOffset: 5, distance: 5, expectedOffset: nil, limitedBy: 5),
IndexOffsetByTest(
startOffset: 5, distance: -5, expectedOffset: 0, limitedBy: 7),
IndexOffsetByTest(
startOffset: 5, distance: -5, expectedOffset: nil, limitedBy: 5)
]
public struct IndexAfterTest {
public let start: Int
public let end: Int
public let loc: SourceLoc
public init(start: Int, end: Int, file: String = #file, line: UInt = #line) {
self.start = start
self.end = end
self.loc = SourceLoc(file, line,
comment: "index(after:) and formIndex(after:) test data")
}
}
public let indexAfterTests = [
IndexAfterTest(start: 0, end: 1),
IndexAfterTest(start: 0, end: 10),
IndexAfterTest(start: 5, end: 12),
IndexAfterTest(start: -58, end: -54),
]
internal func _allIndices<C : Collection>(
into c: C, in bounds: Range<C.Index>
) -> [C.Index] {
var result: [C.Index] = []
var i = bounds.lowerBound
while i != bounds.upperBound {
result.append(i)
i = c.index(after: i)
}
return result
}
internal enum _SubSequenceSubscriptOnIndexMode {
case inRange
case outOfRangeToTheLeft
case outOfRangeToTheRight
case baseEndIndex
case sliceEndIndex
static var all: [_SubSequenceSubscriptOnIndexMode] {
return [
.inRange,
.outOfRangeToTheLeft,
.outOfRangeToTheRight,
.baseEndIndex,
.sliceEndIndex,
]
}
}
internal enum _SubSequenceSubscriptOnRangeMode {
case inRange
case outOfRangeToTheLeftEmpty
case outOfRangeToTheLeftNonEmpty
case outOfRangeToTheRightEmpty
case outOfRangeToTheRightNonEmpty
case outOfRangeBothSides
case baseEndIndex
static var all: [_SubSequenceSubscriptOnRangeMode] {
return [
.inRange,
.outOfRangeToTheLeftEmpty,
.outOfRangeToTheLeftNonEmpty,
.outOfRangeToTheRightEmpty,
.outOfRangeToTheRightNonEmpty,
.outOfRangeBothSides,
.baseEndIndex,
]
}
}
%{
from gyb_stdlib_support import collectionForTraversal
def testConstraints(protocol):
return '''
C : %(protocol)s,
CollectionWithEquatableElement : %(protocol)s,
CollectionWithEquatableElement.Iterator.Element : Equatable
''' % locals()
testParams = '''
_ testNamePrefix: String = "",
makeCollection: @escaping ([C.Iterator.Element]) -> C,
wrapValue: @escaping (OpaqueValue<Int>) -> C.Iterator.Element,
extractValue: @escaping (C.Iterator.Element) -> OpaqueValue<Int>,
makeCollectionOfEquatable: @escaping (
[CollectionWithEquatableElement.Iterator.Element]
) -> CollectionWithEquatableElement,
wrapValueIntoEquatable: @escaping (
MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
outOfBoundsIndexOffset: Int = 1,
outOfBoundsSubscriptOffset: Int = 1,
collectionIsBidirectional: Bool
'''
import re
forwardTestArgs = ',\n '.join(
[ x.group(1) + ': ' + x.group(1)
for x in re.finditer(r'([a-zA-Z0-9_]+):', testParams) ]
).replace('testNamePrefix: ', '\n ')
}%
extension TestSuite {
public func addCollectionTests<
C, CollectionWithEquatableElement
>(
${testParams} = false
) where
${testConstraints('Collection')} {
var testNamePrefix = testNamePrefix
if !checksAdded.insert(
"\(testNamePrefix).\(C.self).\(#function)"
).inserted {
return
}
addSequenceTests(
testNamePrefix,
makeSequence: makeCollection,
wrapValue: wrapValue,
extractValue: extractValue,
makeSequenceOfEquatable: makeCollectionOfEquatable,
wrapValueIntoEquatable: wrapValueIntoEquatable,
extractValueFromEquatable: extractValueFromEquatable,
resiliencyChecks: resiliencyChecks)
func makeWrappedCollection(_ elements: [OpaqueValue<Int>]) -> C {
return makeCollection(elements.map(wrapValue))
}
func makeWrappedCollectionWithEquatableElement(
_ elements: [MinimalEquatableValue]
) -> CollectionWithEquatableElement {
return makeCollectionOfEquatable(elements.map(wrapValueIntoEquatable))
}
testNamePrefix += String(describing: C.Type.self)
//===------------------------------------------------------------------===//
// generate()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).generate()/semantics") {
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
for _ in 0..<3 {
checkSequence(
test.collection.map(wrapValue),
c,
resiliencyChecks: .none) {
extractValue($0).value == extractValue($1).value
}
}
}
}
//===------------------------------------------------------------------===//
// Index
//===------------------------------------------------------------------===//
if resiliencyChecks.creatingOutOfBoundsIndicesBehavior != .none {
self.test("\(testNamePrefix).Index/OutOfBounds/Right/NonEmpty") {
let c = makeWrappedCollection([ 1010, 2020, 3030 ].map(OpaqueValue.init))
let index = c.endIndex
expectCrashLater()
_blackHole(c.index(index, offsetBy: numericCast(outOfBoundsIndexOffset)))
}
self.test("\(testNamePrefix).Index/OutOfBounds/Right/Empty") {
let c = makeWrappedCollection([])
let index = c.endIndex
expectCrashLater()
_blackHole(c.index(index, offsetBy: numericCast(outOfBoundsIndexOffset)))
}
}
//===------------------------------------------------------------------===//
// subscript(_: Index)
//===------------------------------------------------------------------===//
if resiliencyChecks.subscriptOnOutOfBoundsIndicesBehavior != .none {
self.test("\(testNamePrefix).subscript(_: Index)/OutOfBounds/Right/NonEmpty/Get") {
let c = makeWrappedCollection([ 1010, 2020, 3030 ].map(OpaqueValue.init))
var index = c.endIndex
expectCrashLater()
index = c.index(index, offsetBy: numericCast(outOfBoundsSubscriptOffset))
_blackHole(c[index])
}
self.test("\(testNamePrefix).subscript(_: Index)/OutOfBounds/Right/Empty/Get") {
let c = makeWrappedCollection([])
var index = c.endIndex
expectCrashLater()
index = c.index(index, offsetBy: numericCast(outOfBoundsSubscriptOffset))
_blackHole(c[index])
}
let tests = cartesianProduct(
subscriptRangeTests,
_SubSequenceSubscriptOnIndexMode.all)
self.test("\(testNamePrefix).SubSequence.subscript(_: Index)/Get/OutOfBounds")
.forEach(in: tests) {
(test, mode) in
let elements = test.collection
let sliceFromLeft = test.bounds.lowerBound
let sliceFromRight = elements.count - test.bounds.upperBound
print("\(elements)/sliceFromLeft=\(sliceFromLeft)/sliceFromRight=\(sliceFromRight)")
let base = makeWrappedCollection(elements)
let sliceStartIndex =
base.index(base.startIndex, offsetBy: numericCast(sliceFromLeft))
let sliceEndIndex = base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight))
var slice = base[sliceStartIndex..<sliceEndIndex]
expectType(C.SubSequence.self, &slice)
var index: C.Index = base.startIndex
switch mode {
case .inRange:
let sliceNumericIndices =
sliceFromLeft..<(elements.count - sliceFromRight)
for (i, index) in base.indices.enumerated() {
if sliceNumericIndices.contains(i) {
expectEqual(
elements[i].value,
extractValue(slice[index]).value)
expectEqual(
extractValue(base[index]).value,
extractValue(slice[index]).value)
}
}
return
case .outOfRangeToTheLeft:
if sliceFromLeft == 0 { return }
index = base.index(
base.startIndex,
offsetBy: numericCast(sliceFromLeft - 1))
case .outOfRangeToTheRight:
if sliceFromRight == 0 { return }
index = base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight))
case .baseEndIndex:
index = base.endIndex
case .sliceEndIndex:
index = sliceEndIndex
}
expectCrashLater()
_blackHole(slice[index])
}
}
//===------------------------------------------------------------------===//
// subscript(_: Range)
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).subscript(_: Range)/Get/semantics") {
for test in subscriptRangeTests {
let base = makeWrappedCollection(test.collection)
let sliceBounds = test.bounds(in: base)
let slice = base[sliceBounds]
expectEqual(sliceBounds.lowerBound, slice.startIndex)
expectEqual(sliceBounds.upperBound, slice.endIndex)
/*
// TODO: swift-3-indexing-model: uncomment the following.
// FIXME: improve checkForwardCollection to check the SubSequence type.
checkCollection(
expected: test.expected.map(wrapValue),
slice,
resiliencyChecks: .none) {
extractValue($0).value == extractValue($1).value
}
*/
}
}
if resiliencyChecks.subscriptRangeOnOutOfBoundsRangesBehavior != .none {
self.test("\(testNamePrefix).subscript(_: Range)/OutOfBounds/Right/NonEmpty/Get") {
let c = makeWrappedCollection([ 1010, 2020, 3030 ].map(OpaqueValue.init))
var index = c.endIndex
expectCrashLater()
index = c.index(index, offsetBy: numericCast(outOfBoundsSubscriptOffset))
_blackHole(c[index..<index])
}
self.test("\(testNamePrefix).subscript(_: Range)/OutOfBounds/Right/Empty/Get") {
let c = makeWrappedCollection([])
var index = c.endIndex
expectCrashLater()
index = c.index(index, offsetBy: numericCast(outOfBoundsSubscriptOffset))
_blackHole(c[index..<index])
}
let tests = cartesianProduct(
subscriptRangeTests,
_SubSequenceSubscriptOnRangeMode.all)
self.test(
"\(testNamePrefix).SubSequence.subscript(_: Range)/Get/OutOfBounds")
.forEach(in: tests) {
(test, mode) in
let elements = test.collection
let sliceFromLeft = test.bounds.lowerBound
let sliceFromRight = elements.count - test.bounds.upperBound
print(
"\(elements)/sliceFromLeft=\(sliceFromLeft)"
+ "/sliceFromRight=\(sliceFromRight)")
let base = makeWrappedCollection(elements)
let sliceStartIndex =
base.index(base.startIndex, offsetBy: numericCast(sliceFromLeft))
let sliceEndIndex = base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight))
var slice = base[sliceStartIndex..<sliceEndIndex]
expectType(C.SubSequence.self, &slice)
var bounds: Range<C.Index> = base.startIndex..<base.startIndex
switch mode {
case .inRange:
let sliceNumericIndices =
sliceFromLeft..<(elements.count - sliceFromRight + 1)
for (i, subSliceStartIndex) in base.indices.enumerated() {
for (j, subSliceEndIndex) in base.indices.enumerated() {
if i <= j &&
sliceNumericIndices.contains(i) &&
sliceNumericIndices.contains(j) {
let subSlice = slice[subSliceStartIndex..<subSliceEndIndex]
for (k, index) in subSlice.indices.enumerated() {
expectEqual(
elements[i + k].value,
extractValue(subSlice[index]).value)
expectEqual(
extractValue(base[index]).value,
extractValue(subSlice[index]).value)
expectEqual(
extractValue(slice[index]).value,
extractValue(subSlice[index]).value)
}
}
}
}
return
case .outOfRangeToTheLeftEmpty:
if sliceFromLeft == 0 { return }
let index = base.index(
base.startIndex,
offsetBy: numericCast(sliceFromLeft - 1))
bounds = index..<index
break
case .outOfRangeToTheLeftNonEmpty:
if sliceFromLeft == 0 { return }
let index = base.index(
base.startIndex,
offsetBy: numericCast(sliceFromLeft - 1))
bounds = index..<sliceStartIndex
break
case .outOfRangeToTheRightEmpty:
if sliceFromRight == 0 { return }
let index = base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight + 1))
bounds = index..<index
break
case .outOfRangeToTheRightNonEmpty:
if sliceFromRight == 0 { return }
let index = base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight + 1))
bounds = sliceEndIndex..<index
break
case .outOfRangeBothSides:
if sliceFromLeft == 0 { return }
if sliceFromRight == 0 { return }
bounds =
base.index(
base.startIndex,
offsetBy: numericCast(sliceFromLeft - 1))
..<
base.index(
base.startIndex,
offsetBy: numericCast(elements.count - sliceFromRight + 1))
break
case .baseEndIndex:
if sliceFromRight == 0 { return }
bounds = sliceEndIndex..<base.endIndex
break
}
expectCrashLater()
_blackHole(slice[bounds])
}
}
// FIXME: swift-3-indexing-model - add tests for the following?
// _failEarlyRangeCheck(index: Index, bounds: Range<Index>)
// _failEarlyRangeCheck(range: Range<Index>, bounds: Range<Index>)
//===------------------------------------------------------------------===//
// isEmpty
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).isEmpty/semantics") {
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
expectEqual(test.isEmpty, c.isEmpty)
}
}
//===------------------------------------------------------------------===//
// count
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).count/semantics") {
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
expectEqual(test.count, numericCast(c.count) as Int)
}
}
//===------------------------------------------------------------------===//
// index(of:)/index(where:)
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).index(of:)/semantics") {
for test in findTests {
let c = makeWrappedCollectionWithEquatableElement(test.sequence)
var result = c.index(of: wrapValueIntoEquatable(test.element))
expectType(
Optional<CollectionWithEquatableElement.Index>.self,
&result)
let zeroBasedIndex = result.map {
numericCast(c.distance(from: c.startIndex, to: $0)) as Int
}
expectEqual(
test.expected,
zeroBasedIndex,
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).index(where:)/semantics") {
for test in findTests {
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
let c = makeWrappedCollectionWithEquatableElement(test.sequence)
let result = c.index {
(candidate) in
_blackHole(closureLifetimeTracker)
return
extractValueFromEquatable(candidate).value == test.element.value
}
let zeroBasedIndex = result.map {
numericCast(c.distance(from: c.startIndex, to: $0)) as Int
}
expectEqual(
test.expected,
zeroBasedIndex,
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// first
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).first") {
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
let result = c.first
if test.isEmpty {
expectNil(result)
} else {
expectOptionalEqual(
test.collection[0],
result.map(extractValue)
) { $0.value == $1.value }
}
}
}
//===------------------------------------------------------------------===//
// indices
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).indices") {
// TODO: swift-3-indexing-model: improve this test. `indices`
// is not just a `Range` anymore, it can be anything.
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
let indices = c.indices
expectEqual(c.startIndex, indices.startIndex)
expectEqual(c.endIndex, indices.endIndex)
}
}
//===------------------------------------------------------------------===//
// dropFirst()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).dropFirst/semantics") {
for test in dropFirstTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.dropFirst(test.dropElements)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// dropLast()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).dropLast/semantics") {
for test in dropLastTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.dropLast(test.dropElements)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// prefix()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).prefix/semantics") {
for test in prefixTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.prefix(test.maxLength)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// suffix()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).suffix/semantics") {
for test in suffixTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.suffix(test.maxLength)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// split()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).split/semantics") {
for test in splitTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.split(
maxSplits: test.maxSplits,
omittingEmptySubsequences: test.omittingEmptySubsequences
) {
extractValue($0).value == test.separator
}
expectEqualSequence(test.expected, result.map {
$0.map {
extractValue($0).value
}
},
stackTrace: SourceLocStack().with(test.loc)) { $0 == $1 }
}
}
//===------------------------------------------------------------------===//
// prefix(through:)
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).prefix(through:)/semantics") {
for test in prefixThroughTests {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
let index = c.index(
c.startIndex, offsetBy: numericCast(test.position))
let result = c.prefix(through: index)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// prefix(upTo:)
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).prefix(upTo:)/semantics") {
for test in prefixUpToTests {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
let index = c.index(c.startIndex, offsetBy: numericCast(test.end))
let result = c.prefix(upTo: index)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// suffix(from:)
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).suffix(from:)/semantics") {
for test in suffixFromTests {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
let index = c.index(c.startIndex, offsetBy: numericCast(test.start))
let result = c.suffix(from: index)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// removeFirst()/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).removeFirst()/slice/semantics") {
for test in removeFirstTests.filter({ $0.numberToRemove == 1 }) {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.index(after: slice.startIndex)..<slice.endIndex)
let removedElement = slice.removeFirst()
expectEqual(test.collection.first, extractValue(removedElement).value)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"removeFirst() shouldn't mutate the tail of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"removeFirst() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection,
c.map { extractValue($0).value },
"removeFirst() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).removeFirst()/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
_ = slice.removeFirst() // Should trap.
}
//===------------------------------------------------------------------===//
// removeFirst(n: Int)/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).removeFirst(n: Int)/slice/semantics") {
for test in removeFirstTests {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.index(
slice.startIndex,
offsetBy: numericCast(test.numberToRemove)) ..< slice.endIndex
)
slice.removeFirst(test.numberToRemove)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"removeFirst() shouldn't mutate the tail of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"removeFirst() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection,
c.map { extractValue($0).value },
"removeFirst() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).removeFirst(n: Int)/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeFirst(1) // Should trap.
}
self.test(
"\(testNamePrefix).removeFirst(n: Int)/slice/removeNegative/semantics") {
let c = makeWrappedCollection([1010, 2020].map(OpaqueValue.init))
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeFirst(-1) // Should trap.
}
self.test(
"\(testNamePrefix).removeFirst(n: Int)/slice/removeTooMany/semantics") {
let c = makeWrappedCollection([1010, 2020].map(OpaqueValue.init))
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeFirst(3) // Should trap.
}
//===------------------------------------------------------------------===//
// popFirst()/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).popFirst()/slice/semantics") {
// This can just reuse the test data for removeFirst()
for test in removeFirstTests.filter({ $0.numberToRemove == 1 }) {
let c = makeWrappedCollection(test.collection.map(OpaqueValue.init))
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.index(after: slice.startIndex)..<slice.endIndex)
let removedElement = slice.popFirst()!
expectEqual(test.collection.first, extractValue(removedElement).value)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"popFirst() shouldn't mutate the tail of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"popFirst() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection,
c.map { extractValue($0).value },
"popFirst() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).popFirst()/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectNil(slice.popFirst())
}
//===------------------------------------------------------------------===//
self.addCommonTests(${forwardTestArgs})
} // addCollectionTests
public func addBidirectionalCollectionTests<
C, CollectionWithEquatableElement
>(
${testParams} = true
) where
${testConstraints('BidirectionalCollection')} {
var testNamePrefix = testNamePrefix
if !checksAdded.insert(
"\(testNamePrefix).\(C.self).\(#function)"
).inserted {
return
}
addCollectionTests(${forwardTestArgs})
func makeWrappedCollection(_ elements: [OpaqueValue<Int>]) -> C {
return makeCollection(elements.map(wrapValue))
}
testNamePrefix += String(describing: C.Type.self)
// FIXME: swift-3-indexing-model - add tests for the follow?
// index(before: of i: Index) -> Index
// formIndex(before: i: inout Index)
// FIXME: swift-3-indexing-model -
// enhance the following for negative direction?
// advance(i: Index, by n: Int) -> Index
// advance(
// i: Index, by n: Int, limitedBy: Index) -> Index
// distance(from start: Index, to end: Index) -> Int
//===------------------------------------------------------------------===//
// last
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).last") {
for test in subscriptRangeTests {
let c = makeWrappedCollection(test.collection)
let result = c.last
if test.isEmpty {
expectNil(result)
} else {
expectOptionalEqual(
test.collection[test.count - 1],
result.map(extractValue)
) { $0.value == $1.value }
}
}
}
//===------------------------------------------------------------------===//
// removeLast()/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).removeLast()/slice/semantics") {
for test in removeLastTests.filter({ $0.numberToRemove == 1 }) {
let c = makeWrappedCollection(test.collection)
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.startIndex
..< slice.index(
slice.endIndex, offsetBy: numericCast(-test.numberToRemove))
)
let removedElement = slice.removeLast()
expectEqual(
test.collection.last!.value,
extractValue(removedElement).value)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"removeLast() shouldn't mutate the head of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"removeLast() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection.map { $0.value },
c.map { extractValue($0).value },
"removeLast() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).removeLast()/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
_ = slice.removeLast() // Should trap.
}
//===------------------------------------------------------------------===//
// removeLast(n: Int)/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).removeLast(n: Int)/slice/semantics") {
for test in removeLastTests {
let c = makeWrappedCollection(test.collection)
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.startIndex
..< slice.index(
slice.endIndex, offsetBy: numericCast(-test.numberToRemove))
)
slice.removeLast(test.numberToRemove)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"removeLast() shouldn't mutate the head of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"removeLast() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection.map { $0.value },
c.map { extractValue($0).value },
"removeLast() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).removeLast(n: Int)/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeLast(1) // Should trap.
}
self.test(
"\(testNamePrefix).removeLast(n: Int)/slice/removeNegative/semantics"
) {
let c = makeWrappedCollection([1010, 2020].map(OpaqueValue.init))
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeLast(-1) // Should trap.
}
self.test(
"\(testNamePrefix).removeLast(n: Int)/slice/removeTooMany/semantics"
) {
let c = makeWrappedCollection([1010, 2020].map(OpaqueValue.init))
var slice = c[c.startIndex..<c.startIndex]
expectCrashLater()
slice.removeLast(3) // Should trap.
}
//===------------------------------------------------------------------===//
// popLast()/slice
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).popLast()/slice/semantics") {
// This can just reuse the test data for removeLast()
for test in removeLastTests.filter({ $0.numberToRemove == 1 }) {
let c = makeWrappedCollection(test.collection)
var slice = c[...]
let survivingIndices = _allIndices(
into: slice,
in: slice.startIndex
..< slice.index(
slice.endIndex, offsetBy: numericCast(-test.numberToRemove))
)
let removedElement = slice.popLast()!
expectEqual(
test.collection.last!.value,
extractValue(removedElement).value)
expectEqualSequence(
test.expectedCollection,
slice.map { extractValue($0).value },
"popLast() shouldn't mutate the head of the slice",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.expectedCollection,
survivingIndices.map { extractValue(slice[$0]).value },
"popLast() shouldn't invalidate indices",
stackTrace: SourceLocStack().with(test.loc)
)
expectEqualSequence(
test.collection.map { $0.value },
c.map { extractValue($0).value },
"popLast() shouldn't mutate the collection that was sliced",
stackTrace: SourceLocStack().with(test.loc))
}
}
self.test("\(testNamePrefix).popLast()/slice/empty/semantics") {
let c = makeWrappedCollection(Array<OpaqueValue<Int>>())
var slice = c[c.startIndex..<c.startIndex]
expectNil(slice.popLast())
}
//===------------------------------------------------------------------===//
// Index
//===------------------------------------------------------------------===//
if resiliencyChecks.creatingOutOfBoundsIndicesBehavior != .none {
self.test("\(testNamePrefix).Index/OutOfBounds/Left/NonEmpty") {
let c = makeWrappedCollection(
[ 1010, 2020, 3030 ].map(OpaqueValue.init))
let index = c.startIndex
expectCrashLater()
_blackHole(
c.index(index, offsetBy: numericCast(-outOfBoundsIndexOffset)))
}
self.test("\(testNamePrefix).Index/OutOfBounds/Left/Empty") {
let c = makeWrappedCollection([])
let index = c.startIndex
expectCrashLater()
_blackHole(
c.index(index, offsetBy: numericCast(-outOfBoundsIndexOffset)))
}
}
//===------------------------------------------------------------------===//
// subscript(_: Index)
//===------------------------------------------------------------------===//
if resiliencyChecks.subscriptOnOutOfBoundsIndicesBehavior != .none {
self.test(
"\(testNamePrefix).subscript(_: Index)/OutOfBounds/Left/NonEmpty/Get"
) {
let c = makeWrappedCollection(
[ 1010, 2020, 3030 ].map(OpaqueValue.init))
var index = c.startIndex
expectCrashLater()
index = c.index(
index, offsetBy: numericCast(-outOfBoundsSubscriptOffset))
_blackHole(c[index])
}
self.test(
"\(testNamePrefix).subscript(_: Index)/OutOfBounds/Left/Empty/Get"
) {
let c = makeWrappedCollection([])
var index = c.startIndex
expectCrashLater()
index = c.index(
index, offsetBy: numericCast(-outOfBoundsSubscriptOffset))
_blackHole(c[index])
}
}
//===------------------------------------------------------------------===//
// subscript(_: Range)
//===------------------------------------------------------------------===//
if resiliencyChecks.subscriptRangeOnOutOfBoundsRangesBehavior != .none {
self.test(
"\(testNamePrefix).subscript(_: Range)/OutOfBounds/Left/NonEmpty/Get"
) {
let c = makeWrappedCollection(
[ 1010, 2020, 3030 ].map(OpaqueValue.init))
var index = c.startIndex
expectCrashLater()
index = c.index(
index, offsetBy: numericCast(-outOfBoundsSubscriptOffset))
_blackHole(c[index..<index])
}
self.test(
"\(testNamePrefix).subscript(_: Range)/OutOfBounds/Left/Empty/Get"
) {
let c = makeWrappedCollection([])
var index = c.startIndex
expectCrashLater()
index = c.index(
index, offsetBy: numericCast(-outOfBoundsSubscriptOffset))
_blackHole(c[index..<index])
}
}
//===------------------------------------------------------------------===//
// dropLast()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).dropLast/semantics") {
for test in dropLastTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.dropLast(test.dropElements)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// suffix()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).suffix/semantics") {
for test in suffixTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.suffix(test.maxLength)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
self.addCommonTests(${forwardTestArgs})
} // addBidirectionalCollectionTests
public func addRandomAccessCollectionTests<
C, CollectionWithEquatableElement
>(
${testParams} = true
) where
${testConstraints('RandomAccessCollection')} {
var testNamePrefix = testNamePrefix
if !checksAdded.insert(
"\(testNamePrefix).\(C.self).\(#function)"
).inserted {
return
}
addBidirectionalCollectionTests(${forwardTestArgs})
testNamePrefix += String(describing: C.Type.self)
func makeWrappedCollection(_ elements: [OpaqueValue<Int>]) -> C {
return makeCollection(elements.map(wrapValue))
}
//===------------------------------------------------------------------===//
// prefix()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).prefix/semantics") {
for test in prefixTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.prefix(test.maxLength)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
// suffix()
//===------------------------------------------------------------------===//
self.test("\(testNamePrefix).suffix/semantics") {
for test in suffixTests {
let s = makeWrappedCollection(test.sequence.map(OpaqueValue.init))
let result = s.suffix(test.maxLength)
expectEqualSequence(
test.expected, result.map(extractValue).map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===------------------------------------------------------------------===//
self.addCommonTests(${forwardTestArgs})
} // addRandomAccessCollectionTests
% for Traversal in ['Forward', 'Bidirectional', 'RandomAccess']:
func addCommonTests<
C, CollectionWithEquatableElement
>(
${testParams}
) where
${testConstraints(collectionForTraversal(Traversal))} {
if !checksAdded.insert(
"\(testNamePrefix).\(C.self).\(#function)"
).inserted {
return
}
func toCollection(_ r: CountableRange<Int>) -> C {
return makeCollection(r.map { wrapValue(OpaqueValue($0)) })
}
% for function_name in ['index', 'formIndex']:
self.test("\(testNamePrefix).${function_name}(after:)/semantics") {
for test in indexAfterTests {
let c = toCollection(test.start..<test.end)
var currentIndex = c.startIndex
var counter = test.start
repeat {
expectEqual(counter, extractValue(c[currentIndex]).value,
stackTrace: SourceLocStack().with(test.loc))
% if function_name is 'index':
currentIndex = c.index(after: currentIndex)
% else:
c.formIndex(after: &currentIndex)
% end
counter += 1
} while counter < test.end
}
}
% end
self.test("\(testNamePrefix)/distance(from:to:)/semantics")
.forEach(in: distanceFromToTests) {
test in
let c = toCollection(0..<20)
let d = c.distance(
from: c.nthIndex(test.startOffset), to: c.nthIndex(test.endOffset))
expectEqual(
numericCast(test.expectedDistance),
d, stackTrace: SourceLocStack().with(test.loc))
}
self.test("\(testNamePrefix)/index(_:offsetBy: n)/semantics")
.forEach(
in: indexOffsetByTests.filter { $0.limit == nil && $0.distance >= 0 }
) {
test in
let max = 10
let c = toCollection(0..<max)
if test.expectedOffset! >= max {
expectCrashLater()
}
let new = c.index(
c.nthIndex(test.startOffset),
offsetBy: numericCast(test.distance))
// Since the `nthIndex(offset:)` method performs the same operation
// (i.e. advances `c.startIndex` by `test.distance`, it would be
// silly to compare index values. Luckily the underlying collection
// contains exactly index offsets.
expectEqual(test.expectedOffset!, extractValue(c[new]).value,
stackTrace: SourceLocStack().with(test.loc))
}
self.test("\(testNamePrefix)/formIndex(_:offsetBy: n)/semantics")
.forEach(
in: indexOffsetByTests.filter { $0.limit == nil && $0.distance >= 0 }
) {
test in
let max = 10
let c = toCollection(0..<max)
var new = c.nthIndex(test.startOffset)
if test.expectedOffset! >= max {
expectCrashLater()
}
c.formIndex(&new, offsetBy: numericCast(test.distance))
expectEqual(test.expectedOffset!, extractValue(c[new]).value,
stackTrace: SourceLocStack().with(test.loc))
}
% for function_name in ['index', 'formIndex']:
self.test("\(testNamePrefix)/${function_name}(_:offsetBy: -n)/semantics")
.forEach(
in: indexOffsetByTests.filter { $0.limit == nil && $0.distance < 0 }
) {
test in
let c = toCollection(0..<20)
% if function_name is 'index':
let start = c.nthIndex(test.startOffset)
% else:
var new = c.nthIndex(test.startOffset)
% end
if test.expectedOffset! < 0 || !collectionIsBidirectional {
expectCrashLater()
}
% if function_name is 'index':
let new = c.index(start, offsetBy: numericCast(test.distance))
% else:
c.formIndex(&new, offsetBy: numericCast(test.distance))
% end
expectEqual(test.expectedOffset!, extractValue(c[new]).value,
stackTrace: SourceLocStack().with(test.loc))
}
% end
self.test("\(testNamePrefix)/index(_:offsetBy: n, limitedBy:)/semantics") {
for test in indexOffsetByTests.filter(
{$0.limit != nil && $0.distance >= 0}
) {
let c = toCollection(0..<20)
let limit = c.nthIndex(test.limit.unsafelyUnwrapped)
let new = c.index(
c.nthIndex(test.startOffset),
offsetBy: numericCast(test.distance),
limitedBy: limit)
if let expectedOffset = test.expectedOffset {
expectEqual(c.nthIndex(expectedOffset), new!,
stackTrace: SourceLocStack().with(test.loc))
} else {
expectNil(new)
}
}
}
self.test("\(testNamePrefix)/formIndex(_:offsetBy: n, limitedBy:)/semantics") {
for test in indexOffsetByTests.filter(
{$0.limit != nil && $0.distance >= 0}
) {
let c = toCollection(0..<20)
let limit = c.nthIndex(test.limit.unsafelyUnwrapped)
var new = c.nthIndex(test.startOffset)
let exact = c.formIndex(&new, offsetBy: numericCast(test.distance), limitedBy: limit)
if let expectedOffset = test.expectedOffset {
expectEqual(c.nthIndex(expectedOffset), new,
stackTrace: SourceLocStack().with(test.loc))
expectTrue(exact, stackTrace: SourceLocStack().with(test.loc))
} else {
// Clamped to the limit
expectEqual(limit, new, stackTrace: SourceLocStack().with(test.loc))
expectFalse(exact, stackTrace: SourceLocStack().with(test.loc))
}
}
}
self.test("\(testNamePrefix)/index(_:offsetBy: -n, limitedBy:)/semantics")
.forEach(
in: indexOffsetByTests.filter { $0.limit != nil && $0.distance < 0 }
) {
test in
let c = toCollection(0..<20)
let limit = c.nthIndex(test.limit.unsafelyUnwrapped)
if collectionIsBidirectional {
let new = c.index(
c.nthIndex(test.startOffset),
offsetBy: numericCast(test.distance),
limitedBy: limit)
if let expectedOffset = test.expectedOffset {
expectEqual(c.nthIndex(expectedOffset), new!,
stackTrace: SourceLocStack().with(test.loc))
} else {
expectNil(new)
}
} else {
expectCrashLater()
_ = c.index(
c.nthIndex(test.startOffset),
offsetBy: numericCast(test.distance),
limitedBy: limit)
}
}
self.test("\(testNamePrefix)/formIndex(_:offsetBy: -n, limitedBy:)/semantics")
.forEach(
in: indexOffsetByTests.filter { $0.limit != nil && $0.distance < 0 }
) {
test in
let c = toCollection(0..<20)
let limit = c.nthIndex(test.limit.unsafelyUnwrapped)
var new = c.nthIndex(test.startOffset)
if collectionIsBidirectional {
let exact = c.formIndex(
&new,
offsetBy: numericCast(test.distance),
limitedBy: limit)
if let expectedOffset = test.expectedOffset {
expectEqual(c.nthIndex(expectedOffset), new,
stackTrace: SourceLocStack().with(test.loc))
expectTrue(exact, stackTrace: SourceLocStack().with(test.loc))
} else {
expectEqual(limit, new, stackTrace: SourceLocStack().with(test.loc))
expectFalse(exact, stackTrace: SourceLocStack().with(test.loc))
}
} else {
expectCrashLater()
_ = c.formIndex(&new, offsetBy: numericCast(test.distance), limitedBy: limit)
}
}
}
% end
}