Files
swift-mirror/validation-test/stdlib/Lazy.swift.gyb

891 lines
27 KiB
Plaintext

//===--- Lazy.swift - Tests for LazySequence and LazyCollection -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %S/../../utils/gyb %s -o %t/Lazy.swift
// RUN: %S/../../utils/line-directive %t/Lazy.swift -- %target-build-swift %t/Lazy.swift -o %t/a.out
// RUN: %S/../../utils/line-directive %t/Lazy.swift -- %target-run %t/a.out
// REQUIRES: executable_test
import StdlibUnittest
import StdlibCollectionUnittest
// Also import modules which are used by StdlibUnittest internally. This
// workaround is needed to link all required libraries in case we compile
// StdlibUnittest with -sil-serialize-all.
#if _runtime(_ObjC)
import ObjectiveC
#endif
var LazyTestSuite = TestSuite("Lazy")
protocol TestProtocol1 {}
//===----------------------------------------------------------------------===//
// Repeated
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Element'.
extension Repeated where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("Repeated") {
checkRandomAccessCollection(
[] as Array<OpaqueValue<Int>>,
repeatElement(OpaqueValue(42), count: 0))
{ $0.value == $1.value }
checkRandomAccessCollection(
[ OpaqueValue(42) ] as Array<OpaqueValue<Int>>,
repeatElement(OpaqueValue(42), count: 1))
{ $0.value == $1.value }
checkRandomAccessCollection(
[ OpaqueValue(42), OpaqueValue(42), OpaqueValue(42) ] as Array<OpaqueValue<Int>>,
repeatElement(OpaqueValue(42), count: 3))
{ $0.value == $1.value }
}
// FIXME: trap tests.
//===----------------------------------------------------------------------===//
// CollectionOfOne
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Element'.
extension CollectionOfOne where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("CollectionOfOne") {
checkRandomAccessCollection(
[ OpaqueValue(42) ],
CollectionOfOne(OpaqueValue(42))) { $0.value == $1.value }
}
// FIXME: trap tests.
//===----------------------------------------------------------------------===//
// IteratorOverOne
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Element'.
extension IteratorOverOne where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("IteratorOverOne") {
checkIterator(
[] as Array<OpaqueValue<Int>>,
IteratorOverOne(_elements: nil as Optional<OpaqueValue<Int>>))
{ $0.value == $1.value }
checkIterator(
[ OpaqueValue(42) ] as Array<OpaqueValue<Int>>,
IteratorOverOne(_elements: OpaqueValue(42)))
{ $0.value == $1.value }
}
//===----------------------------------------------------------------------===//
// EmptyCollection
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Element'.
extension EmptyCollection where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("EmptyCollection") {
checkRandomAccessCollection(
[],
EmptyCollection<OpaqueValue<Int>>()) { $0.value == $1.value }
}
// FIXME: trap tests.
//===----------------------------------------------------------------------===//
// EmptyIterator
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Element'.
extension EmptyIterator where Element : TestProtocol1 {
var _elementIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("EmptyIterator") {
checkIterator(
[] as Array<OpaqueValue<Int>>,
EmptyIterator<OpaqueValue<Int>>())
{ $0.value == $1.value }
}
// FIXME: trap tests.
//===----------------------------------------------------------------------===//
// lazy()
//===----------------------------------------------------------------------===//
LazyTestSuite.test("isEmpty") {
expectTrue((0..<0).lazy.isEmpty)
expectFalse((0...0).lazy.isEmpty)
}
LazyTestSuite.test("firstLast") {
expectOptionalEqual(7 as Int, (7..<42).lazy.first)
expectOptionalEqual(41 as Int, (7..<42).lazy.last)
expectEmpty((7..<7).lazy.first)
expectEmpty((7..<7).lazy.last)
}
//===----------------------------------------------------------------------===//
// LazySequence
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension LazySequence where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
LazyTestSuite.test("LazySequence<Sequence>/underestimatedCount") {
let s = MinimalSequence(
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
underestimatedCount: .value(42))
var lazySeq = s.lazy
expectType(LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &lazySeq)
expectEqual(42, lazySeq.underestimatedCount)
}
%for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
LazyTestSuite.test("LazySequence<${traversal}Collection>/underestimatedCount") {
let s = Minimal${traversal}Collection(
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
underestimatedCount: .value(42))
var lazySeq = s.lazy
expectType(
LazyCollection<
Minimal${traversal}Collection<OpaqueValue<Int>>
>.self,
&lazySeq)
expectEqual(42, lazySeq.underestimatedCount)
}
%end
//===----------------------------------------------------------------------===//
// MapSequence
//===----------------------------------------------------------------------===//
LazyTestSuite.test("MapSequence<Sequence>/underestimatedCount") {
let s = MinimalSequence(
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
underestimatedCount: .value(42))
var lazyMap = s.lazy.map { OpaqueValue(Int32($0.value)) }
expectType(
LazyMapSequence<MinimalSequence<OpaqueValue<Int>>, OpaqueValue<Int32>>.self,
&lazyMap)
expectEqual(42, lazyMap.underestimatedCount)
}
struct SequenceWithCustomUnderestimatedCount : Sequence {
init(_ data: [Int]) {
self._data = MinimalSequence(elements: data.map(OpaqueValue.init))
}
func makeIterator() -> MinimalSequence<OpaqueValue<Int>>.Iterator {
return _data.makeIterator()
}
var underestimatedCount: Int {
SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled += 1
return _data.underestimatedCount
}
static var timesUnderestimatedCountWasCalled: Int = 0
let _data: MinimalSequence<OpaqueValue<Int>>
}
LazyTestSuite.test("LazySequence.array") {
SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled = 0
let base = SequenceWithCustomUnderestimatedCount([ 0, 30, 10, 90 ])
let lazySequence = base.lazy
let arrayFromLazy = Array(lazySequence)
expectEqual([ 0, 30, 10, 90 ], arrayFromLazy.map { $0.value })
// Lazy sequences should use underestimated count to preallocate array
// storage.
expectEqual(1, SequenceWithCustomUnderestimatedCount.timesUnderestimatedCountWasCalled)
expectEqualSequence(
[], Array(base).map { $0.value }, "sequence should be consumed")
}
%for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
LazyTestSuite.test("MapCollection<${traversal}Collection>/underestimatedCount") {
let s = Minimal${traversal}Collection(
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
underestimatedCount: .value(42))
var lazyMap = s.lazy.map {
(input: OpaqueValue<Int>) -> OpaqueValue<Int32> in
OpaqueValue(Int32(input.value))
}
expectType(
LazyMapCollection<
Minimal${traversal}Collection<OpaqueValue<Int>>, OpaqueValue<Int32>
>.self,
&lazyMap)
expectEqual(42, lazyMap.underestimatedCount)
}
%end
//===----------------------------------------------------------------------===//
// LazyCollection
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension LazyCollection where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
%for (traversal, ReversedType) in [
% ('Forward', None),
% ('Bidirectional', 'ReverseCollection'),
% ('RandomAccess', 'ReverseRandomAccessCollection')
%]:
LazyTestSuite.test("LazyCollection.array") {
let base = Minimal${traversal}Collection(
elements: [ 0, 30, 10, 90 ], underestimatedCount: .value(42))
let lazyCollection = base.lazy
let arrayFromLazy = Array(lazyCollection)
expectEqual([ 0, 30, 10, 90 ], arrayFromLazy)
// Lazy collections should not use underestimated count to preallocate array
// storage, since they have access to real count instead.
expectLE(4, arrayFromLazy.capacity)
expectGE(40, arrayFromLazy.capacity)
}
% if ReversedType is not None:
LazyTestSuite.test("LazyCollection.reversed") {
let base = Minimal${traversal}Collection(
elements: [ 0, 30, 10, 90 ].map(OpaqueValue.init),
underestimatedCount: .value(42))
let lazyCollection = base.lazy
var reversed = lazyCollection.reversed()
expectType(
LazyCollection<${ReversedType}<Minimal${traversal}Collection<OpaqueValue<Int>>>>.self,
&reversed)
check${traversal}Collection(
[ 90, 10, 30, 0 ].map(OpaqueValue.init) as [OpaqueValue<Int>],
reversed) { $0.value == $1.value }
var reversedTwice = reversed.reversed()
expectType(
LazyCollection<${ReversedType}<${ReversedType}<Minimal${traversal}Collection<OpaqueValue<Int>>>>>.self,
&reversedTwice)
check${traversal}Collection(
[ 0, 30, 10, 90 ].map(OpaqueValue.init) as [OpaqueValue<Int>],
reversedTwice) { $0.value == $1.value }
}
% end
%end
//===----------------------------------------------------------------------===//
// ReverseCollection
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension ReverseCollection where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
//===----------------------------------------------------------------------===//
// ReverseIndex
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension ReverseIndex where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
//===----------------------------------------------------------------------===//
// RandomAccessReverseCollection
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension ReverseRandomAccessCollection where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
//===----------------------------------------------------------------------===//
// ReverseRandomAccessIndex
//===----------------------------------------------------------------------===//
// Check that the generic parameter is called 'Base'.
extension ReverseRandomAccessIndex where Base : TestProtocol1 {
var _baseIsTestProtocol1: Bool {
fatalError("not implemented")
}
}
var tests = TestSuite("NewLazy")
tests.test("LazySequence/Sequence") {
let expected = (0..<100).map(OpaqueValue.init)
var actual = MinimalSequence(elements: expected).lazy
expectType(
LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &actual)
// Asking for .lazy again doesn't re-wrap the type
var again = actual.lazy
expectType(
LazySequence<MinimalSequence<OpaqueValue<Int>>>.self, &again)
var elements = actual.elements
// Expect .elements to strip a lazy wrapper
expectType(MinimalSequence<OpaqueValue<Int>>.self, &elements)
checkSequence(expected, actual, resiliencyChecks: .none) {
$0.value == $1.value
}
}
func expectSequencePassthrough<
S : Sequence,
Base : Sequence
where
S : LazySequenceProtocol, Base : LoggingType,
Base.Iterator.Element == S.Iterator.Element
>(s: S, base: Base, arbitraryElement: S.Iterator.Element, count: Int) {
let baseType = base.dynamicType
SequenceLog.makeIterator.expectIncrement(baseType) { _ = s.makeIterator() }
SequenceLog.underestimatedCount.expectIncrement(baseType) {
_ = s.underestimatedCount
}
SequenceLog._customContainsEquatableElement.expectIncrement(baseType) {
_ = s._customContainsEquatableElement(arbitraryElement)
}
SequenceLog._copyToNativeArrayBuffer.expectIncrement(baseType) {
_ = s._copyToNativeArrayBuffer()
}
SequenceLog._copyContents.expectIncrement(baseType) { () -> Void in
let buf = UnsafeMutablePointer<S.Iterator.Element>(allocatingCapacity: count)
let end = s._copyContents(initializing: buf)
expectTrue(end <= buf + count)
buf.deinitialize(count: end - buf)
buf.deallocateCapacity(count)
}
}
tests.test("LazySequence/Passthrough") {
// Test that operations that might be optimized are passed
// through to the underlying sequence.
let a = (0..<100).map(OpaqueValue.init)
let base = LoggingSequence(a)
expectSequencePassthrough(
base.lazy,
base: base, arbitraryElement: OpaqueValue(0), count: a.count)
}
% for traversal in 'Forward', 'Bidirectional', 'RandomAccess':
tests.test("LazyCollection/Collection/${traversal}") {
let expected = (0..<100).map(OpaqueValue.init)
let base = Minimal${traversal}Collection(elements: expected)
var actual = base.lazy
expectType(
LazyCollection<Minimal${traversal}Collection<OpaqueValue<Int>>>.self,
&actual)
// Asking for .lazy again doesn't re-wrap the type
var again = actual.lazy
expectType(
LazyCollection<Minimal${traversal}Collection<OpaqueValue<Int>>>.self,
&again)
check${traversal}Collection(
expected, base.lazy, resiliencyChecks: .none
) { $0.value == $1.value }
var elements = base.lazy.elements
expectType(Minimal${traversal}Collection<OpaqueValue<Int>>.self, &elements)
}
% end
tests.test("LazyCollection/Passthrough") {
let expected = (0..<100).map(OpaqueValue.init)
let base = LoggingCollection(expected)
expectSequencePassthrough(
base.lazy,
base: base.lazy._base,
arbitraryElement: OpaqueValue(0),
count: Int(expected.count))
let s = base.lazy
let baseType = base.dynamicType
let startIndex = CollectionLog.startIndex.expectIncrement(baseType) {
s.startIndex
}
let endIndex = CollectionLog.endIndex.expectIncrement(baseType) {
s.endIndex
}
CollectionLog.subscriptIndex.expectIncrement(baseType) { _ = s[startIndex] }
CollectionLog.subscriptRange.expectUnchanged(baseType) {
_ = s[startIndex..<endIndex]
}
CollectionLog.isEmpty.expectIncrement(baseType) { _ = s.isEmpty }
CollectionLog.count.expectIncrement(baseType) { _ = s.count }
CollectionLog._customIndexOfEquatableElement.expectIncrement(baseType) {
_ = s._customIndexOfEquatableElement(OpaqueValue(0))
}
CollectionLog.first.expectIncrement(baseType) { _ = s.first }
}
//===--- Map --------------------------------------------------------------===//
tests.test("LazyMapSequence") {
let base = MinimalSequence(
elements: [2, 3, 5, 7, 11].map(OpaqueValue.init)).lazy
var calls = 0
var mapped = base.map {
(x: OpaqueValue<Int>) -> OpaqueValue<Double> in
calls += 1
return OpaqueValue(Double(x.value) / 2.0)
}
expectEqual(0, calls)
expectType(
LazyMapSequence<
MinimalSequence<OpaqueValue<Int>>,
OpaqueValue<Double>>.self,
&mapped)
let expected = [ 1.0, 1.5, 2.5, 3.5, 5.5 ].map(OpaqueValue.init)
checkSequence(expected, mapped, resiliencyChecks: .none) {
$0.value == $1.value
}
expectEqual(expected.count, calls)
}
tests.test("MapSequence/Passthrough") {
let expected = (0..<100).map(OpaqueValue.init)
let base = LoggingSequence(expected)
let mapped = base.lazy.map { OpaqueValue(Double($0.value) / 2.0) }
CollectionLog.underestimatedCount.expectIncrement(base.dynamicType) {
_ = mapped.underestimatedCount
}
// Not exactly passthrough because we wrap the result
CollectionLog.makeIterator.expectIncrement(base.dynamicType) {
_ = mapped.makeIterator()
}
}
% for traversal in 'Forward', 'Bidirectional', 'RandomAccess':
tests.test("LazyMapCollection/${traversal}") {
let base = Minimal${traversal}Collection(
elements: [2, 3, 5, 7, 11].map(OpaqueValue.init)).lazy
var calls = 0
var mapped = base.map {
(x: OpaqueValue<Int>) -> OpaqueValue<Double> in
calls += 1
return OpaqueValue(Double(x.value) / 2.0)
}
expectEqual(0, calls)
expectType(
LazyMapCollection<
Minimal${traversal}Collection<OpaqueValue<Int>>,
OpaqueValue<Double>>.self,
&mapped)
let expected = [ 1.0, 1.5, 2.5, 3.5, 5.5 ].map(OpaqueValue.init)
check${traversal}Collection(expected, mapped, resiliencyChecks: .none) {
$0.value == $1.value
}
// check${traversal}Collection makes multiple passes over the input,
// so we test that each element was transformed *at least* once.
expectLE(expected.count, calls)
}
%end
tests.test("LazyMapCollection/Passthrough") {
let expected = (0..<100).map(OpaqueValue.init)
let base = LoggingCollection(expected)
let mapped = base.lazy.map { OpaqueValue(Double($0.value) / 2.0) }
let startIndex = CollectionLog.startIndex.expectIncrement(base.dynamicType) {
mapped.startIndex
}
let endIndex = CollectionLog.endIndex.expectIncrement(base.dynamicType) {
mapped.endIndex
}
// Not exactly passthrough, because mapping transforms the result
CollectionLog.subscriptIndex.expectIncrement(base.dynamicType) {
_ = mapped[startIndex]
}
CollectionLog.isEmpty.expectIncrement(base.dynamicType) {
_ = mapped.isEmpty
}
CollectionLog.first.expectIncrement(base.dynamicType) {
_ = mapped.first
}
CollectionLog.underestimatedCount.expectIncrement(base.dynamicType) {
_ = mapped.underestimatedCount
}
// Not exactly passthrough because we wrap the result
CollectionLog.makeIterator.expectIncrement(base.dynamicType) {
_ = mapped.makeIterator()
}
}
//===--- Reverse ----------------------------------------------------------===//
tests.test("ReverseCollection") {
let expected = Array(stride(from: 11, through: 0, by: -1))
let r = 0..<12
checkRandomAccessCollection(
expected,
r.reversed())
// Check that the reverse collection is still eager
do {
var calls = 0
_ = r.reversed().map { _ in calls += 1 }
expectEqual(r.count, calls)
}
checkBidirectionalCollection(
"raboof".characters,
"foobar".characters.reversed())
// Check that the reverse collection is still eager
do {
var calls = 0
_ = "foobar".characters.reversed().map { _ in calls += 1 }
expectEqual("foobar".characters.count, calls)
}
}
enum _Void {}
struct ExpectType<T> {
static func test(_: T){ print("T") }
static func test(_: Any) { fatalError() }
static func test(_: Any) -> _Void { fatalError() }
}
tests.test("ReverseCollection/Lazy") {
// Check that reversing a lazy collection, or lazy-ing a reverse
// collection, produces the same lazy reverse collection.
do {
let base = Array(stride(from: 11, through: 0, by: -1)).lazy.map { $0 }
typealias Base = LazyMapCollection<[Int], Int>
ExpectType<Base>.test(base)
typealias LazyReversedBase = LazyCollection<
ReverseRandomAccessCollection<Base>>
let reversed = base.reversed()
ExpectType<LazyReversedBase>.test(reversed)
var calls = 0
let reversedAndMapped = reversed.map { (x) -> Int in calls += 1; return x }
expectEqual(0, calls)
checkRandomAccessCollection(0...11, reversedAndMapped)
expectNotEqual(0, calls)
}
do {
typealias Expected = LazyCollection<
ReverseCollection<String.CharacterView>
>
let base = "foobar".characters.lazy.map { $0 }
typealias Base = LazyMapCollection<String.CharacterView, Character>
ExpectType<Base>.test(base)
typealias LazyReversedBase = LazyCollection<
ReverseCollection<Base>>
let reversed = base.reversed()
ExpectType<LazyReversedBase>.test(reversed)
var calls = 0
let reversedAndMapped = reversed.map { (x) -> Character in calls += 1; return x }
expectEqual(0, calls)
checkBidirectionalCollection("raboof".characters, reversedAndMapped)
expectNotEqual(0, calls)
}
}
// Given a couple of sequences backed by FilterGenerator's, check that
// the first selects even numbers and the second selects odd numbers,
// both from an underlying sequence of whole numbers.
func checkFilterIteratorBase<
S : Sequence, I : IteratorProtocol
where
S.Iterator == LazyFilterIterator<I>,
I.Element == OpaqueValue<Int>
>(s1: S, _ s2: S) {
var iter1 = s1.makeIterator()
expectEqual(0, iter1.next()!.value)
expectEqual(2, iter1.next()!.value)
expectEqual(4, iter1.next()!.value)
var h1 = iter1.base
expectEqual(5, h1.next()!.value)
expectEqual(6, h1.next()!.value)
expectEqual(7, h1.next()!.value)
var iter2 = s2.makeIterator()
expectEqual(1, iter2.next()!.value)
expectEqual(3, iter2.next()!.value)
expectEqual(5, iter2.next()!.value)
var h2 = iter2.base
expectEqual(6, h2.next()!.value)
expectEqual(7, h2.next()!.value)
expectEqual(8, h2.next()!.value)
}
tests.test("LazyFilterSequence") {
let base = (0..<100).map(OpaqueValue.init)
var calls = 0
var filtered = MinimalSequence(elements: base).lazy.filter {
x in calls += 1;
return x.value % 2 == 0
}
expectEqual(calls, 0, "filtering was eager!")
ExpectType<
LazyFilterSequence<MinimalSequence<OpaqueValue<Int>>>
>.test(filtered)
let evens = stride(from: 0, to: 100, by: 2).map(OpaqueValue.init)
checkSequence(evens, filtered, resiliencyChecks: .none) {
$0.value == $1.value
}
expectEqual(100, calls)
// Check that it works when the first element doesn't satisfy the predicate
let odds = stride(from: 1, to: 100, by: 2).map(OpaqueValue.init)
filtered =
MinimalSequence(elements: base).lazy.filter { $0.value % 2 != 0 }
checkSequence(odds, filtered, resiliencyChecks: .none) {
$0.value == $1.value
}
// Try again using explicit construction
filtered = LazyFilterSequence(
_base: MinimalSequence(elements: base),
whereElementsSatisfy: { x in calls += 1; return x.value % 2 == 0})
expectEqual(100, calls)
// Check that it constructs the same sequence
checkSequence(evens, filtered, resiliencyChecks: .none) {
$0.value == $1.value
}
expectEqual(200, calls)
checkFilterIteratorBase(
MinimalSequence(elements: base).lazy.filter { $0.value % 2 == 0 },
MinimalSequence(elements: base).lazy.filter { $0.value % 2 != 0 })
}
tests.test("LazyFilterIndex/base") {
let base = MinimalForwardCollection(elements: (0..<100).map(OpaqueValue.init))
let evens = base.lazy.filter { $0.value % 2 == 0 }
let odds = base.lazy.filter { $0.value % 2 != 0 }
expectEqual(base.startIndex, evens.startIndex.base)
expectEqual(base.startIndex.successor(), odds.startIndex.base)
expectEqual(
base.startIndex.successor().successor(),
evens.startIndex.successor().base)
expectEqual(
base.startIndex.successor().successor().successor(),
odds.startIndex.successor().base)
}
tests.test("LazyFilterCollection") {
let base = MinimalForwardCollection(elements: (0..<100).map(OpaqueValue.init))
var calls = 0
let filtered = base.lazy.filter {
x in calls += 1;
return x.value % 2 == 0
}
expectEqual(calls, 0, "filtering was eager!")
ExpectType<
LazyFilterCollection<MinimalForwardCollection<OpaqueValue<Int>>>
>.test(filtered)
checkForwardCollection(
stride(from: 0, to: 100, by: 2).map(OpaqueValue.init), filtered,
resiliencyChecks: .none
) {
$0.value == $1.value
}
expectGE(calls, 100)
let oldCalls = calls
_ = filtered.first
expectLT(oldCalls, calls)
expectGE(oldCalls + 2, calls)
checkFilterIteratorBase(
base.lazy.filter { $0.value % 2 == 0 },
base.lazy.filter { $0.value % 2 != 0 })
}
do {
struct Sample {
var expected: Range<Int>
var data: [Range<Int>]
}
let flattenSamples: [Sample] = [
Sample(
expected: 0..<8, data: [ 1..<1, 0..<5, 7..<7, 5..<7, 7..<8 ]),
Sample(expected: 0..<8, data: [ 0..<5, 7..<7, 5..<7, 7..<8 ]),
Sample(
expected: 0..<8, data: [ 1..<1, 0..<5, 7..<7, 5..<7, 7..<8, 11..<11 ]),
Sample(
expected: 0..<16, data: [ 0..<10, 14..<14, 10..<14, 14..<16, 22..<22 ]),
Sample(expected: 0..<0, data: [ 11..<11 ]),
Sample(expected: 0..<0, data: [ 3..<3, 11..<11 ]),
Sample(expected: 0..<0, data: []),
]
for sample in flattenSamples {
let expected = sample.expected
let data = sample.data
tests.test("FlattenSequence/\(data)") {
var base = MinimalSequence(
elements: data.map { MinimalSequence(elements: $0) })
checkSequence(expected, base.flatten(), resiliencyChecks: .none)
// Checking that flatten doesn't introduce laziness
// checkSequence consumed base, so reassign
base = MinimalSequence(
elements: data.map { MinimalSequence(elements: $0) })
let flattened = base.flatten()
var calls = 0
_ = flattened.map { _ in calls += 1 }
expectEqual(
expected.count, calls,
"unexpected laziness in \(flattened.dynamicType)")
}
tests.test("FlattenSequence/Lazy/\(data)") {
// Checking that flatten doesn't remove laziness
let base = MinimalSequence(
elements: data.map { MinimalSequence(elements: $0) }
).lazy.map { $0 }
let flattened = base.flatten()
var calls = 0
_ = flattened.map { _ in calls += 1 }
expectEqual(0, calls, "unexpected eagerness in \(flattened.dynamicType)")
}
% for traversal in 'Forward', 'Bidirectional':
% t = '' if traversal == 'Forward' else traversal
tests.test("Flatten${t}Collection/\(data)") {
let base = Minimal${traversal}Collection(
elements: data.map { Minimal${traversal}Collection(elements: $0) })
let flattened = base.flatten()
check${traversal}Collection(expected, flattened, resiliencyChecks: .none)
// Checking that flatten doesn't introduce laziness
var calls = 0
_ = flattened.map { _ in calls += 1 }
expectLE(
expected.count, calls,
"unexpected laziness in \(flattened.dynamicType)")
}
tests.test("Flatten${t}Collection/Lazy\(data)") {
// Checking that flatten doesn't remove laziness
let base = Minimal${traversal}Collection(
elements: data.map { Minimal${traversal}Collection(elements: $0) }
).lazy.map { $0 }
let flattened = base.flatten()
var calls = 0
_ = flattened.map { _ in calls += 1 }
expectEqual(0, calls, "unexpected eagerness in \(flattened.dynamicType)")
}
% end
}
}
runAllTests()