blob: 464327476729674d9a8e01da674b20132a9b5ea6 [file] [log] [blame]
// -*- swift -*-
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test
% import os.path
% import gyb
import StdlibUnittest
import StdlibCollectionUnittest
// Extend LoggingSequence to shadow the new operation. When
// requirements are added to a protocol 'P', there should be an
// implementation in 'InstrumentedP' that does some bookkeeping for
// testing (like counting calls to the operation) and then dispatches
// to the same operation on its 'base' member. InstrumentedSequence
// already contains implementations of all the Sequence
// requirements.
var _nonCustomizableOperation = TypeIndexed(0)
extension SequenceLog {
static var nonCustomizableOperation : TypeIndexed<Int> {
get {return _nonCustomizableOperation}
set {_nonCustomizableOperation = newValue}
}
}
extension LoggingSequence {
func nonCustomizableOperation() {
Log.nonCustomizableOperation[type(of: self)] += 1
return base.nonCustomizableOperation()
}
}
// Add a non-customizable operation to sequence
extension Sequence {
func nonCustomizableOperation() {}
}
var SequenceTypeTests = TestSuite("Sequence")
//===----------------------------------------------------------------------===//
// FIXME: add tests for:
//
// - Array, ContiguousArray and ArraySlice as inputs. These types special-case
// a lot of collection behavior for performance reasons. Not to even mention
// that these are important types to test in any case.
//
// - NaN behavior of floating point types, combined with these generic
// algorithms, should make sense if possible. For example,
// [1.0, Double.nan].starts(with: [1.0, 2.0]) should be false.
//===----------------------------------------------------------------------===//
// min(), max()
//===----------------------------------------------------------------------===//
% for algorithmKind in ['min', 'max']:
% AlgorithmKind = algorithmKind.capitalize()
SequenceTypeTests.test("${algorithmKind}/WhereElementIsComparable") {
for test in minMaxTests {
let s = MinimalSequence<MinimalComparableValue>(
elements: test.sequence.enumerated().map {
MinimalComparableValue($1, identity: $0)
})
var maybeResult = s.${algorithmKind}()
expectType(Optional<MinimalComparableValue>.self, &maybeResult)
if let result = maybeResult {
expectEqual(
test.expected${AlgorithmKind}Value!, result.value,
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expected${AlgorithmKind}Index!, result.identity,
stackTrace: SourceLocStack().with(test.loc))
} else {
expectNil(
test.expected${AlgorithmKind}Value,
stackTrace: SourceLocStack().with(test.loc))
expectNil(
test.expected${AlgorithmKind}Index,
stackTrace: SourceLocStack().with(test.loc))
}
expectEqual([], s.map { $0.value }, "sequence should be consumed")
}
}
SequenceTypeTests.test("${algorithmKind}/Predicate") {
for test in minMaxTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.enumerated().map {
OpaqueValue($1, identity: $0)
})
var timesClosureWasCalled = 0
var maybeResult = s.${algorithmKind} {
(lhs, rhs) -> Bool in
timesClosureWasCalled += 1
return lhs.value < rhs.value
}
expectType(Optional<OpaqueValue<Int>>.self, &maybeResult)
if let result = maybeResult {
expectEqual(
test.expected${AlgorithmKind}Value!, result.value,
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expected${AlgorithmKind}Index!, result.identity,
stackTrace: SourceLocStack().with(test.loc))
} else {
expectNil(
test.expected${AlgorithmKind}Value,
stackTrace: SourceLocStack().with(test.loc))
expectNil(
test.expected${AlgorithmKind}Index,
stackTrace: SourceLocStack().with(test.loc))
}
expectEqual([], s.map { $0.value }, "sequence should be consumed")
expectEqual(
max(0, test.sequence.count - 1), timesClosureWasCalled,
"max() should be eager and should only call its predicate"
+ " once per element")
}
}
% end
//===----------------------------------------------------------------------===//
// IteratorSequence
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
protocol TestProtocol1 {}
extension IteratorSequence where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
//===--- Demonstrate technique for testing generic dispatching ------------===//
// A counter we can use to record calls to our non-customizable operation
SequenceTypeTests.test("Demonstration/NotCustomizable") {
let tester = SequenceLog.dispatchTester([OpaqueValue(1)])
tester.nonCustomizableOperation()
expectNotCustomizable(tester, tester.log.nonCustomizableOperation)
}
SequenceTypeTests.test("IteratorSequence/IteratorProtocol/empty") {
do {
let data: [OpaqueValue<Int>] = []
let base = MinimalIterator(data)
var iter = IteratorSequence(base)
expectType(
IteratorSequence<MinimalIterator<OpaqueValue<Int>>>.self,
&iter)
checkIterator(data, iter, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let data: [OpaqueValue<Int>] = []
let base = data.makeIterator()
var iter = IteratorSequence(base)
expectType(
IteratorSequence<IndexingIterator<Array<OpaqueValue<Int>>>>.self,
&iter)
checkIterator(data, iter) { $0.value == $1.value }
}
}
SequenceTypeTests.test("IteratorSequence/IteratorProtocol") {
do {
let data: [OpaqueValue<Int>] = []
let base = MinimalIterator(data)
var iter = IteratorSequence(base)
expectType(
IteratorSequence<MinimalIterator<OpaqueValue<Int>>>.self,
&iter)
checkIterator(data, iter, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let data: [OpaqueValue<Int>] = []
let base = data.makeIterator()
var iter = IteratorSequence(base)
expectType(
IteratorSequence<IndexingIterator<Array<OpaqueValue<Int>>>>.self,
&iter)
checkIterator(data, iter) { $0.value == $1.value }
}
}
SequenceTypeTests.test("IteratorSequence/Sequence/empty") {
do {
let data = [ 10, 20, 30 ].map(OpaqueValue.init)
let base = MinimalIterator(data)
var iter = IteratorSequence(base)
expectType(
IteratorSequence<MinimalIterator<OpaqueValue<Int>>>.self,
&iter)
checkSequence(data, iter, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let data = [ 10, 20, 30 ].map(OpaqueValue.init)
let base = data.makeIterator()
var iter = IteratorSequence(base)
expectType(
IteratorSequence<IndexingIterator<Array<OpaqueValue<Int>>>>.self,
&iter)
checkSequence(data, iter) { $0.value == $1.value }
}
}
SequenceTypeTests.test("IteratorSequence/Sequence") {
do {
let data = [ 10, 20, 30 ].map(OpaqueValue.init)
let base = MinimalIterator(data)
var iter = IteratorSequence(base)
expectType(
IteratorSequence<MinimalIterator<OpaqueValue<Int>>>.self,
&iter)
checkSequence(data, iter, resiliencyChecks: .none) { $0.value == $1.value }
}
do {
let data = [ 10, 20, 30 ].map(OpaqueValue.init)
let base = data.makeIterator()
var iter = IteratorSequence(base)
expectType(
IteratorSequence<IndexingIterator<Array<OpaqueValue<Int>>>>.self,
&iter)
checkSequence(data, iter) { $0.value == $1.value }
}
}
//===----------------------------------------------------------------------===//
// enumerated()
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension EnumeratedIterator where Base : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
extension EnumeratedSequence where Base : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
SequenceTypeTests.test("enumerated()") {
typealias Element = (offset: Int, element: OpaqueValue<Int>)
func compareElements(_ lhs: Element, rhs: Element) -> Bool {
return lhs.0 == rhs.0 && lhs.1.value == rhs.1.value
}
for test in enumerateTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
var result = s.enumerated()
expectType(
EnumeratedSequence<MinimalSequence<OpaqueValue<Int>>>.self,
&result)
checkSequence(
test.expected.map {
(offset: $0.0, element: OpaqueValue($0.1))
} as [Element],
result,
resiliencyChecks: .none, sameValue: compareElements)
expectEqual([], s.map { $0.value }, "sequence should be consumed")
}
}
//===----------------------------------------------------------------------===//
// starts(with:)
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("starts(with:)/WhereElementIsEquatable") {
for test in startsWithTests {
do {
let s = MinimalSequence<MinimalEquatableValue>(
elements: test.sequence.map(MinimalEquatableValue.init))
let prefix = MinimalSequence<MinimalEquatableValue>(
elements: test.prefix.map(MinimalEquatableValue.init))
expectEqual(
test.expected,
s.starts(with: prefix),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverPrefix, prefix.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and prefix.
do {
let s = MinimalCollection<MinimalEquatableValue>(
elements: test.sequence.map(MinimalEquatableValue.init))
let prefix = MinimalSequence<MinimalEquatableValue>(
elements: test.prefix.map(MinimalEquatableValue.init))
expectEqual(
test.expected,
s.starts(with: prefix),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverPrefix, prefix.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
SequenceTypeTests.test("starts(with:)/Predicate") {
for test in startsWithTests {
do {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let prefix = MinimalSequence<OpaqueValue<Int>>(
elements: test.prefix.map(OpaqueValue.init))
expectEqual(
test.expected,
s.starts(with: prefix) { $0.value == $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverPrefix, prefix.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
do {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map { OpaqueValue($0 * 2) })
let prefix = MinimalSequence<OpaqueValue<Int>>(
elements: test.prefix.map(OpaqueValue.init))
expectEqual(
test.expected,
s.starts(with: prefix) { $0.value / 2 == $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value / 2 },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverPrefix, prefix.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and prefix.
do {
let s = MinimalCollection<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let prefix = MinimalSequence<OpaqueValue<Int>>(
elements: test.prefix.map(OpaqueValue.init))
expectEqual(
test.expected,
s.starts(with: prefix) { $0.value == $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverPrefix, prefix.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
//===----------------------------------------------------------------------===//
// equal()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("elementsEqual/WhereElementIsEquatable") {
for test in elementsEqualTests {
do {
let s = MinimalSequence<MinimalEquatableValue>(
elements: test.sequence.map(MinimalEquatableValue.init))
let other = MinimalSequence<MinimalEquatableValue>(
elements: test.other.map(MinimalEquatableValue.init))
expectEqual(
test.expected,
s.elementsEqual(other),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and other.
do {
let s = MinimalCollection<MinimalEquatableValue>(
elements: test.sequence.map(MinimalEquatableValue.init))
let other = MinimalSequence<MinimalEquatableValue>(
elements: test.other.map(MinimalEquatableValue.init))
expectEqual(
test.expected,
s.elementsEqual(other),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
SequenceTypeTests.test("elementsEqual/Predicate") {
for test in elementsEqualTests {
do {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let other = MinimalSequence<OpaqueValue<Int>>(
elements: test.other.map(OpaqueValue.init))
expectEqual(
test.expected,
s.elementsEqual(other) { $0.value == $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and other.
do {
let s = MinimalCollection<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let other = MinimalSequence<OpaqueValue<Int>>(
elements: test.other.map(OpaqueValue.init))
expectEqual(
test.expected,
s.elementsEqual(other) { $0.value == $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
//===----------------------------------------------------------------------===//
// lexicographicallyPrecedes()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("lexicographicallyPrecedes(_:)/WhereElementIsComparable") {
for test in lexicographicallyPrecedesTests {
do {
let s = MinimalSequence<MinimalComparableValue>(
elements: test.sequence.map(MinimalComparableValue.init))
let other = MinimalSequence<MinimalComparableValue>(
elements: test.other.map(MinimalComparableValue.init))
expectEqual(
test.expected.isLT(),
s.lexicographicallyPrecedes(other),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and other.
do {
let s = MinimalCollection<MinimalComparableValue>(
elements: test.sequence.map(MinimalComparableValue.init))
let other = MinimalSequence<MinimalComparableValue>(
elements: test.other.map(MinimalComparableValue.init))
expectEqual(
test.expected.isLT(),
s.lexicographicallyPrecedes(other),
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
SequenceTypeTests.test("lexicographicallyPrecedes(_:)/Predicate") {
for test in lexicographicallyPrecedesTests {
do {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let other = MinimalSequence<OpaqueValue<Int>>(
elements: test.other.map(OpaqueValue.init))
expectEqual(
test.expected.isLT(),
s.lexicographicallyPrecedes(other) { $0.value < $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
// Use different types for the sequence and other.
do {
let s = MinimalCollection<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let other = MinimalSequence<OpaqueValue<Int>>(
elements: test.other.map(OpaqueValue.init))
expectEqual(
test.expected.isLT(),
s.lexicographicallyPrecedes(other) { $0.value < $1.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.sequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
}
//===----------------------------------------------------------------------===//
// contains()
//===----------------------------------------------------------------------===//
typealias StrictSequenceOfEquatable = MinimalSequence<MinimalEquatableValue>
// FIXME: rename in StdlibUnittest
// typealias StrictSequence = MinimalSequence
SequenceTypeTests.test("contains/WhereElementIsEquatable/dispatch") {
let tester = SequenceLog.dispatchTester([MinimalEquatableValue(1)])
_ = tester.contains(MinimalEquatableValue(1))
expectCustomizable(tester, tester.log._customContainsEquatableElement)
}
func callStaticContains(
_ set: Set<MinimalHashableValue>,
_ element: MinimalHashableValue
) -> Bool {
return set.contains(element)
}
func callGenericContains<
S : Sequence
>(_ sequence: S, _ element: S.Iterator.Element) -> Bool
where S.Iterator.Element : Equatable {
return sequence.contains(element)
}
% for dispatch in ['Static', 'Generic']:
// FIXME: implement the same optimization for Dictionary.
// FIXME: move to the file where other Set tests live.
SequenceTypeTests.test("Set<T>.contains/CustomImplementation/${dispatch}") {
for test in findTests {
let s = Set<MinimalHashableValue>(
test.sequence.map { MinimalHashableValue($0.value) })
MinimalHashableValue.timesEqualEqualWasCalled = 0
MinimalHashableValue.timesHashIntoWasCalled = 0
expectEqual(
test.expected != nil,
call${dispatch}Contains(s, MinimalHashableValue(test.element.value)),
stackTrace: SourceLocStack().with(test.loc))
if test.sequence.isEmpty {
expectEqual(
0, MinimalHashableValue.timesEqualEqualWasCalled,
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
0, MinimalHashableValue.timesHashIntoWasCalled,
stackTrace: SourceLocStack().with(test.loc))
} else {
expectNotEqual(
0, MinimalHashableValue.timesHashIntoWasCalled,
stackTrace: SourceLocStack().with(test.loc))
}
if test.expected != nil {
expectNotEqual(
0, MinimalHashableValue.timesEqualEqualWasCalled,
stackTrace: SourceLocStack().with(test.loc))
}
}
}
% end
SequenceTypeTests.test("contains/Predicate") {
for test in findTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map { OpaqueValue($0.value) })
expectEqual(
test.expected != nil,
s.contains { $0.value == test.element.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence.map { $0.value }, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
SequenceTypeTests.test("allSatisfy/Predicate") {
for test in findTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map { OpaqueValue($0.value) })
expectEqual(
test.expected == nil,
s.allSatisfy { $0.value != test.element.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverSequence.map { $0.value }, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===----------------------------------------------------------------------===//
// reduce()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("reduce") {
for test in reduceTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
var timesClosureWasCalled = 0
let result = s.reduce(OpaqueValue<[Int]>([])) {
(partialResult: OpaqueValue<[Int]>, element: OpaqueValue<Int>)
-> OpaqueValue<[Int]> in
timesClosureWasCalled += 1
return OpaqueValue<[Int]>(partialResult.value + [element.value])
}
expectEqual(test.sequence, result.value)
expectEqual([], s.map { $0.value }, "sequence should be consumed")
expectEqual(
test.sequence.count, timesClosureWasCalled,
"reduce() should be eager and should only call its predicate"
+ "once per element")
}
}
//===----------------------------------------------------------------------===//
// reversed()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("reverse/Sequence") {
for test in reverseTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
var result = s.reversed()
expectType([OpaqueValue<Int>].self, &result)
expectEqual(
test.expected, result.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual([], s.map { $0.value }, "sequence should be consumed")
}
}
SequenceTypeTests.test("reverse/WhereIndexIsBidirectional,BidirectionalReverseView") {
for test in reverseTests {
let s = MinimalBidirectionalCollection<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
var result = s.reversed()
expectType(
ReversedCollection<MinimalBidirectionalCollection<OpaqueValue<Int>>>.self,
&result)
expectEqual(
test.expected, result.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
// Check ReversedCollection's Collection conformance.
checkBidirectionalCollection(
test.expected.map(OpaqueValue.init) as [OpaqueValue<Int>],
result) { $0.value == $1.value }
}
}
SequenceTypeTests.test("reverse/WhereIndexIsRandomAccess,RandomAccessReverseView") {
for test in reverseTests {
let s = MinimalRandomAccessCollection<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
var result = s.reversed()
expectType(
ReversedCollection<MinimalRandomAccessCollection<OpaqueValue<Int>>>.self,
&result)
expectEqual(
test.expected, result.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
// Check ReversedRandomAccessCollection Collection conformance.
let expected = test.expected.map(OpaqueValue.init) as [OpaqueValue<Int>]
checkRandomAccessCollection(expected, result) { $0.value == $1.value }
}
}
//===----------------------------------------------------------------------===//
// filter()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("filter/Sequence/Semantics") {
for test in filterTests {
for underestimatedCountBehavior in [
UnderestimatedCountBehavior.precise,
UnderestimatedCountBehavior.half,
UnderestimatedCountBehavior.value(0)
] {
let s = DefaultedSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init),
underestimatedCount: underestimatedCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
var result = s.filter {
(element) in
_blackHole(closureLifetimeTracker)
timesClosureWasCalled += 1
return test.includeElement(element.value)
}
expectType([OpaqueValue<Int>].self, &result)
expectEqual(test.expected, result.map { $0.value })
expectEqual([], s.map { $0.value }, "sequence should be consumed")
expectEqual(
test.sequence.count, timesClosureWasCalled,
"filter() should be eager and should only call its predicate"
+ "once per element")
expectGE(
2 * result.count, result.capacity,
"filter() should not reserve capacity (it does not know how much the"
+ "predicate will filter out)")
}
}
}
//===----------------------------------------------------------------------===//
// map()
//===----------------------------------------------------------------------===//
var MinimalSequenceWithCustomMap_timesMapWasCalled: Int = 0
% for Implementation in ['Default', 'Custom']:
struct MinimalSequenceWith${Implementation}Map<Element> : Sequence {
init(_ data: [Element], underestimatedCount: UnderestimatedCountBehavior) {
self._data = MinimalSequence(
elements: data, underestimatedCount: underestimatedCount)
}
func makeIterator() -> MinimalIterator<Element> {
return _data.makeIterator()
}
var _data: MinimalSequence<Element>
% if Implementation == 'Custom':
static var timesMapWasCalled: Int {
get {
return MinimalSequenceWithCustomMap_timesMapWasCalled
}
set {
MinimalSequenceWithCustomMap_timesMapWasCalled = newValue
}
}
func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
MinimalSequenceWithCustomMap.timesMapWasCalled += 1
return try _data.map(transform)
}
% end
}
% end
func callStaticSequenceMap<T>(
_ sequence: MinimalSequenceWithDefaultMap<OpaqueValue<Int>>,
transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = sequence.map(transform)
expectType([T].self, &result)
return result
}
func callStaticSequenceMap<T>(
_ sequence: MinimalSequenceWithCustomMap<OpaqueValue<Int>>,
transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = sequence.map(transform)
expectType([T].self, &result)
return result
}
func callGenericSequenceMap<S : Sequence, T>(
_ sequence: S,
transform: (S.Iterator.Element) -> T
) -> [T] {
var result = sequence.map(transform)
expectType([T].self, &result)
return result
}
% for dispatch in ['Static', 'Generic']:
SequenceTypeTests.test(
"map/Sequence/${Implementation}Implementation/${dispatch}"
) {
for test in mapTests {
for underestimatedCountBehavior in [
UnderestimatedCountBehavior.precise,
UnderestimatedCountBehavior.half,
UnderestimatedCountBehavior.value(0)
] {
let s = MinimalSequenceWith${Implementation}Map<OpaqueValue<Int>>(
test.sequence.map(OpaqueValue.init),
underestimatedCount: underestimatedCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
var result = call${dispatch}SequenceMap(s) {
(element: OpaqueValue<Int>) -> OpaqueValue<Int32> in
_blackHole(closureLifetimeTracker)
timesClosureWasCalled += 1
return OpaqueValue(Int32(test.transform(element.value)))
}
expectType([OpaqueValue<Int32>].self, &result)
expectEqual(test.expected, result.map { $0.value })
expectEqual([], s.map { $0.value }, "sequence should be consumed")
expectEqual( test.sequence.count, timesClosureWasCalled,
"map() should be eager and should only call its predicate"
+ "once per element")
}
}
}
% end
//===----------------------------------------------------------------------===//
// flatMap()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("flatMap/Sequence") {
for test in flatMapTests {
for underestimatedCountBehavior in [
UnderestimatedCountBehavior.precise,
UnderestimatedCountBehavior.value(0)
] {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init),
underestimatedCount: underestimatedCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
var timesClosureWasCalled = 0
var result = s.flatMap {
(element: OpaqueValue<Int>) -> MinimalSequence<OpaqueValue<Int32>> in
_blackHole(closureLifetimeTracker)
timesClosureWasCalled += 1
return MinimalSequence<OpaqueValue<Int32>>(
elements: test.transform(element.value).map { OpaqueValue(Int32($0)) })
}
expectType([OpaqueValue<Int32>].self, &result)
expectEqual(
test.expected, result.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectTrue(Array(s).isEmpty, "sequence should be consumed")
expectEqual(
test.sequence.count, timesClosureWasCalled,
"flatMap() should be eager and should only call its predicate"
+ "once per element")
expectGE(
2 * result.count, result.capacity,
"flatMap() should not reserve capacity")
}
}
}
% TLazyFlatMapTest = gyb.parse_template(os.path.join(os.path.dirname(__file__), "Inputs/flatMap.gyb"))
% LazyFlatMapTest = gyb.execute_template(TLazyFlatMapTest, Test='SequenceTypeTests', Kinds=['Sequence'])
${LazyFlatMapTest}
SequenceTypeTests.test("flatMap/Sequence/TransformProducesOptional") {
for test in flatMapToOptionalTests {
for underestimatedCountBehavior in [
UnderestimatedCountBehavior.precise,
UnderestimatedCountBehavior.value(0)
] {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init),
underestimatedCount: underestimatedCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
var result = s.compactMap {
(element: OpaqueValue<Int>) -> OpaqueValue<Int32>? in
_blackHole(closureLifetimeTracker)
timesClosureWasCalled += 1
return test.transform(element.value).map { OpaqueValue(Int32($0)) }
}
expectType([OpaqueValue<Int32>].self, &result)
expectEqual(
test.expected, result.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectTrue(Array(s).isEmpty, "sequence should be consumed")
expectEqual(
test.sequence.count, timesClosureWasCalled,
"flatMap() should be eager and should only call its predicate"
+ "once per element")
expectGE(
2 * result.count, result.capacity,
"flatMap() should not reserve capacity")
}
}
}
//===----------------------------------------------------------------------===//
// zip()
//===----------------------------------------------------------------------===//
// Check generic parameter names.
extension Zip2Sequence.Iterator
where Sequence1 : TestProtocol1, Sequence2 : TestProtocol1 {
var _generator1IsTestProtocol1: Bool {
fatalError("not implemented")
}
}
// Check generic parameter names.
extension Zip2Sequence
where Sequence1 : TestProtocol1, Sequence2 : TestProtocol1 {
var _sequence1IsTestProtocol1: Bool {
fatalError("not implemented")
}
}
SequenceTypeTests.test("zip") {
typealias Element = (OpaqueValue<Int>, OpaqueValue<Int32>)
func compareElements(_ lhs: Element, rhs: Element) -> Bool {
return lhs.0.value == rhs.0.value && lhs.1.value == rhs.1.value
}
for test in zipTests {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: test.sequence.map(OpaqueValue.init))
let other = MinimalSequence<OpaqueValue<Int32>>(
elements: test.other.map(OpaqueValue.init))
var result = zip(s, other)
expectType(
Zip2Sequence<MinimalSequence<OpaqueValue<Int>>, MinimalSequence<OpaqueValue<Int32>>>.self,
&result)
// Check for expected result and check the Zip2Sequence's Sequence
// conformance.
checkSequence(
test.expected.map { (OpaqueValue($0), OpaqueValue($1)) }, result,
stackTrace: SourceLocStack().with(test.loc), sameValue: compareElements)
// Check leftovers *after* doing checkSequence(), not before, to ensure
// that checkSequence() didn't force us to consume more elements than
// needed.
expectEqual(
test.expectedLeftoverSequence, s.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
expectEqual(
test.expectedLeftoverOther, other.map { $0.value },
stackTrace: SourceLocStack().with(test.loc))
}
}
//===----------------------------------------------------------------------===//
// underestimatedCount
//===----------------------------------------------------------------------===//
struct SequenceWithDefaultUnderestimatedCount : Sequence {
init() {}
func makeIterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
expectUnreachable()
return MinimalSequence(
elements: [ 1, 2, 3 ].map(OpaqueValue.init)
).makeIterator()
}
}
SequenceTypeTests.test("underestimatedCount/Sequence/DefaultImplementation") {
let s = SequenceWithDefaultUnderestimatedCount()
expectEqual(0, callGenericUnderestimatedCount(s))
}
struct SequenceWithCustomUnderestimatedCount : Sequence {
init(underestimatedCount: Int) {
self._underestimatedCount = underestimatedCount
}
func makeIterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
expectUnreachable()
return MinimalSequence(
elements: [ 0xffff, 0xffff, 0xffff ].map(OpaqueValue.init)
).makeIterator()
}
var underestimatedCount: Int {
return _underestimatedCount
}
let _underestimatedCount: Int
}
SequenceTypeTests.test("underestimatedCount/Sequence/CustomImplementation") {
do {
let s = SequenceWithCustomUnderestimatedCount(underestimatedCount: 5)
expectEqual(5, callGenericUnderestimatedCount(s))
}
do {
let s = SequenceWithCustomUnderestimatedCount(underestimatedCount: 42)
expectEqual(42, callGenericUnderestimatedCount(s))
}
}
//===----------------------------------------------------------------------===//
// withContiguousStorageIfAvailable()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("withContiguousMutableStorageIfAvailable")
.code {
let s = [ 1, 2, 3 ].map(OpaqueValue.init)
let tester = SequenceLog.dispatchTester(s)
let result = tester.withContiguousStorageIfAvailable { buf in
buf.reduce(0) { $0 + $1.value }
}
expectEqual(6, result)
expectCustomizable(tester, tester.log.withContiguousStorageIfAvailable)
}
//===----------------------------------------------------------------------===//
// _copyToContiguousArray()
//===----------------------------------------------------------------------===//
SequenceTypeTests.test("_copyToContiguousArray/OverestimatedCount")
.skip(.custom(
{ _isFastAssertConfiguration() },
reason: "this trap is not guaranteed to happen in -Ounchecked"))
.code {
let s = MinimalSequence<OpaqueValue<Int>>(
elements: [ 1, 2, 3 ].map(OpaqueValue.init),
underestimatedCount: .value(4))
expectCrashLater()
let array = s._copyToContiguousArray()
_blackHole(array)
}
//===----------------------------------------------------------------------===//
// Standard sequence tests
//===----------------------------------------------------------------------===//
% for Base in ['DefaultedSequence', 'MinimalSequence']:
do {
let resiliencyChecks = CollectionMisuseResiliencyChecks.all
SequenceTypeTests.addSequenceTests(
makeSequence: { (elements: [OpaqueValue<Int>]) in
return ${Base}(elements: elements)
},
wrapValue: identity,
extractValue: identity,
makeSequenceOfEquatable: { (elements: [MinimalEquatableValue]) in
return ${Base}(elements: elements)
},
wrapValueIntoEquatable: identityEq,
extractValueFromEquatable: identityEq,
resiliencyChecks: resiliencyChecks)
}
% end
runAllTests()