Skip to content

Commit 0cfb46d

Browse files
committed
Publishes values of subsequent publisher after emptying publisher queue
1 parent ec32fa7 commit 0cfb46d

File tree

2 files changed

+82
-13
lines changed

2 files changed

+82
-13
lines changed

Sources/Operators/ConcatMap.swift

+5-6
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,12 @@ private extension Publishers.ConcatMap {
112112

113113
override func receive(_ input: Upstream.Output) -> Subscribers.Demand {
114114
let mapped = transform(input)
115-
116115
lock.lock()
116+
defer { lock.unlock() }
117+
117118
if activePublisher == nil {
118-
lock.unlock()
119119
setActivePublisher(mapped)
120120
} else {
121-
lock.unlock()
122121
bufferedPublishers.append(mapped)
123122
}
124123

@@ -132,15 +131,15 @@ private extension Publishers.ConcatMap {
132131

133132
publisher.sink(
134133
receiveCompletion: { completion in
134+
self.lock.lock()
135+
defer { self.lock.unlock() }
135136
switch completion {
136137
case .finished:
137-
self.lock.lock()
138138
guard let next = self.bufferedPublishers.first else {
139-
self.lock.unlock()
139+
self.activePublisher = nil
140140
return
141141
}
142142
self.bufferedPublishers.removeFirst()
143-
self.lock.unlock()
144143
self.setActivePublisher(next)
145144
case .failure(let error):
146145
self.receive(completion: .failure(error))

Tests/ConcatMapTests.swift

+77-7
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ final class ConcatMapTests: XCTestCase {
2424
cancellables = []
2525
}
2626

27-
func test_publishes_values_inOrder() {
27+
func test_publishes_values_in_order() {
2828
var receivedValues = [Int]()
29-
let expectedValues = [1, 2, 4, 5, 6]
29+
let expectedValues = [1, 2, 3]
3030

3131
let firstPublisher = P()
3232
let secondPublisher = P()
@@ -43,19 +43,89 @@ final class ConcatMapTests: XCTestCase {
4343

4444
sut.send(firstPublisher)
4545
sut.send(secondPublisher)
46+
47+
firstPublisher.send(1)
48+
firstPublisher.send(completion: .finished)
49+
50+
secondPublisher.send(2)
4651
sut.send(thirdPublisher)
52+
secondPublisher.send(completion: .finished)
53+
54+
thirdPublisher.send(3)
55+
56+
XCTAssertEqual(expectedValues, receivedValues)
57+
}
58+
59+
func test_ignores_values_of_subsequent_while_previous_hasNot_completed() {
60+
var receivedValues = [Int]()
61+
let expectedValues = [1, 3]
62+
63+
let firstPublisher = P()
64+
let secondPublisher = P()
65+
66+
let sut = PassthroughSubject<P, TestError>()
67+
68+
sut.concatMap { $0 }
69+
.sink(
70+
receiveCompletion: { _ in },
71+
receiveValue: { value in receivedValues.append(value) }
72+
)
73+
.store(in: &cancellables)
74+
75+
sut.send(firstPublisher)
76+
sut.send(secondPublisher)
4777

4878
firstPublisher.send(1)
49-
firstPublisher.send(2)
50-
// values sent onto the second publisher will be ignored as long as the first publisher hasn't completed
79+
secondPublisher.send(2)
80+
firstPublisher.send(completion: .finished)
81+
5182
secondPublisher.send(3)
83+
secondPublisher.send(completion: .finished)
84+
85+
XCTAssertEqual(expectedValues, receivedValues)
86+
}
87+
88+
func test_publishes_values_of_subsequent_publisher_after_emptying_publisher_queue() {
89+
var receivedValues = [Int]()
90+
let expectedValues = [1, 2]
91+
92+
let firstPublisher = P()
93+
let secondPublisher = P()
94+
95+
let sut = PassthroughSubject<P, TestError>()
96+
97+
sut.concatMap { $0 }
98+
.sink(
99+
receiveCompletion: { _ in },
100+
receiveValue: { value in receivedValues.append(value) }
101+
)
102+
.store(in: &cancellables)
103+
104+
sut.send(firstPublisher)
105+
firstPublisher.send(1)
52106
firstPublisher.send(completion: .finished)
53107

54-
secondPublisher.send(4)
55-
secondPublisher.send(5)
108+
sut.send(secondPublisher)
109+
secondPublisher.send(2)
56110
secondPublisher.send(completion: .finished)
57111

58-
thirdPublisher.send(6)
112+
XCTAssertEqual(expectedValues, receivedValues)
113+
}
114+
115+
func test_synchronous_completion() {
116+
var receivedValues = [Int]()
117+
let expectedValues = [1, 2]
118+
let firstPublisher = Just<Int>(1)
119+
let secondPublisher = Just<Int>(2)
120+
121+
let sut = PassthroughSubject<Just<Int>, Never>()
122+
123+
sut.concatMap { $0 }
124+
.sink { value in receivedValues.append(value) }
125+
.store(in: &cancellables)
126+
127+
sut.send(firstPublisher)
128+
sut.send(secondPublisher)
59129

60130
XCTAssertEqual(expectedValues, receivedValues)
61131
}

0 commit comments

Comments
 (0)