mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The RangeSet test depends on the StdlibCollectionUnittest, which is part of the validation tests. This should repair the tests.
364 lines
11 KiB
Swift
364 lines
11 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
|
|
extension RangeSet: ExpressibleByArrayLiteral {
|
|
public init(arrayLiteral elements: Range<Bound>...) {
|
|
self.init(elements)
|
|
}
|
|
}
|
|
|
|
extension Collection {
|
|
func every(_ n: Int) -> [Element] {
|
|
sequence(first: startIndex) { i in
|
|
self.index(i, offsetBy: n, limitedBy: self.endIndex)
|
|
}.map { self[$0] }
|
|
}
|
|
}
|
|
|
|
let RangeSetTests = TestSuite("RangeSet")
|
|
|
|
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
|
|
|
|
let parent = -200..<200
|
|
let source: RangeSet = [1..<5, 8..<10, 20..<22, 27..<29]
|
|
|
|
let letterString = "ABCdefGHIjklMNOpqrStUvWxyz"
|
|
let lowercaseLetters = letterString.filter { $0.isLowercase }
|
|
let uppercaseLetters = letterString.filter { $0.isUppercase }
|
|
|
|
func buildRandomRangeSet(iterations: Int = 100) -> RangeSet<Int> {
|
|
var set = RangeSet<Int>()
|
|
for _ in 0..<100 {
|
|
var (a, b) = (Int.random(in: -100...100), Int.random(in: -100...100))
|
|
if (a > b) { swap(&a, &b) }
|
|
if Double.random(in: 0..<1) > 0.3 {
|
|
set.insert(contentsOf: a..<b)
|
|
} else {
|
|
set.remove(contentsOf: a..<b)
|
|
}
|
|
}
|
|
return set
|
|
}
|
|
|
|
RangeSetTests.test("contains") {
|
|
expectFalse(source.contains(0))
|
|
expectTrue(source.contains(1))
|
|
expectTrue(source.contains(4))
|
|
expectFalse(source.contains(5))
|
|
expectTrue(source.contains(28))
|
|
expectFalse(source.contains(29))
|
|
|
|
for _ in 0..<1000 {
|
|
let set = buildRandomRangeSet()
|
|
for i in parent.indices[set] {
|
|
expectTrue(set.contains(i))
|
|
}
|
|
|
|
for i in parent.indices.removingSubranges(set) {
|
|
expectFalse(set.contains(i))
|
|
}
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("insertions") {
|
|
do {
|
|
// Overlap from middle to middle
|
|
var s = source
|
|
s.insert(contentsOf: 3..<21)
|
|
expectEqualSequence(s.ranges, [1..<22, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// insert in middle
|
|
var s = source
|
|
s.insert(contentsOf: 13..<15)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 13..<15, 20..<22, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// extend a range
|
|
var s = source
|
|
s.insert(contentsOf: 22..<25)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 20..<25, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// extend at beginning of range
|
|
var s = source
|
|
s.insert(contentsOf: 17..<20)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 17..<22, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// insert at the beginning
|
|
var s = source
|
|
s.insert(contentsOf: -10 ..< -5)
|
|
expectEqualSequence(s.ranges, [-10 ..< -5, 1..<5, 8..<10, 20..<22, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// insert at the end
|
|
var s = source
|
|
s.insert(contentsOf: 35 ..< 40)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 20..<22, 27..<29, 35..<40])
|
|
}
|
|
|
|
do {
|
|
// Overlap multiple ranges
|
|
var s = source
|
|
s.insert(contentsOf: 0..<21)
|
|
expectEqualSequence(s.ranges, [0..<22, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// Insert at end of range
|
|
var s = source
|
|
s.insert(22, within: parent)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 20..<23, 27..<29])
|
|
}
|
|
|
|
do {
|
|
// Insert between ranges
|
|
var s = source
|
|
s.insert(14, within: parent)
|
|
expectEqualSequence(s.ranges, [1..<5, 8..<10, 14..<15, 20..<22, 27..<29])
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("removals") {
|
|
var s = source
|
|
s.remove(contentsOf: 4..<28)
|
|
expectEqualSequence(s.ranges, [1..<4, 28..<29])
|
|
s.remove(3, within: parent)
|
|
expectEqualSequence(s.ranges, [1..<3, 28..<29])
|
|
}
|
|
|
|
RangeSetTests.test("invariants") {
|
|
for _ in 0..<1000 {
|
|
let set = buildRandomRangeSet()
|
|
|
|
// No empty ranges allowed
|
|
expectTrue(set.ranges.allSatisfy { !$0.isEmpty })
|
|
|
|
// No overlapping / out-of-order ranges allowed
|
|
let adjacentRanges = zip(set.ranges, set.ranges.dropFirst())
|
|
expectTrue(adjacentRanges.allSatisfy { $0.upperBound < $1.lowerBound })
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("intersection") {
|
|
func intersectionViaSet(_ s1: RangeSet<Int>, _ s2: RangeSet<Int>) -> RangeSet<Int> {
|
|
let set1 = Set(parent.indices[s1])
|
|
let set2 = Set(parent.indices[s2])
|
|
return RangeSet(set1.intersection(set2), within: parent)
|
|
}
|
|
|
|
do {
|
|
// Simple test
|
|
let set1: RangeSet = [0..<5, 9..<14]
|
|
let set2: RangeSet = [1..<3, 4..<6, 8..<12]
|
|
let intersection: RangeSet = [1..<3, 4..<5, 9..<12]
|
|
expectEqual(set1.intersection(set2), intersection)
|
|
expectEqual(set2.intersection(set1), intersection)
|
|
}
|
|
|
|
do {
|
|
// Test with upper bound / lower bound equality
|
|
let set1: RangeSet = [10..<20, 30..<40]
|
|
let set2: RangeSet = [15..<30, 40..<50]
|
|
let intersection: RangeSet = [15..<20]
|
|
expectEqual(set1.intersection(set2), intersection)
|
|
expectEqual(set2.intersection(set1), intersection)
|
|
}
|
|
|
|
for _ in 0..<100 {
|
|
let set1 = buildRandomRangeSet()
|
|
let set2 = buildRandomRangeSet()
|
|
|
|
let rangeSetIntersection = set1.intersection(set2)
|
|
let stdlibSetIntersection = intersectionViaSet(set1, set2)
|
|
expectEqual(rangeSetIntersection, stdlibSetIntersection)
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("symmetricDifference") {
|
|
func symmetricDifferenceViaSet(_ s1: RangeSet<Int>, _ s2: RangeSet<Int>) -> RangeSet<Int> {
|
|
let set1 = Set(parent.indices[s1])
|
|
let set2 = Set(parent.indices[s2])
|
|
return RangeSet(set1.symmetricDifference(set2), within: parent)
|
|
}
|
|
|
|
do {
|
|
// Simple test
|
|
let set1: RangeSet = [0..<5, 9..<14]
|
|
let set2: RangeSet = [1..<3, 4..<6, 8..<12]
|
|
let difference: RangeSet = [0..<1, 3..<4, 5..<6, 8..<9, 12..<14]
|
|
expectEqual(set1.symmetricDifference(set2), difference)
|
|
expectEqual(set2.symmetricDifference(set1), difference)
|
|
}
|
|
|
|
do {
|
|
// Test with upper bound / lower bound equality
|
|
let set1: RangeSet = [10..<20, 30..<40]
|
|
let set2: RangeSet = [15..<30, 40..<50]
|
|
let difference: RangeSet = [10..<15, 20..<50]
|
|
expectEqual(set1.symmetricDifference(set2), difference)
|
|
expectEqual(set2.symmetricDifference(set1), difference)
|
|
}
|
|
|
|
for _ in 0..<100 {
|
|
let set1 = buildRandomRangeSet()
|
|
let set2 = buildRandomRangeSet()
|
|
|
|
let rangeSetDifference = set1.symmetricDifference(set2)
|
|
let stdlibSetDifference = symmetricDifferenceViaSet(set1, set2)
|
|
expectEqual(rangeSetDifference, stdlibSetDifference)
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("subranges(of:/where:)") {
|
|
let a = [1, 2, 3, 4, 3, 3, 4, 5, 3, 4, 3, 3, 3]
|
|
let indices = a.subranges(of: 3)
|
|
expectEqual(indices, [2..<3, 4..<6, 8..<9, 10..<13])
|
|
|
|
let allTheThrees = a[indices]
|
|
expectEqual(allTheThrees.count, 7)
|
|
expectTrue(allTheThrees.allSatisfy { $0 == 3 })
|
|
expectEqual(Array(allTheThrees), Array(repeating: 3, count: 7))
|
|
|
|
let lowerIndices = letterString.subranges(where: { $0.isLowercase })
|
|
let lowerOnly = letterString[lowerIndices]
|
|
expectEqualSequence(lowerOnly, lowercaseLetters)
|
|
expectEqualSequence(lowerOnly.reversed(), lowercaseLetters.reversed())
|
|
|
|
let upperOnly = letterString.removingSubranges(lowerIndices)
|
|
expectEqualSequence(upperOnly, uppercaseLetters)
|
|
expectEqualSequence(upperOnly.reversed(), uppercaseLetters.reversed())
|
|
}
|
|
|
|
RangeSetTests.test("removeSubranges") {
|
|
var a = [1, 2, 3, 4, 3, 3, 4, 5, 3, 4, 3, 3, 3]
|
|
let indices = a.subranges(of: 3)
|
|
a.removeSubranges(indices)
|
|
expectEqual(a, [1, 2, 4, 4, 5, 4])
|
|
|
|
var numbers = Array(1...20)
|
|
numbers.removeSubranges(RangeSet([2..<5, 10..<15, 18..<20]))
|
|
expectEqual(numbers, [1, 2, 6, 7, 8, 9, 10, 16, 17, 18])
|
|
|
|
numbers = Array(1...20)
|
|
numbers.removeSubranges([])
|
|
expectEqual(numbers, Array(1...20))
|
|
|
|
let sameNumbers = numbers.removingSubranges([])
|
|
expectEqualSequence(numbers, sameNumbers)
|
|
|
|
let noNumbers = numbers.removingSubranges(RangeSet(numbers.indices))
|
|
expectEqualSequence(EmptyCollection(), noNumbers)
|
|
|
|
var str = letterString
|
|
let lowerIndices = str.subranges(where: { $0.isLowercase })
|
|
|
|
let upperOnly = str.removingSubranges(lowerIndices)
|
|
expectEqualSequence(upperOnly, uppercaseLetters)
|
|
|
|
str.removeSubranges(lowerIndices)
|
|
expectEqualSequence(str, uppercaseLetters)
|
|
}
|
|
|
|
RangeSetTests.test("moveSubranges/rangeset") {
|
|
// Move before
|
|
var numbers = Array(1...20)
|
|
let range1 = numbers.moveSubranges(RangeSet([10..<15, 18..<20]), to: 4)
|
|
expectEqual(range1, 4..<11)
|
|
expectEqual(numbers, [
|
|
1, 2, 3, 4,
|
|
11, 12, 13, 14, 15,
|
|
19, 20,
|
|
5, 6, 7, 8, 9, 10, 16, 17, 18])
|
|
|
|
// Move to start
|
|
numbers = Array(1...20)
|
|
let range2 = numbers.moveSubranges(RangeSet([10..<15, 18..<20]), to: 0)
|
|
expectEqual(range2, 0..<7)
|
|
expectEqual(numbers, [
|
|
11, 12, 13, 14, 15,
|
|
19, 20,
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17, 18])
|
|
|
|
// Move to end
|
|
numbers = Array(1...20)
|
|
let range3 = numbers.moveSubranges(RangeSet([10..<15, 18..<20]), to: 20)
|
|
expectEqual(range3, 13..<20)
|
|
expectEqual(numbers, [
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17, 18,
|
|
11, 12, 13, 14, 15,
|
|
19, 20,
|
|
])
|
|
|
|
// Move to middle of selected elements
|
|
numbers = Array(1...20)
|
|
let range4 = numbers.moveSubranges(RangeSet([10..<15, 18..<20]), to: 14)
|
|
expectEqual(range4, 10..<17)
|
|
expectEqual(numbers, [
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
11, 12, 13, 14, 15,
|
|
19, 20,
|
|
16, 17, 18])
|
|
|
|
// Move none
|
|
numbers = Array(1...20)
|
|
let range5 = numbers.moveSubranges(RangeSet(), to: 10)
|
|
expectEqual(range5, 10..<10)
|
|
expectEqual(numbers, Array(1...20))
|
|
}
|
|
|
|
RangeSetTests.test("moveSubranges/noCOW") {
|
|
let numbers = Array(1...20)
|
|
expectNoCopyOnWrite(numbers) { numbers in
|
|
numbers.moveSubranges(RangeSet([10..<15, 18..<20]), to: 4)
|
|
}
|
|
expectNoCopyOnWrite(numbers) { numbers in
|
|
numbers.removeSubranges(RangeSet([2..<5, 10..<15, 18..<20]))
|
|
}
|
|
}
|
|
|
|
RangeSetTests.test("DiscontiguousSliceSlicing") {
|
|
let initial = 1...100
|
|
|
|
// Build an array of ranges that include alternating groups of 5 elements
|
|
// e.g. 1...5, 11...15, etc
|
|
let rangeStarts = initial.indices.every(10)
|
|
let rangeEnds = rangeStarts.compactMap {
|
|
initial.index($0, offsetBy: 5, limitedBy: initial.endIndex)
|
|
}
|
|
let ranges = zip(rangeStarts, rangeEnds).map(Range.init)
|
|
|
|
// Create a collection of the elements represented by `ranges` without
|
|
// using `RangeSet`
|
|
let chosenElements = ranges.map { initial[$0] }.joined()
|
|
|
|
let set = RangeSet(ranges)
|
|
let discontiguousSlice = initial[set]
|
|
expectEqualSequence(discontiguousSlice, chosenElements)
|
|
|
|
for (chosenIdx, disIdx) in zip(chosenElements.indices, discontiguousSlice.indices) {
|
|
expectEqualSequence(chosenElements[chosenIdx...], discontiguousSlice[disIdx...])
|
|
expectEqualSequence(chosenElements[..<chosenIdx], discontiguousSlice[..<disIdx])
|
|
for (chosenUpper, disUpper) in
|
|
zip(chosenElements.indices[chosenIdx...], discontiguousSlice.indices[disIdx...])
|
|
{
|
|
expectEqualSequence(
|
|
Array(chosenElements[chosenIdx..<chosenUpper]),
|
|
Array(discontiguousSlice[disIdx..<disUpper]))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
runAllTests()
|