// -*- swift -*- // RUN: rm -rf %t ; mkdir -p %t // RUN: %S/../../utils/gyb %s -o %t/Algorithm.swift // RUN: %S/../../utils/line-directive %t/Algorithm.swift -- %target-build-swift %t/Algorithm.swift -o %t/a.out // RUN: %S/../../utils/line-directive %t/Algorithm.swift -- %target-run %t/a.out import StdlibUnittest import SwiftPrivate var Algorithm = TestSuite("Algorithm") // FIXME(prext): remove this conformance. extension String.UnicodeScalarView : Equatable {} // FIXME(prext): remove this function. public func == ( lhs: String.UnicodeScalarView, rhs: String.UnicodeScalarView) -> Bool { return Array(lhs) == Array(rhs) } Algorithm.test("split") { expectEqual( [ "foo", " bar baz " ].map { $0.unicodeScalars }, split(" foo bar baz ".unicodeScalars, maxSplit: 1) { $0._isSpace() }) expectEqual( [ "foo", "bar", "baz" ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: false) { $0._isSpace() }) expectEqual( [ "", "", "foo", "", "", "bar", "baz", "" ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: true) { $0._isSpace() }) expectEqual( [ "", "", "foo bar baz " ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: true, maxSplit: 2, isSeparator: { $0._isSpace() })) } // FIXME(prext): move this struct to the point of use. struct StartsWithTest { let expected: Bool let sequence: [Int] let prefix: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverPrefix: [Int] let loc: SourceLoc init( _ expected: Bool, _ sequence: [Int], _ prefix: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverPrefix: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.prefix = prefix self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverPrefix = expectedLeftoverPrefix self.loc = SourceLoc(file, line, comment: "test data") } } let startsWithTests = [ // Corner cases. StartsWithTest(true, [], [], [], []), StartsWithTest(false, [], [ 1 ], [], []), StartsWithTest(true, [ 1 ], [], [], []), // Equal sequences. StartsWithTest(true, [ 1 ], [ 1 ], [], []), StartsWithTest(true, [ 1, 2 ], [ 1, 2 ], [], []), // Proper prefix. StartsWithTest(true, [ 0, 1, 2 ], [ 0, 1 ], [], []), StartsWithTest(false, [ 0, 1 ], [ 0, 1, 2 ], [], []), StartsWithTest(true, [ 1, 2, 3, 4 ], [ 1, 2 ], [ 4 ], []), StartsWithTest(false, [ 1, 2 ], [ 1, 2, 3, 4 ], [], [ 4 ]), // Not a prefix. StartsWithTest(false, [ 1, 2, 3, 4 ], [ 1, 2, 10 ], [ 4 ], []), StartsWithTest(false, [ 1, 2, 10 ], [ 1, 2, 3, 4 ], [], [ 4 ]), StartsWithTest(false, [ 1, 2, 3, 4, 10 ], [ 1, 2, 10 ], [ 4, 10 ], []), StartsWithTest(false, [ 1, 2, 10 ], [ 1, 2, 3, 4, 10 ], [], [ 4, 10 ]), ] // FIXME(prext): remove this function. func checkStartsWith( expected: Bool, sequence: [Int], prefix: [Int], stackTrace: SourceLocStack ) { expectEqual(expected, startsWith(sequence, prefix), stackTrace: stackTrace) expectEqual( expected, startsWith(sequence, prefix, (==)), stackTrace: stackTrace) expectEqual( expected, startsWith(sequence.map { $0 * 2 }, prefix) { $0 / 2 == $1 }, stackTrace: stackTrace) // Test using different types for the sequence and prefix. expectEqual( expected, startsWith(ContiguousArray(sequence), prefix), stackTrace: stackTrace) expectEqual( expected, startsWith(ContiguousArray(sequence), prefix, (==)), stackTrace: stackTrace) } Algorithm.test("startsWith") { // FIXME(prext): remove these tests together with the startsWith() function when // protocol extensions land. These tests have been migrated to the new API. for test in startsWithTests { checkStartsWith( test.expected, test.sequence, test.prefix, test.loc.withCurrentLoc()) } } Algorithm.test("enumerate") { // FIXME(prext): remove these tests together with the enumerate() function when // protocol extensions land. These tests have been migrated to the new API. var result = [String]() for (i, s) in enumerate( "You will never retrieve the necronomicon!"._split(" ") ) { result.append("\(i) \(s)") } expectEqual( [ "0 You", "1 will", "2 never", "3 retrieve", "4 the", "5 necronomicon!" ], result) } Algorithm.test("equal") { // FIXME(prext): remove these tests together with the equal() function when // protocol extensions land. These tests have been migrated to the new API. var _0_4 = [0, 1, 2, 3] expectFalse(equal(_0_4, 0..<3)) expectTrue(equal(_0_4, 0..<4)) expectFalse(equal(_0_4, 0..<5)) expectFalse(equal(_0_4, 1..<4)) } Algorithm.test("equal/predicate") { func compare(lhs: (Int, Int), rhs: (Int, Int)) -> Bool { return lhs.0 == rhs.0 && lhs.1 == rhs.1 } var _0_4 = [(0, 10), (1, 11), (2, 12), (3, 13)] expectFalse(equal(_0_4, [(0, 10), (1, 11), (2, 12)], compare)) expectTrue(equal(_0_4, [(0, 10), (1, 11), (2, 12), (3, 13)], compare)) expectFalse(equal(_0_4, [(0, 10), (1, 11), (2, 12), (3, 13), (4, 14)], compare)) expectFalse(equal(_0_4, [(1, 11), (2, 12), (3, 13)], compare)) } Algorithm.test("contains") { // FIXME(prext): remove these tests together with the contains() function when // protocol extensions land. These tests have been migrated to the new API. let _0_4 = [0, 1, 2, 3] expectFalse(contains(_0_4, 7)) expectTrue(contains(_0_4, 2)) expectFalse(contains(_0_4, { $0 - 10 > 0 })) expectTrue(contains(_0_4, { $0 % 3 == 0 })) } Algorithm.test("min,max") { expectEqual(2, min(3, 2)) expectEqual(3, min(3, 7, 5)) expectEqual(3, max(3, 2)) expectEqual(7, max(3, 7, 5)) // FIXME: add tests that check that min/max return the // first element of the sequence (by reference equailty) that satisfy the // condition. } Algorithm.test("minElement,maxElement") { // FIXME(prext): remove these tests together with the minElement() function // when protocol extensions land. These tests have been migrated to the new // API. var arr = [Int](count: 10, repeatedValue: 0) for i in 0..<10 { arr[i] = i % 7 + 2 } expectEqual([2, 3, 4, 5, 6, 7, 8, 2, 3, 4], arr) expectEqual(2, minElement(arr)) expectEqual(8, maxElement(arr)) // min and max element of a slice expectEqual(3, minElement(arr[1..<5])) expectEqual(6, maxElement(arr[1..<5])) // FIXME: add tests that check that minElement/maxElement return the // first element of the sequence (by reference equailty) that satisfy the // condition. } Algorithm.test("filter/SequenceType") { // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. if true { let s = MinimalSequence([], underestimatedCount: .Overestimate) var result = filter(s) { (x: Int) -> Bool in expectUnreachable() return true } expectType([Int].self, &result) expectEqual([], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectEqual(0, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Overestimate) let result = filter(s) { (x: Int) -> Bool in false } expectEqual([], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectEqual(0, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Overestimate) let result = filter(s) { (x: Int) -> Bool in true } expectEqual([ 0, 30, 10, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = filter(s) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Overestimate) let result = filter(s) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } } Algorithm.test("filter/CollectionType") { // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. if true { let c = MinimalForwardCollection([]) var result = filter(c) { (x: Int) -> Bool in expectUnreachable() return true } expectEqual([], result) expectType([Int].self, &result) expectEqual(0, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { (x: Int) -> Bool in false } expectEqual([], result) expectEqual(0, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { (x: Int) -> Bool in true } expectEqual([ 0, 30, 10, 90 ], result) expectGE(2 * result.count, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectGE(2 * result.count, result.capacity) } } Algorithm.test("filter/eager") { // Make sure filter is eager and only calls its predicate once per element. // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. var count = 0 let one = filter(0..<10) { (x: Int)->Bool in ++count; return x == 1 } for x in one {} expectEqual(10, count) for x in one {} expectEqual(10, count) } Algorithm.test("map/SequenceType") { // FIXME(prext): remove these tests together with the map() function when // protocol extensions land. These tests have been migrated to the new API. if true { let s = MinimalSequence([], underestimatedCount: .Overestimate) var result = map(s) { (x: Int) -> Int16 in expectUnreachable() return 42 } expectType([Int16].self, &result) expectEqual([], result) expectEqual([], Array(s)) expectLE(s.underestimatedCount, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = map(s) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectEqual([], Array(s)) expectLE(s.underestimatedCount, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Overestimate) let result = map(s) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectEqual([], Array(s)) expectLE(s.underestimatedCount, result.capacity) } } Algorithm.test("map/CollectionType") { // FIXME(prext): remove these tests together with the map() function when // protocol extensions land. These tests have been migrated to the new API. if true { let c = MinimalForwardCollection([]) var result = map(c) { (x: Int) -> Int16 in expectUnreachable() return 42 } expectType([Int16].self, &result) expectEqual([], result) expectLE(c.underestimatedCount, result.capacity) } if true { let c = MinimalForwardCollection( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = map(c) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectLE(c.underestimatedCount, result.capacity) } if true { let c = MinimalForwardCollection( [ 0, 30, 10, 90 ], underestimatedCount: .Overestimate) let result = map(c) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectLE(c.underestimatedCount, result.capacity) } } Algorithm.test("flatMap/SequenceType") { // FIXME(prext): remove these tests together with the flatMap() function when // protocol extensions land. These tests have been migrated to the new API. if true { let s = MinimalSequence([]) var result = flatMap(s) { (x: Int) -> [Int16] in expectUnreachable() return [42] } expectType([Int16].self, &result) expectEqual([], result) expectEqual([], Array(s)) } if true { let s = MinimalSequence([ 0, 30, 10, 90 ]) let result = flatMap(s) { [$0 + 1] } expectEqual([ 1, 31, 11, 91 ], result) expectEqual([], Array(s)) } } Algorithm.test("flatMap/CollectionType") { // FIXME(prext): remove these tests together with the flatMap() function when // protocol extensions land. These tests have been migrated to the new API. if true { let c = MinimalForwardCollection([]) var result = flatMap(c) { (x: Int) -> [Int16] in expectUnreachable() return [42] } expectType([Int16].self, &result) expectEqual([], result) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = flatMap(c) { [$0 + 1] } expectEqual([ 1, 31, 11, 91 ], result) } } Algorithm.test("sorted/strings") .xfail(.LinuxAny(reason: "String comparison: ICU vs. Foundation")) .code { expectEqual( [ "Banana", "apple", "cherry" ], sorted([ "apple", "Banana", "cherry" ])) let s = sorted(["apple", "Banana", "cherry"]) { count($0) > count($1) } expectEqual([ "Banana", "cherry", "apple" ], s) } // A wrapper around Array that disables any type-specific algorithm // optimizations and forces bounds checking on. struct A : MutableSliceable { init(_ a: Array) { impl = a } var startIndex: Int { return 0 } var endIndex: Int { return impl.count } func generate() -> Array.Generator { return impl.generate() } subscript(i: Int) -> T { get { expectTrue(i >= 0 && i < impl.count) return impl[i] } set (x) { expectTrue(i >= 0 && i < impl.count) impl[i] = x } } subscript(r: Range) -> Array.SubSlice { get { expectTrue(r.startIndex >= 0 && r.startIndex <= impl.count) expectTrue(r.endIndex >= 0 && r.endIndex <= impl.count) return impl[r] } set (x) { expectTrue(r.startIndex >= 0 && r.startIndex <= impl.count) expectTrue(r.endIndex >= 0 && r.endIndex <= impl.count) impl[r] = x } } var impl: Array } func withInvalidOrderings(body: ((Int,Int)->Bool)->Void) { // Test some ordering predicates that don't create strict weak orderings body { (_,_) in true } body { (_,_) in false } var i = 0 body { (_,_) in i++ % 2 == 0 } body { (_,_) in i++ % 3 == 0 } body { (_,_) in i++ % 5 == 0 } } func randomArray() -> A { let count = Int(rand32(exclusiveUpperBound: 50)) return A(randArray(count)) } Algorithm.test("invalidOrderings") { withInvalidOrderings { var a = randomArray() sort(&a, $0) } withInvalidOrderings { var a: A a = randomArray() partition(&a, indices(a), $0) } /* // FIXME: Disabled due to Unimplemented: // abstraction difference in l-value withInvalidOrderings { var a = randomArray() var pred = $0 _insertionSort(&a, indices(a), &pred) } */ withInvalidOrderings { let predicate: (Int,Int)->Bool = $0 let result = lexicographicalCompare(randomArray(), randomArray(), isOrderedBefore: predicate) } } // The routine is based on http://www.cs.dartmouth.edu/~doug/mdmspe.pdf func makeQSortKiller(len: Int) -> [Int] { var candidate: Int = 0 var keys = [Int:Int]() func Compare(x: Int, y : Int) -> Bool { if keys[x] == nil && keys[y] == nil { if (x == candidate) { keys[x] = keys.count } else { keys[y] = keys.count } } if keys[x] == nil { candidate = x return true } if keys[y] == nil { candidate = y return false } return keys[x]! > keys[y]! } var ary = [Int](count: len, repeatedValue:0) var ret = [Int](count: len, repeatedValue:0) for i in 0.. { public var value: Underlying public var identity: Int public init(_ value: Underlying) { self.value = value self.identity = 0 } public init(_ value: Underlying, identity: Int) { self.value = value self.identity = identity } } /// A type that conforms only to `Equatable`. /// /// This type can be used to check that generic functions don't rely on any /// other conformances. public struct MinimalEquatableValue : Equatable { public static var timesEqualEqualWasCalled: Int = 0 public var value: Int public var identity: Int public init(_ value: Int) { self.value = value self.identity = 0 } public init(_ value: Int, identity: Int) { self.value = value self.identity = identity } } public func == ( lhs: MinimalEquatableValue, rhs: MinimalEquatableValue ) -> Bool { ++MinimalEquatableValue.timesEqualEqualWasCalled return lhs.value == rhs.value } /// A type that conforms only to `Equatable` and `Hashable`. /// /// This type can be used to check that generic functions don't rely on any /// other conformances. public struct MinimalHashableValue : Equatable, Hashable { public static var timesEqualEqualWasCalled: Int = 0 public static var timesHashValueWasCalled: Int = 0 public var value: Int public var identity: Int public init(_ value: Int) { self.value = value self.identity = 0 } public init(_ value: Int, identity: Int) { self.value = value self.identity = identity } public var hashValue: Int { ++MinimalHashableValue.timesHashValueWasCalled return value.hashValue } } public func == ( lhs: MinimalHashableValue, rhs: MinimalHashableValue ) -> Bool { ++MinimalHashableValue.timesEqualEqualWasCalled return lhs.value == rhs.value } /// A type that conforms only to `Equatable` and `Comparable`. /// /// This type can be used to check that generic functions don't rely on any /// other conformances. public struct MinimalComparableValue : Equatable, Comparable { public static var timesEqualEqualWasCalled: Int = 0 public static var timesLessWasCalled: Int = 0 public var value: Int public var identity: Int public init(_ value: Int) { self.value = value self.identity = 0 } public init(_ value: Int, identity: Int) { self.value = value self.identity = identity } } public func == ( lhs: MinimalComparableValue, rhs: MinimalComparableValue ) -> Bool { ++MinimalComparableValue.timesEqualEqualWasCalled return lhs.value == rhs.value } public func < ( lhs: MinimalComparableValue, rhs: MinimalComparableValue ) -> Bool { ++MinimalComparableValue.timesLessWasCalled return lhs.value < rhs.value } var SequenceTypeAlgorithms = TestSuite("SequenceTypeAlgorithms") // 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].startsWith([1.0, 2.0]) should be false. //===----------------------------------------------------------------------===// // enumerate() //===----------------------------------------------------------------------===// struct EnumerateTest { let expected: [(Int, Int)] let sequence: [Int] let loc: SourceLoc init( _ expected: [(Int, Int)], _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expected = expected self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data" + comment) } } let enumerateTests = [ EnumerateTest([], []), EnumerateTest([ (0, 10) ], [ 10 ]), EnumerateTest([ (0, 10), (1, 20) ], [ 10, 20 ]), EnumerateTest([ (0, 10), (1, 20), (2, 30) ], [ 10, 20, 30 ]), ] SequenceTypeAlgorithms.test("enumerate") { typealias Element = (index: Int, element: OpaqueValue) 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>( test.sequence._prext_map { OpaqueValue($0) }) var result = s._prext_enumerate() expectType( EnumerateSequence>>.self, &result) checkSequence( test.expected._prext_map { (index: $0.0, element: OpaqueValue($0.1)) } as [Element], result, compareElements, resiliencyChecks: .none, test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } //===----------------------------------------------------------------------===// // minElement(), maxElement() //===----------------------------------------------------------------------===// struct MinMaxElementTest { let expectedMinValue: Int? let expectedMinIndex: Int? let expectedMaxValue: Int? let expectedMaxIndex: Int? let sequence: [Int] let loc: SourceLoc init( minValue expectedMinValue: Int?, index expectedMinIndex: Int?, maxValue expectedMaxValue: Int?, index expectedMaxIndex: Int?, _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expectedMinValue = expectedMinValue self.expectedMinIndex = expectedMinIndex self.expectedMaxValue = expectedMaxValue self.expectedMaxIndex = expectedMaxIndex self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data" + comment) } } let minMaxElementTests = [ MinMaxElementTest( minValue: nil, index: nil, maxValue: nil, index: nil, []), MinMaxElementTest( minValue: 42, index: 0, maxValue: 42, index: 0, [ 42 ]), MinMaxElementTest( minValue: -1, index: 1, maxValue: 30, index: 2, [ 10, -1, 30, -1, 30 ]), MinMaxElementTest( minValue: -2, index: 5, maxValue: 31, index: 6, [ 10, -1, 30, -1, 30, -2, 31 ]), ] % for algorithmKind in [ 'min', 'max' ]: % AlgorithmKind = algorithmKind.capitalize() SequenceTypeAlgorithms.test("${algorithmKind}Element/WhereElementIsComparable") { for test in minMaxElementTests { let s = MinimalSequence( test.sequence._prext_enumerate()._prext_map { MinimalComparableValue($1, identity: $0) }) var maybeResult = s._prext_${algorithmKind}Element() expectType(Optional.self, &maybeResult) if let result? = maybeResult { expectEqual( test.expected${AlgorithmKind}Value!, result.value, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expected${AlgorithmKind}Index!, result.identity, stackTrace: test.loc.withCurrentLoc()) } else { expectEmpty( test.expected${AlgorithmKind}Value, stackTrace: test.loc.withCurrentLoc()) expectEmpty( test.expected${AlgorithmKind}Index, stackTrace: test.loc.withCurrentLoc()) } expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } SequenceTypeAlgorithms.test("${algorithmKind}Element/Predicate") { for test in minMaxElementTests { let s = MinimalSequence>( test.sequence._prext_enumerate()._prext_map { OpaqueValue($1, identity: $0) }) var timesClosureWasCalled = 0 var maybeResult = s._prext_${algorithmKind}Element { (lhs, rhs) -> Bool in ++timesClosureWasCalled return lhs.value < rhs.value } expectType(Optional>.self, &maybeResult) if let result? = maybeResult { expectEqual( test.expected${AlgorithmKind}Value!, result.value, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expected${AlgorithmKind}Index!, result.identity, stackTrace: test.loc.withCurrentLoc()) } else { expectEmpty( test.expected${AlgorithmKind}Value, stackTrace: test.loc.withCurrentLoc()) expectEmpty( test.expected${AlgorithmKind}Index, stackTrace: test.loc.withCurrentLoc()) } expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(max(0, test.sequence.count - 1), timesClosureWasCalled) { "maxElement() should be eager and should only call its predicate once per element" } } } % end //===----------------------------------------------------------------------===// // startsWith() //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("startsWith/WhereElementIsEquatable") { for test in startsWithTests { if true { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) let prefix = MinimalSequence( test.prefix.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s._prext_startsWith(prefix), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and prefix. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) let prefix = MinimalSequence( test.prefix.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s._prext_startsWith(prefix), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("startsWith/Predicate") { for test in startsWithTests { if true { let s = MinimalSequence>( map(test.sequence) { OpaqueValue($0) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s._prext_startsWith(prefix) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } if true { let s = MinimalSequence>( map(test.sequence) { OpaqueValue($0 * 2) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s._prext_startsWith(prefix) { $0.value / 2 == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value / 2 }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and prefix. if true { let s = MinimalForwardCollection>( map(test.sequence) { OpaqueValue($0) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s._prext_startsWith(prefix) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // equal() //===----------------------------------------------------------------------===// struct EqualElementsTest { let expected: Bool let sequence: [Int] let other: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int] let loc: SourceLoc init( _ expected: Bool, _ sequence: [Int], _ other: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data" + comment) } func flip() -> EqualElementsTest { return EqualElementsTest( expected, other, sequence, expectedLeftoverOther, expectedLeftoverSequence, file: loc.file, line: loc.line, comment: " (flipped)") } } let equalElementsTests = [ EqualElementsTest(true, [], [], [], []), EqualElementsTest(false, [ 1 ], [], [], []), EqualElementsTest(false, [], [ 1 ], [], []), EqualElementsTest(false, [ 1, 2 ], [], [ 2 ], []), EqualElementsTest(false, [], [ 1, 2 ], [], [ 2 ]), EqualElementsTest(false, [ 1, 2, 3, 4 ], [ 1, 2 ], [ 4 ], []), EqualElementsTest(false, [ 1, 2 ], [ 1, 2, 3, 4 ], [], [ 4 ]), ].flatMap { [ $0, $0.flip() ] } SequenceTypeAlgorithms.test("equalElements/WhereElementIsEquatable") { for test in equalElementsTests { if true { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) let other = MinimalSequence( test.other.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s._prext_equalElements(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) let other = MinimalSequence( test.other.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s._prext_equalElements(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("equalElements/Predicate") { for test in equalElementsTests { if true { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected, s._prext_equalElements(other) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected, s._prext_equalElements(other) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // lexicographicalCompare() //===----------------------------------------------------------------------===// struct LexicographicalCompareTest { let expected: ExpectedComparisonResult let sequence: [Int] let other: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int] let loc: SourceLoc init( _ expected: ExpectedComparisonResult, _ sequence: [Int], _ other: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data" + comment) } func flip() -> LexicographicalCompareTest { return LexicographicalCompareTest( expected.flip(), other, sequence, expectedLeftoverOther, expectedLeftoverSequence, file: loc.file, line: loc.line, comment: " (flipped)") } } let lexicographicalCompareTests = [ LexicographicalCompareTest(.EQ, [], [], [], []), LexicographicalCompareTest(.EQ, [ 1 ], [ 1 ], [], []), LexicographicalCompareTest(.GT, [ 1 ], [], [], []), LexicographicalCompareTest(.GT, [ 1 ], [ 0 ], [], []), LexicographicalCompareTest(.EQ, [ 1 ], [ 1 ], [], []), LexicographicalCompareTest(.LT, [ 1 ], [ 2 ], [], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0 ], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2 ], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 0 ], [ 2 ], [ 0 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1, 0 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 0 ], [ 2 ], [ 0 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 1 ], [ 2 ], [ 1 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1, 1 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 1 ], [ 2 ], [ 1 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 2 ], [ 2 ], [ 2 ]), LexicographicalCompareTest(.EQ, [ 1, 2 ], [ 1, 2 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 2 ], [ 2 ], [ 2 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 3 ], [ 2 ], [ 3 ]), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 1, 3 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 3 ], [ 2 ], [ 3 ]), ].flatMap { [ $0, $0.flip() ] } SequenceTypeAlgorithms.test("lexicographicalCompare/WhereElementIsComparable") { for test in lexicographicalCompareTests { if true { let s = MinimalSequence( test.sequence.map { MinimalComparableValue($0) }) let other = MinimalSequence( test.other.map { MinimalComparableValue($0) }) expectEqual( test.expected.isLT(), s._prext_lexicographicalCompare(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalComparableValue($0) }) let other = MinimalSequence( test.other.map { MinimalComparableValue($0) }) expectEqual( test.expected.isLT(), s._prext_lexicographicalCompare(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("lexicographicalCompare/Predicate") { for test in lexicographicalCompareTests { if true { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected.isLT(), s._prext_lexicographicalCompare(other) { $0.value < $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected.isLT(), s._prext_lexicographicalCompare(other) { $0.value < $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // contains() //===----------------------------------------------------------------------===// // These tests are shared between find() and contains(). struct FindTest { let expected: Int? let element: Int let sequence: [Int] let expectedLeftoverSequence: [Int] let loc: SourceLoc init( _ expected: Int?, _ element: Int, _ sequence: [Int], _ expectedLeftoverSequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.element = element self.sequence = sequence self.expectedLeftoverSequence = expectedLeftoverSequence self.loc = SourceLoc(file, line, comment: "test data") } } let findTests = [ FindTest(nil, 42, [], []), FindTest(nil, 42, [ 1 ], []), FindTest(0, 1, [ 1 ], []), FindTest(nil, 42, [ 1, 2, 3, 4 ], []), FindTest(0, 1, [ 1, 2, 3, 4 ], [ 2, 3, 4 ]), FindTest(1, 2, [ 1, 2, 3, 4 ], [ 3, 4 ]), FindTest(2, 3, [ 1, 2, 3, 4 ], [ 4 ]), FindTest(3, 4, [ 1, 2, 3, 4 ], []), ] func callStaticContains( sequence: MinimalSequence, element: MinimalEquatableValue) -> Bool { return sequence._prext_contains(element) } func callGenericContains< S : SequenceType where S.Generator.Element : Equatable >(sequence: S, element: S.Generator.Element) -> Bool { return sequence._prext_contains(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("contains/WhereElementIsEquatable/${dispatch}") { for test in findTests { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) expectEqual( test.expected != nil, call${dispatch}Contains(s, MinimalEquatableValue(test.element)), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } % end SequenceTypeAlgorithms.test("contains/Predicate") { for test in findTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) expectEqual( test.expected != nil, s._prext_contains { $0.value == test.element }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===// struct ReduceTest { let sequence: [Int] let loc: SourceLoc init( _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data") } } let reduceTests = [ ReduceTest([]), ReduceTest([ 1 ]), ReduceTest([ 1, 2 ]), ReduceTest([ 1, 2, 3 ]), ReduceTest([ 1, 2, 3, 4, 5, 6, 7 ]), ] SequenceTypeAlgorithms.test("reduce") { for test in reduceTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) var timesClosureWasCalled = 0 let result = s._prext_reduce(OpaqueValue<[Int]>([])) { (partialResult: OpaqueValue<[Int]>, element: OpaqueValue) -> OpaqueValue<[Int]> in ++timesClosureWasCalled return OpaqueValue<[Int]>(partialResult.value + [ element.value ]) } expectEqual(test.sequence, result.value) expectEqual([], s._prext_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" } } } //===----------------------------------------------------------------------===// // reverse() //===----------------------------------------------------------------------===// struct ReverseTest { let expected: [Int] let sequence: [Int] let loc: SourceLoc init( _ expected: [Int], _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data") } } let reverseTests = [ ReverseTest([], []), ReverseTest([ 1 ], [ 1 ]), ReverseTest([ 2, 1 ], [ 1, 2 ]), ReverseTest([ 3, 2, 1 ], [ 1, 2, 3 ]), ReverseTest([ 4, 3, 2, 1 ], [ 1, 2, 3, 4]), ReverseTest( [ 7, 6, 5, 4, 3, 2, 1 ], [ 1, 2, 3, 4, 5, 6, 7 ]), ] SequenceTypeAlgorithms.test("reverse/SequenceType") { for test in reverseTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) var result = s._prext_reverse() expectType([OpaqueValue].self, &result) expectEqual( test.expected, result.map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } SequenceTypeAlgorithms.test("reverse/WhereIndexIsBidirectional,BidirectionalReverseView") { for test in reverseTests { let s = MinimalBidirectionalCollection>( test.sequence.map { OpaqueValue($0) }) var result = s._prext_reverse() expectType( BidirectionalReverseView>>.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) // Check BidirectionalReverseView CollectionType conformance. checkBidirectionalCollection( test.expected.map { OpaqueValue($0) }, result, { $0.value == $1.value }, test.loc.withCurrentLoc()) } } SequenceTypeAlgorithms.test("reverse/WhereIndexIsRandomAccess,RandomAccessReverseView") { for test in reverseTests { let s = MinimalRandomAccessCollection>( test.sequence.map { OpaqueValue($0) }) var result = s._prext_reverse() expectType( RandomAccessReverseView>>.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) // Check RandomAccessReverseView CollectionType conformance. checkRandomAccessCollection( test.expected.map { OpaqueValue($0) }, result, { $0.value == $1.value }, test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // filter() //===----------------------------------------------------------------------===// struct FilterTest { let expected: [Int] let sequence: [Int] let includeElement: (Int) -> Bool let loc: SourceLoc init( _ expected: [Int], _ sequence: [Int], _ includeElement: (Int) -> Bool, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.includeElement = includeElement self.loc = SourceLoc(file, line, comment: "test data") } } let filterTests = [ FilterTest( [], [], { (x: Int) -> Bool in expectUnreachable(); return true }), FilterTest([], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in false }), FilterTest( [ 0, 30, 10, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in true } ), FilterTest( [ 0, 30, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in x % 3 == 0 } ), ] SequenceTypeAlgorithms.test("filter/SequenceType") { for test in filterTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_filter { (element) in ++timesClosureWasCalled return test.includeElement(element.value) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, map(result) { $0.value }) expectEqual([], s._prext_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)" } } } } SequenceTypeAlgorithms.test("filter/RangeReplaceableCollectionType") { for test in filterTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalForwardRangeReplaceableCollectionType>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_filter { (element) in ++timesClosureWasCalled return test.includeElement(element.value) } expectType( MinimalForwardRangeReplaceableCollectionType>.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual(test.sequence, s._prext_map { $0.value }) { "collection should not be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "filter() should be eager and should only call its predicate once per element" } expectGE(2 * count(result), result.reservedCapacity) { "filter() should not reserve capacity (it does not know how much the predicate will filter out)" } } } } //===----------------------------------------------------------------------===// // map() //===----------------------------------------------------------------------===// struct MapTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> Int32 let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> Int32, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } let mapTests = [ MapTest( [], [], { (x: Int) -> Int32 in expectUnreachable(); return 0xffff }), MapTest([ 101 ], [ 1 ], { (x: Int) -> Int32 in x + 100 }), MapTest([ 101, 102 ], [ 1, 2 ], { (x: Int) -> Int32 in x + 100 }), MapTest([ 101, 102, 103 ], [ 1, 2, 3 ], { (x: Int) -> Int32 in x + 100 }), ] SequenceTypeAlgorithms.test("map/SequenceType") { for test in mapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_map { (element: OpaqueValue) -> OpaqueValue in ++timesClosureWasCalled return OpaqueValue(Int32(test.transform(element.value))) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, result._prext_map { $0.value }) expectEqual([], s._prext_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" } expectLE(s.underestimatedCount, result.capacity) { "map() should reserve capacity" } } } } SequenceTypeAlgorithms.test("map/CollectionType") { for test in mapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalForwardCollection>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_map { (element: OpaqueValue) -> OpaqueValue in ++timesClosureWasCalled return OpaqueValue(Int32(test.transform(element.value))) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, result._prext_map { $0.value }) expectEqual(test.sequence, s._prext_map { $0.value }) { "collection should not be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "map() should be eager and should only call its predicate once per element" } expectLE(s.underestimatedCount, result.capacity) { "map() should reserve capacity" } } } } //===----------------------------------------------------------------------===// // flatMap() //===----------------------------------------------------------------------===// struct FlatMapTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> [Int32] let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> [Int32], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } func flatMapTransformation(x: Int) -> [Int32] { let repetitions = x / 10 let identity = x % 10 return (1..<(repetitions+1)).map { $0 * 10 + identity } } let flatMapTests = [ FlatMapTest( [], [], { (x: Int) -> [Int32] in expectUnreachable(); return [ 0xffff ] }), FlatMapTest([], [ 1 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([], [ 1, 2 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([ 101 ], [ 1 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest([ 101, 102 ], [ 1, 2 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest( [ 101, 102, 103 ], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest( [ 101, 201 ], [ 1 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest( [ 101, 201, 102, 202 ], [ 1, 2 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest( [ 101, 201, 102, 202, 103, 203 ], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest([ 11, 15 ], [ 11, 2, 3, 4, 15 ], flatMapTransformation), FlatMapTest([ 12, 13, 23 ], [ 1, 12, 23 ], flatMapTransformation), FlatMapTest( [ 11, 21, 13, 23, 33, 14 ], [ 21, 2, 33, 14 ], flatMapTransformation), ] SequenceTypeAlgorithms.test("flatMap/SequenceType") { for test in flatMapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_flatMap { (element: OpaqueValue) -> MinimalSequence> in ++timesClosureWasCalled return MinimalSequence>( test.transform(element.value).map { OpaqueValue(Int32($0)) }) } expectType([OpaqueValue].self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_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" } expectGE(2 * count(result), result.capacity) { "flatMap() should not reserve capacity" } } } } struct FlatMapToOptionalTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> Int32? let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> Int32?, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } let flatMapToOptionalTests = [ FlatMapToOptionalTest( [], [], { (x: Int) -> Int32? in expectUnreachable(); return 0xffff }), FlatMapToOptionalTest([], [ 1 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest([], [ 1, 2 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest([], [ 1, 2, 3 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest( [ 1 ], [ 1 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 2 ], [ 11, 2, 13, 14 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 1, 4 ], [ 1, 12, 13, 4 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 1, 2, 3 ], [ 1, 2, 3 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), ] SequenceTypeAlgorithms.test("flatMap/SequenceType/TransformProducesOptional") { for test in flatMapToOptionalTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Overestimate, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) var timesClosureWasCalled = 0 var result = s._prext_flatMap { (element: OpaqueValue) -> OpaqueValue? in ++timesClosureWasCalled return test.transform(element.value).map { OpaqueValue(Int32($0)) } } expectType([OpaqueValue].self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "flatMap() should be eager and should only call its predicate once per element" } expectGE(2 * count(result), result.capacity) { "flatMap() should not reserve capacity" } } } } //===----------------------------------------------------------------------===// // zip() //===----------------------------------------------------------------------===// struct ZipTest { let expected: [(Int, Int32)] let sequence: [Int] let other: [Int32] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int32] let loc: SourceLoc init( _ expected: [(Int, Int32)], sequences sequence: [Int], _ other: [Int32], leftovers expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int32], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data") } } let zipTests = [ ZipTest([], sequences: [], [], leftovers: [], []), ZipTest([], sequences: [], [ 1 ], leftovers: [], [ 1 ]), ZipTest([], sequences: [], [ 1, 2 ], leftovers: [], [ 1, 2 ]), ZipTest([], sequences: [], [ 1, 2, 3 ], leftovers: [], [ 1, 2, 3 ]), ZipTest([], sequences: [ 10 ], [], leftovers: [], []), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1 ], leftovers: [], []), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1, 2 ], leftovers: [], [ 2 ]), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1, 2, 3 ], leftovers: [], [ 2, 3 ]), ZipTest( [], sequences: [ 10, 20 ], [], leftovers: [ 20 ], []), ZipTest( [ (10, 1) ], sequences: [ 10, 20 ], [ 1 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20 ], [ 1, 2 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20 ], [ 1, 2, 3 ], leftovers: [], [ 3 ]), ZipTest( [], sequences: [ 10, 20, 30 ], [], leftovers: [ 20, 30 ], []), ZipTest( [ (10, 1) ], sequences: [ 10, 20, 30 ], [ 1 ], leftovers: [ 30 ], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20, 30 ], [ 1, 2 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2), (30, 3) ], sequences: [ 10, 20, 30 ], [ 1, 2, 3 ], leftovers: [], []), ] SequenceTypeAlgorithms.test("zip") { typealias Element = (OpaqueValue, OpaqueValue) 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>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) var result = s._prext_zip(other) expectType( Zip2>, MinimalSequence>>.self, &result) // Check for expected result and check the Zip2 SequenceType conformance. checkSequence( test.expected._prext_map { (OpaqueValue($0), OpaqueValue($1)) }, result, compareElements, test.loc.withCurrentLoc()) // 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._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // isEmpty //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("isEmpty") { if true { let s = MinimalForwardCollection>([]) expectTrue(s._prext_isEmpty) } if true { let s = MinimalForwardCollection>( [ 1 ]._prext_map { OpaqueValue($0) }) expectFalse(s._prext_isEmpty) } } //===----------------------------------------------------------------------===// // first //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("first") { if true { let s = MinimalForwardCollection>([]) expectEmpty(s._prext_first) } if true { let s = MinimalForwardCollection>([ OpaqueValue(1, identity: 10), OpaqueValue(2, identity: 20) ]) if let result? = s._prext_first { expectEqual(1, result.value) expectEqual(10, result.identity) } else { expectUnreachable() } } } //===----------------------------------------------------------------------===// // find() //===----------------------------------------------------------------------===// func callStaticFind( collection: MinimalForwardCollection, element: MinimalEquatableValue ) -> MinimalForwardCollection.Index? { return collection._prext_find(element) } func callGenericFind< C : CollectionType where C.Generator.Element : Equatable >(collection: C, element: C.Generator.Element) -> C.Index? { return collection._prext_find(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("find/WhereElementIsEquatable/${dispatch}") { for test in findTests { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) expectEqual( test.expected, call${dispatch}Find(s, MinimalEquatableValue(test.element)) .map { $0.position }, stackTrace: test.loc.withCurrentLoc()) } } % end SequenceTypeAlgorithms.test("find/Predicate") { for test in findTests { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s._prext_find { $0.value == test.element } .map { $0.position }, stackTrace: test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // indices() //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("indices") { if true { let s = MinimalForwardCollection>([]) let indices = s._prext_indices expectEqual(s.startIndex, indices.startIndex) expectEqual(s.endIndex, indices.endIndex) } if true { let s = MinimalForwardCollection>([ OpaqueValue(1, identity: 10), OpaqueValue(2, identity: 20) ]) let indices = s._prext_indices expectEqual(s.startIndex, indices.startIndex) expectEqual(s.endIndex, indices.endIndex) } } runAllTests()