Skip to content

Commit 22ab0df

Browse files
authored
Fix debounce when started twice (#772)
* Duplicating the Signal tests on debounce for SignalProducers * Adding a debounce test The test now fails so I can make sure my fix works. * Fixing issue with debounce Now all tests pass! * Adding change to changelog
1 parent 81c7849 commit 22ab0df

File tree

3 files changed

+271
-2
lines changed

3 files changed

+271
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# master
22
*Please add new entries at the top.*
33

4+
1. Fixed `SignalProducer.debounce` operator that, when started more than once, would not deliver values on producers started after the first time. (#772, kudos to @gpambrozio)
45
1. `FlattenStrategy.throttle` is introduced. (#713, kudos to @inamiy)
56
1. Updated `README.md` to reflect Swift 5.1 compatibility and point snippets to 6.1.0 (#763, kudos to @Marcocanc)
67
1. Update travis to Xcode 11.1 and Swift 5.1 (#764, kudos @petrpavlik)

Sources/Event.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,9 +870,8 @@ extension Signal.Event {
870870
internal static func debounce(_ interval: TimeInterval, on scheduler: DateScheduler, discardWhenCompleted: Bool) -> Transformation<Value, Error> {
871871
precondition(interval >= 0)
872872

873-
let state: Atomic<ThrottleState<Value>> = Atomic(ThrottleState(previousDate: scheduler.currentDate, pendingValue: nil))
874-
875873
return { action, lifetime in
874+
let state: Atomic<ThrottleState<Value>> = Atomic(ThrottleState(previousDate: scheduler.currentDate, pendingValue: nil))
876875
let d = SerialDisposable()
877876

878877
lifetime.observeEnded {

Tests/ReactiveSwiftTests/SignalProducerSpec.swift

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,275 @@ class SignalProducerSpec: QuickSpec {
11671167
}
11681168
}
11691169

1170+
describe("debounce discarding the latest value when terminated") {
1171+
var scheduler: TestScheduler!
1172+
var observer: Signal<Int, Never>.Observer!
1173+
var producer: SignalProducer<Int, Never>!
1174+
1175+
beforeEach {
1176+
scheduler = TestScheduler()
1177+
1178+
let (baseSignal, baseObserver) = Signal<Int, Never>.pipe()
1179+
observer = baseObserver
1180+
1181+
producer = SignalProducer(baseSignal)
1182+
.debounce(0.1, on: scheduler)
1183+
1184+
expect(producer).notTo(beNil())
1185+
}
1186+
1187+
it("should send values on the given scheduler once the interval has passed since the last value was sent") {
1188+
var values: [Int] = []
1189+
producer.startWithValues { value in
1190+
values.append(value)
1191+
}
1192+
1193+
expect(values) == []
1194+
1195+
observer.send(value: 0)
1196+
expect(values) == []
1197+
1198+
scheduler.advance()
1199+
expect(values) == []
1200+
1201+
observer.send(value: 1)
1202+
observer.send(value: 2)
1203+
expect(values) == []
1204+
1205+
scheduler.advance(by: .milliseconds(1500))
1206+
expect(values) == [ 2 ]
1207+
1208+
scheduler.advance(by: .seconds(3))
1209+
expect(values) == [ 2 ]
1210+
1211+
observer.send(value: 3)
1212+
expect(values) == [ 2 ]
1213+
1214+
scheduler.advance()
1215+
expect(values) == [ 2 ]
1216+
1217+
observer.send(value: 4)
1218+
observer.send(value: 5)
1219+
scheduler.advance()
1220+
expect(values) == [ 2 ]
1221+
1222+
scheduler.run()
1223+
expect(values) == [ 2, 5 ]
1224+
}
1225+
1226+
it("should schedule completion immediately") {
1227+
var values: [Int] = []
1228+
var completed = false
1229+
1230+
producer.on(event: { event in
1231+
switch event {
1232+
case let .value(value):
1233+
values.append(value)
1234+
case .completed:
1235+
completed = true
1236+
default:
1237+
break
1238+
}
1239+
}).start()
1240+
1241+
observer.send(value: 0)
1242+
scheduler.advance()
1243+
expect(values) == []
1244+
1245+
observer.send(value: 1)
1246+
observer.sendCompleted()
1247+
expect(completed) == false
1248+
1249+
scheduler.advance()
1250+
expect(values) == []
1251+
expect(completed) == true
1252+
1253+
scheduler.run()
1254+
expect(values) == []
1255+
expect(completed) == true
1256+
}
1257+
1258+
context("starting the producer twice") {
1259+
it("should deviver the same values") {
1260+
var values1: [Int] = []
1261+
var values2: [Int] = []
1262+
producer.startWithValues { value in
1263+
values1.append(value)
1264+
}
1265+
producer.startWithValues { value in
1266+
values2.append(value)
1267+
}
1268+
1269+
expect(values1) == []
1270+
expect(values2) == []
1271+
1272+
observer.send(value: 1)
1273+
observer.send(value: 2)
1274+
1275+
scheduler.advance(by: .milliseconds(1500))
1276+
expect(values1) == [ 2 ]
1277+
expect(values2) == [ 2 ]
1278+
1279+
observer.send(value: 3)
1280+
scheduler.advance(by: .milliseconds(1500))
1281+
expect(values1) == [ 2, 3 ]
1282+
expect(values2) == [ 2, 3 ]
1283+
1284+
observer.send(value: 4)
1285+
observer.sendCompleted()
1286+
scheduler.run()
1287+
1288+
expect(values1) == [ 2, 3 ]
1289+
expect(values2) == [ 2, 3 ]
1290+
}
1291+
}
1292+
}
1293+
1294+
describe("debounce without discarding the latest value when terminated") {
1295+
var scheduler: TestScheduler!
1296+
var observer: Signal<Int, Never>.Observer!
1297+
var producer: SignalProducer<Int, Never>!
1298+
1299+
beforeEach {
1300+
scheduler = TestScheduler()
1301+
1302+
let (baseSignal, baseObserver) = Signal<Int, Never>.pipe()
1303+
observer = baseObserver
1304+
1305+
producer = SignalProducer(baseSignal)
1306+
.debounce(0.1, on: scheduler, discardWhenCompleted: false)
1307+
1308+
expect(producer).notTo(beNil())
1309+
}
1310+
1311+
it("should send values on the given scheduler once the interval has passed since the last value was sent") {
1312+
var values: [Int] = []
1313+
producer.startWithValues { value in
1314+
values.append(value)
1315+
}
1316+
1317+
expect(values) == []
1318+
1319+
observer.send(value: 0)
1320+
expect(values) == []
1321+
1322+
scheduler.advance()
1323+
expect(values) == []
1324+
1325+
observer.send(value: 1)
1326+
observer.send(value: 2)
1327+
expect(values) == []
1328+
1329+
scheduler.advance(by: .milliseconds(1500))
1330+
expect(values) == [ 2 ]
1331+
1332+
scheduler.advance(by: .seconds(3))
1333+
expect(values) == [ 2 ]
1334+
1335+
observer.send(value: 3)
1336+
expect(values) == [ 2 ]
1337+
1338+
scheduler.advance()
1339+
expect(values) == [ 2 ]
1340+
1341+
observer.send(value: 4)
1342+
observer.send(value: 5)
1343+
scheduler.advance()
1344+
expect(values) == [ 2 ]
1345+
observer.sendCompleted()
1346+
1347+
scheduler.run()
1348+
expect(values) == [ 2, 5 ]
1349+
1350+
}
1351+
1352+
it("should schedule completion after sending the last value") {
1353+
var values: [Int] = []
1354+
var completed = false
1355+
1356+
producer.on(event: { event in
1357+
switch event {
1358+
case let .value(value):
1359+
values.append(value)
1360+
case .completed:
1361+
completed = true
1362+
default:
1363+
break
1364+
}
1365+
}).start()
1366+
1367+
observer.send(value: 0)
1368+
scheduler.advance()
1369+
expect(values) == []
1370+
1371+
observer.send(value: 1)
1372+
scheduler.advance()
1373+
observer.sendCompleted()
1374+
expect(completed) == false
1375+
1376+
scheduler.advance()
1377+
expect(values) == []
1378+
expect(completed) == false
1379+
1380+
scheduler.run()
1381+
expect(values) == [1]
1382+
expect(completed) == true
1383+
}
1384+
1385+
it("should schedule completion immediately if there is no pending value") {
1386+
var completed = false
1387+
1388+
producer.on(event: { event in
1389+
switch event {
1390+
case .completed:
1391+
completed = true
1392+
default:
1393+
break
1394+
}
1395+
}).start()
1396+
1397+
observer.sendCompleted()
1398+
expect(completed) == false
1399+
scheduler.advance()
1400+
expect(completed) == true
1401+
}
1402+
1403+
context("starting the producer twice") {
1404+
it("should deviver the same values") {
1405+
var values1: [Int] = []
1406+
var values2: [Int] = []
1407+
producer.startWithValues { value in
1408+
values1.append(value)
1409+
}
1410+
producer.startWithValues { value in
1411+
values2.append(value)
1412+
}
1413+
1414+
expect(values1) == []
1415+
expect(values2) == []
1416+
1417+
observer.send(value: 1)
1418+
observer.send(value: 2)
1419+
1420+
scheduler.advance(by: .milliseconds(1500))
1421+
expect(values1) == [ 2 ]
1422+
expect(values2) == [ 2 ]
1423+
1424+
observer.send(value: 3)
1425+
scheduler.advance(by: .milliseconds(1500))
1426+
expect(values1) == [ 2, 3 ]
1427+
expect(values2) == [ 2, 3 ]
1428+
1429+
observer.send(value: 4)
1430+
observer.sendCompleted()
1431+
scheduler.run()
1432+
1433+
expect(values1) == [ 2, 3, 4 ]
1434+
expect(values2) == [ 2, 3, 4 ]
1435+
}
1436+
}
1437+
}
1438+
11701439
describe("on") {
11711440
it("should attach event handlers to each started signal") {
11721441
let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()

0 commit comments

Comments
 (0)