Skip to content

Commit 9c392bf

Browse files
committed
StdlibCollectionUnittest: generalize MutableCollection.SubSequence.subscript(_: Range)/Set tests
1 parent 1fe5f04 commit 9c392bf

File tree

2 files changed

+184
-55
lines changed

2 files changed

+184
-55
lines changed

stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb

+184
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,73 @@ if resiliencyChecks.subscriptOnOutOfBoundsIndicesBehavior != .none {
175175
}
176176
}
177177
}
178+
179+
let tests = _product(
180+
subscriptRangeTests,
181+
_SubSequenceSubscriptOnIndexMode.all)
182+
183+
self.test("\(testNamePrefix).SubSequence.subscript(_: Index)/Set/OutOfBounds")
184+
.forEach(in: tests) {
185+
(test, mode) in
186+
let elements = test.collection
187+
let sliceFromLeft = test.bounds.lowerBound
188+
let sliceFromRight = elements.count - test.bounds.upperBound
189+
print("\(elements)/sliceFromLeft=\(sliceFromLeft)/sliceFromRight=\(sliceFromRight)")
190+
let base = makeWrappedCollection(elements)
191+
let sliceStartIndex =
192+
base.index(numericCast(sliceFromLeft), stepsFrom: base.startIndex)
193+
let sliceEndIndex = base.index(
194+
numericCast(elements.count - sliceFromRight),
195+
stepsFrom: base.startIndex)
196+
var slice = base[sliceStartIndex..<sliceEndIndex]
197+
expectType(C.SubSequence.self, &slice)
198+
199+
var index: C.Index = base.startIndex
200+
switch mode {
201+
case .inRange:
202+
let sliceNumericIndices =
203+
sliceFromLeft..<(elements.count - sliceFromRight)
204+
for (i, index) in base.indices.enumerated() {
205+
if sliceNumericIndices.contains(i) {
206+
slice[index] = wrapValue(OpaqueValue(elements[i].value + 90000))
207+
}
208+
}
209+
for (i, index) in base.indices.enumerated() {
210+
if sliceNumericIndices.contains(i) {
211+
expectEqual(
212+
elements[i].value + 90000,
213+
extractValue(slice[index]).value)
214+
expectEqual(
215+
extractValue(base[index]).value + 90000,
216+
extractValue(slice[index]).value)
217+
}
218+
}
219+
return
220+
case .outOfRangeToTheLeft:
221+
if sliceFromLeft == 0 { return }
222+
index = base.index(
223+
numericCast(sliceFromLeft - 1),
224+
stepsFrom: base.startIndex)
225+
case .outOfRangeToTheRight:
226+
if sliceFromRight == 0 { return }
227+
index = base.index(
228+
numericCast(elements.count - sliceFromRight),
229+
stepsFrom: base.startIndex)
230+
case .baseEndIndex:
231+
index = base.endIndex
232+
case .sliceEndIndex:
233+
index = sliceEndIndex
234+
}
235+
236+
if resiliencyChecks.subscriptOnOutOfBoundsIndicesBehavior == .trap {
237+
expectCrashLater()
238+
slice[index] = wrapValue(OpaqueValue(9999))
239+
} else {
240+
expectFailure {
241+
slice[index] = wrapValue(OpaqueValue(9999))
242+
}
243+
}
244+
}
178245
}
179246

180247
//===----------------------------------------------------------------------===//
@@ -267,6 +334,123 @@ if isFixedLengthCollection {
267334
}
268335
}
269336

337+
if resiliencyChecks.subscriptRangeOnOutOfBoundsRangesBehavior != .none {
338+
let tests = _product(
339+
subscriptRangeTests,
340+
_SubSequenceSubscriptOnRangeMode.all)
341+
342+
self.test("\(testNamePrefix).SubSequence.subscript(_: Range)/Set/OutOfBounds")
343+
.forEach(in: tests) {
344+
(test, mode) in
345+
let elements = test.collection
346+
let sliceFromLeft = test.bounds.lowerBound
347+
let sliceFromRight = elements.count - test.bounds.upperBound
348+
print("\(elements)/sliceFromLeft=\(sliceFromLeft)/sliceFromRight=\(sliceFromRight)")
349+
let base = makeWrappedCollection(elements)
350+
let sliceStartIndex =
351+
base.index(numericCast(sliceFromLeft), stepsFrom: base.startIndex)
352+
let sliceEndIndex = base.index(
353+
numericCast(elements.count - sliceFromRight),
354+
stepsFrom: base.startIndex)
355+
var slice = base[sliceStartIndex..<sliceEndIndex]
356+
expectType(C.SubSequence.self, &slice)
357+
358+
var bounds: Range<C.Index> = base.startIndex..<base.startIndex
359+
switch mode {
360+
case .inRange:
361+
let sliceNumericIndices =
362+
sliceFromLeft..<(elements.count - sliceFromRight + 1)
363+
for (i, subSliceStartIndex) in base.indices.enumerated() {
364+
for (j, subSliceEndIndex) in base.indices.enumerated() {
365+
if i <= j &&
366+
sliceNumericIndices.contains(i) &&
367+
sliceNumericIndices.contains(j) {
368+
let newValues = makeWrappedCollection(
369+
elements[i..<j].map { OpaqueValue($0.value + 90000) }
370+
)
371+
slice[subSliceStartIndex..<subSliceEndIndex]
372+
= newValues[newValues.startIndex..<newValues.endIndex]
373+
let subSlice = slice[subSliceStartIndex..<subSliceEndIndex]
374+
for (k, index) in subSlice.indices.enumerated() {
375+
expectEqual(
376+
elements[i + k].value + 90000,
377+
extractValue(subSlice[index]).value)
378+
expectEqual(
379+
extractValue(base[index]).value + 90000,
380+
extractValue(subSlice[index]).value)
381+
expectEqual(
382+
extractValue(slice[index]).value,
383+
extractValue(subSlice[index]).value)
384+
}
385+
let oldValues = makeWrappedCollection(Array(elements[i..<j]))
386+
slice[subSliceStartIndex..<subSliceEndIndex]
387+
= oldValues[oldValues.startIndex..<oldValues.endIndex]
388+
}
389+
}
390+
}
391+
return
392+
case .outOfRangeToTheLeftEmpty:
393+
if sliceFromLeft == 0 { return }
394+
let index = base.index(
395+
numericCast(sliceFromLeft - 1),
396+
stepsFrom: base.startIndex)
397+
bounds = index..<index
398+
break
399+
case .outOfRangeToTheLeftNonEmpty:
400+
if sliceFromLeft == 0 { return }
401+
let index = base.index(
402+
numericCast(sliceFromLeft - 1),
403+
stepsFrom: base.startIndex)
404+
bounds = index..<sliceStartIndex
405+
break
406+
case .outOfRangeToTheRightEmpty:
407+
if sliceFromRight == 0 { return }
408+
let index = base.index(
409+
numericCast(elements.count - sliceFromRight + 1),
410+
stepsFrom: base.startIndex)
411+
bounds = index..<index
412+
break
413+
case .outOfRangeToTheRightNonEmpty:
414+
if sliceFromRight == 0 { return }
415+
let index = base.index(
416+
numericCast(elements.count - sliceFromRight + 1),
417+
stepsFrom: base.startIndex)
418+
bounds = sliceEndIndex..<index
419+
break
420+
case .outOfRangeBothSides:
421+
if sliceFromLeft == 0 { return }
422+
if sliceFromRight == 0 { return }
423+
bounds =
424+
base.index(
425+
numericCast(sliceFromLeft - 1),
426+
stepsFrom: base.startIndex)
427+
..<
428+
base.index(
429+
numericCast(elements.count - sliceFromRight + 1),
430+
stepsFrom: base.startIndex)
431+
break
432+
case .baseEndIndex:
433+
if sliceFromRight == 0 { return }
434+
bounds = sliceEndIndex..<base.endIndex
435+
break
436+
}
437+
438+
let count: Int = numericCast(
439+
base.distance(from: bounds.lowerBound, to: bounds.upperBound))
440+
let newValues = makeWrappedCollection(Array(elements[0..<count]))
441+
let newSlice = newValues[newValues.startIndex..<newValues.endIndex]
442+
443+
if resiliencyChecks.subscriptOnOutOfBoundsIndicesBehavior == .trap {
444+
expectCrashLater()
445+
slice[bounds] = newSlice
446+
} else {
447+
expectFailure {
448+
slice[bounds] = newSlice
449+
}
450+
}
451+
}
452+
}
453+
270454
//===----------------------------------------------------------------------===//
271455
// _withUnsafeMutableBufferPointerIfSupported()
272456
//===----------------------------------------------------------------------===//

validation-test/stdlib/Slice.swift.gyb

-55
Original file line numberDiff line numberDiff line change
@@ -111,59 +111,4 @@ extension MutableSlice {
111111
}
112112
*/
113113

114-
SliceTests.test("MutableSlice.subscript(_: Index)/{get,set}") {
115-
for test in subscriptRangeTests {
116-
typealias Base = MinimalMutableCollection<OpaqueValue<Int>>
117-
Base.Index.trapOnRangeCheckFailure.value = false
118-
let base = Base(elements: test.collection)
119-
let bounds = test.bounds(in: base)
120-
var slice = MutableSlice(base: base, bounds: bounds)
121-
expectType(MutableSlice<Base>.self, &slice)
122-
123-
for i in base[bounds].indices {
124-
// Test getter.
125-
var element = slice[i]
126-
expectType(OpaqueValue<Int>.self, &element)
127-
expectEqual(base[i].value, element.value)
128-
}
129-
130-
do {
131-
var sliceForSetter = slice
132-
for i in base[bounds].indices {
133-
// Test setter.
134-
sliceForSetter[i].value += 1
135-
expectEqual(base[i].value + 1, sliceForSetter[i].value)
136-
}
137-
}
138-
139-
var sliceForSetter = slice
140-
for (i, index) in base.indices.enumerated() {
141-
if test.bounds.contains(i) {
142-
// Test getter.
143-
expectEqual(base[index].value, slice[index].value)
144-
145-
// Test setter.
146-
sliceForSetter[index].value += 1
147-
expectEqual(base[index].value + 1, sliceForSetter[index].value)
148-
} else {
149-
// `MutableSlice` disallows out-of-bounds indices when the underlying
150-
// index type can perform a range check.
151-
152-
// Test getter.
153-
expectFailure {
154-
_blackHole(slice[index])
155-
}
156-
157-
// Test setter.
158-
expectFailure {
159-
sliceForSetter[index].value += 1
160-
}
161-
}
162-
}
163-
164-
// Check that none of the mutations above affected the original collection.
165-
expectEqualSequence(test.collection, base) { $0.value == $1.value }
166-
}
167-
}
168-
169114
runAllTests()

0 commit comments

Comments
 (0)