platform/sandbox/reactivex/test/transformers/backpressure/throttle_test.dart
2024-11-12 01:00:05 -07:00

160 lines
4.7 KiB
Dart

import 'dart:async';
import 'package:angel3_reactivex/angel3_reactivex.dart';
import 'package:test/test.dart';
import '../../utils.dart';
Stream<int> _stream() =>
Stream.periodic(const Duration(milliseconds: 100), (i) => i + 1).take(10);
void main() {
test('Rx.throttle', () async {
await expectLater(
_stream()
.throttle(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)))
.take(3),
emitsInOrder(<dynamic>[1, 4, 7, emitsDone]));
});
test('Rx.throttle.trailing', () async {
await expectLater(
_stream()
.throttle(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)),
trailing: true,
leading: false)
.take(3),
emitsInOrder(<dynamic>[3, 6, 9, emitsDone]));
});
test('Rx.throttle.dynamic.window', () async {
await expectLater(
_stream()
.throttle((value) => value == 1
? Stream<void>.periodic(const Duration(milliseconds: 10))
: Stream<void>.periodic(const Duration(milliseconds: 250)))
.take(3),
emitsInOrder(<dynamic>[1, 2, 5, emitsDone]));
});
test('Rx.throttle.dynamic.window.trailing', () async {
await expectLater(
_stream()
.throttle(
(value) => value == 1
? Stream<void>.periodic(const Duration(milliseconds: 10))
: Stream<void>.periodic(const Duration(milliseconds: 250)),
trailing: true,
leading: false)
.take(3),
emitsInOrder(<dynamic>[1, 4, 7, emitsDone]));
});
test('Rx.throttle.leading.trailing.1', () async {
// --1--2--3--4--5--6--7--8--9--10--11|
// --1-----3--4-----6--7-----9--10-----11|
// --^--------^--------^---------^-----
final values = <int>[];
final stream = _stream()
.concatWith([Rx.timer(11, const Duration(milliseconds: 100))]).throttle(
(v) {
values.add(v);
return Stream<void>.periodic(const Duration(milliseconds: 250));
},
leading: true,
trailing: true,
);
await expectLater(
stream,
emitsInOrder(<dynamic>[1, 3, 4, 6, 7, 9, 10, 11, emitsDone]),
);
expect(values, [1, 4, 7, 10]);
});
test('Rx.throttle.leading.trailing.2', () async {
// --1--2--3--4--5--6--7--8--9--10--11|
// --1-----3--4-----6--7-----9--10-----11|
// --^--------^--------^---------^-----
final values = <int>[];
final stream = _stream().throttle(
(v) {
values.add(v);
return Stream<void>.periodic(const Duration(milliseconds: 250));
},
leading: true,
trailing: true,
);
await expectLater(
stream,
emitsInOrder(<dynamic>[1, 3, 4, 6, 7, 9, 10, emitsDone]),
);
expect(values, [1, 4, 7, 10]);
});
test('Rx.throttle.reusable', () async {
final transformer = ThrottleStreamTransformer<int>(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)));
await expectLater(_stream().transform(transformer).take(2),
emitsInOrder(<dynamic>[1, 4, emitsDone]));
await expectLater(_stream().transform(transformer).take(2),
emitsInOrder(<dynamic>[1, 4, emitsDone]));
});
test('Rx.throttle.asBroadcastStream', () async {
final future = _stream()
.asBroadcastStream()
.throttle(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)))
.drain<void>();
// listen twice on same stream
await expectLater(future, completes);
await expectLater(future, completes);
});
test('Rx.throttle.error.shouldThrowA', () async {
final streamWithError = Stream<void>.error(Exception()).throttle(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)));
streamWithError.listen(null,
onError: expectAsync2((Exception e, StackTrace s) {
expect(e, isException);
}));
});
test('Rx.throttle.pause.resume', () async {
late StreamSubscription<int> subscription;
final controller = StreamController<int>();
subscription = _stream()
.throttle(
(_) => Stream<void>.periodic(const Duration(milliseconds: 250)))
.take(2)
.listen(controller.add, onDone: () {
controller.close();
subscription.cancel();
});
await expectLater(
controller.stream, emitsInOrder(<dynamic>[1, 4, emitsDone]));
await Future<void>.delayed(const Duration(milliseconds: 150)).whenComplete(
() => subscription
.pause(Future<void>.delayed(const Duration(milliseconds: 150))));
});
test('Rx.throttle.nullable', () {
nullableTest<String?>(
(s) => s.throttle((_) => Stream<void>.empty()),
);
});
}