Skip to content

Commit f44d02e

Browse files
authored
Improve adjacent pairs unit tests (#179)
* adjacentPairs: improve unit tests * adjacentPairs: conform indentation to project standards
1 parent 57072e6 commit f44d02e

File tree

2 files changed

+129
-92
lines changed

2 files changed

+129
-92
lines changed

Sources/AsyncAlgorithms/AsyncAdjacentPairsSequence.swift

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,74 +13,74 @@
1313
/// `AsyncSequence`.
1414
@frozen
1515
public struct AsyncAdjacentPairsSequence<Base: AsyncSequence>: AsyncSequence {
16-
public typealias Element = (Base.Element, Base.Element)
16+
public typealias Element = (Base.Element, Base.Element)
1717

18-
@usableFromInline
19-
let base: Base
18+
@usableFromInline
19+
let base: Base
2020

21-
@inlinable
22-
init(_ base: Base) {
23-
self.base = base
24-
}
21+
@inlinable
22+
init(_ base: Base) {
23+
self.base = base
24+
}
2525

26-
/// The iterator for an `AsyncAdjacentPairsSequence` instance.
27-
@frozen
28-
public struct Iterator: AsyncIteratorProtocol {
29-
public typealias Element = (Base.Element, Base.Element)
26+
/// The iterator for an `AsyncAdjacentPairsSequence` instance.
27+
@frozen
28+
public struct Iterator: AsyncIteratorProtocol {
29+
public typealias Element = (Base.Element, Base.Element)
3030

31-
@usableFromInline
32-
var base: Base.AsyncIterator
31+
@usableFromInline
32+
var base: Base.AsyncIterator
3333

34-
@usableFromInline
35-
internal var previousElement: Base.Element?
34+
@usableFromInline
35+
internal var previousElement: Base.Element?
3636

37-
@inlinable
38-
init(_ base: Base.AsyncIterator) {
39-
self.base = base
40-
}
37+
@inlinable
38+
init(_ base: Base.AsyncIterator) {
39+
self.base = base
40+
}
4141

42-
@inlinable
43-
public mutating func next() async rethrows -> (Base.Element, Base.Element)? {
44-
if previousElement == nil {
45-
previousElement = try await base.next()
46-
}
42+
@inlinable
43+
public mutating func next() async rethrows -> (Base.Element, Base.Element)? {
44+
if previousElement == nil {
45+
previousElement = try await base.next()
46+
}
4747

48-
guard let previous = previousElement, let next = try await base.next() else {
49-
return nil
50-
}
48+
guard let previous = previousElement, let next = try await base.next() else {
49+
return nil
50+
}
5151

52-
previousElement = next
53-
return (previous, next)
54-
}
52+
previousElement = next
53+
return (previous, next)
5554
}
55+
}
5656

57-
@inlinable
58-
public func makeAsyncIterator() -> Iterator {
59-
Iterator(base.makeAsyncIterator())
60-
}
57+
@inlinable
58+
public func makeAsyncIterator() -> Iterator {
59+
Iterator(base.makeAsyncIterator())
60+
}
6161
}
6262

6363
extension AsyncSequence {
64-
/// An `AsyncSequence` that iterates over the adjacent pairs of the original
65-
/// original `AsyncSequence`.
66-
///
67-
/// ```
68-
/// for await (first, second) in (1...5).async.adjacentPairs() {
69-
/// print("First: \(first), Second: \(second)")
70-
/// }
71-
///
72-
/// // First: 1, Second: 2
73-
/// // First: 2, Second: 3
74-
/// // First: 3, Second: 4
75-
/// // First: 4, Second: 5
76-
/// ```
77-
///
78-
/// - Returns: An `AsyncSequence` where the element is a tuple of two adjacent elements
79-
/// or the original `AsyncSequence`.
80-
@inlinable
81-
public func adjacentPairs() -> AsyncAdjacentPairsSequence<Self> {
82-
AsyncAdjacentPairsSequence(self)
83-
}
64+
/// An `AsyncSequence` that iterates over the adjacent pairs of the original
65+
/// original `AsyncSequence`.
66+
///
67+
/// ```
68+
/// for await (first, second) in (1...5).async.adjacentPairs() {
69+
/// print("First: \(first), Second: \(second)")
70+
/// }
71+
///
72+
/// // First: 1, Second: 2
73+
/// // First: 2, Second: 3
74+
/// // First: 3, Second: 4
75+
/// // First: 4, Second: 5
76+
/// ```
77+
///
78+
/// - Returns: An `AsyncSequence` where the element is a tuple of two adjacent elements
79+
/// or the original `AsyncSequence`.
80+
@inlinable
81+
public func adjacentPairs() -> AsyncAdjacentPairsSequence<Self> {
82+
AsyncAdjacentPairsSequence(self)
83+
}
8484
}
8585

8686
extension AsyncAdjacentPairsSequence: Sendable where Base: Sendable, Base.Element: Sendable, Base.AsyncIterator: Sendable { }

Tests/AsyncAlgorithmsTests/TestAdjacentPairs.swift

Lines changed: 75 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,85 @@
1313
import AsyncAlgorithms
1414

1515
final class TestAdjacentPairs: XCTestCase {
16-
func test_adjacentPairs() async {
17-
let source = 1...5
18-
let expected = [(1,2), (2,3), (3,4), (4,5)]
19-
let sequence = source.async.adjacentPairs()
20-
var actual: [(Int, Int)] = []
21-
for await item in sequence {
22-
actual.append(item)
23-
}
24-
XCTAssertEqual(expected, actual)
16+
func test_adjacentPairs_produces_tuples_of_adjacent_values_of_original_element() async {
17+
let source = 1...5
18+
let expected = Array(zip(source, source.dropFirst()))
19+
20+
let sequence = source.async.adjacentPairs()
21+
var actual: [(Int, Int)] = []
22+
for await item in sequence {
23+
actual.append(item)
2524
}
2625

27-
func test_empty() async {
28-
let source = 0..<1
29-
let expected: [(Int, Int)] = []
30-
let sequence = source.async.adjacentPairs()
31-
var actual: [(Int, Int)] = []
32-
for await item in sequence {
33-
actual.append(item)
34-
}
35-
XCTAssertEqual(expected, actual)
26+
XCTAssertEqual(expected, actual)
27+
}
28+
29+
func test_adjacentPairs_forwards_termination_from_source_when_iteration_is_finished() async {
30+
let source = 1...5
31+
32+
var iterator = source.async.adjacentPairs().makeAsyncIterator()
33+
while let _ = await iterator.next() {}
34+
35+
let pastEnd = await iterator.next()
36+
XCTAssertNil(pastEnd)
37+
}
38+
39+
func test_adjacentPairs_produces_empty_sequence_when_source_sequence_is_empty() async {
40+
let source = 0..<1
41+
let expected: [(Int, Int)] = []
42+
43+
let sequence = source.async.adjacentPairs()
44+
var actual: [(Int, Int)] = []
45+
for await item in sequence {
46+
actual.append(item)
3647
}
3748

38-
func test_cancellation() async {
39-
let source = Indefinite(value: 0)
40-
let sequence = source.async.adjacentPairs()
41-
let finished = expectation(description: "finished")
42-
let iterated = expectation(description: "iterated")
43-
let task = Task {
44-
var firstIteration = false
45-
for await _ in sequence {
46-
if !firstIteration {
47-
firstIteration = true
48-
iterated.fulfill()
49-
}
50-
}
51-
finished.fulfill()
49+
XCTAssertEqual(expected, actual)
50+
}
51+
52+
func test_adjacentPairs_throws_when_source_sequence_throws() async throws {
53+
let source = 1...5
54+
let expected = [(1, 2), (2, 3)]
55+
56+
let sequence = source.async.map { try throwOn(4, $0) }.adjacentPairs()
57+
var iterator = sequence.makeAsyncIterator()
58+
var actual = [(Int, Int)]()
59+
do {
60+
while let value = try await iterator.next() {
61+
actual.append(value)
62+
}
63+
XCTFail(".adjacentPairs should throw when the source sequence throws")
64+
} catch {
65+
XCTAssertEqual(error as? Failure, Failure())
66+
}
67+
68+
XCTAssertEqual(actual, expected)
69+
let pastEnd = try await iterator.next()
70+
XCTAssertNil(pastEnd)
71+
}
72+
73+
func test_adjacentPairs_finishes_when_iteration_task_is_cancelled() async {
74+
let source = Indefinite(value: 0)
75+
let sequence = source.async.adjacentPairs()
76+
let finished = expectation(description: "finished")
77+
let iterated = expectation(description: "iterated")
78+
79+
let task = Task {
80+
var firstIteration = false
81+
for await _ in sequence {
82+
if !firstIteration {
83+
firstIteration = true
84+
iterated.fulfill()
5285
}
53-
// ensure the other task actually starts
54-
wait(for: [iterated], timeout: 1.0)
55-
// cancellation should ensure the loop finishes
56-
// without regards to the remaining underlying sequence
57-
task.cancel()
58-
wait(for: [finished], timeout: 1.0)
86+
}
87+
finished.fulfill()
5988
}
89+
90+
// ensure the other task actually starts
91+
wait(for: [iterated], timeout: 1.0)
92+
// cancellation should ensure the loop finishes
93+
// without regards to the remaining underlying sequence
94+
task.cancel()
95+
wait(for: [finished], timeout: 1.0)
96+
}
6097
}

0 commit comments

Comments
 (0)