| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| // Test empty stream. | |
| import "package:expect/expect.dart"; | |
| import "dart:async"; | |
| import 'package:expect/async_helper.dart'; | |
| main() async { | |
| await asyncTest(() async { | |
| // Is a `const` constructor. | |
| // Can be called with optional boolean to say whether broadcast or not. | |
| await asyncTest(() => emptyTest(const Stream<int>.empty(), true)); | |
| await asyncTest( | |
| () => emptyTest(const Stream<int>.empty(broadcast: true), true), | |
| ); | |
| await asyncTest( | |
| () => emptyTest(const Stream<int>.empty(broadcast: false), false), | |
| ); | |
| // Check that the behavior is consistent with other empty multi-subscription | |
| // streams. | |
| await asyncTest(() => emptyTest(Stream<int>.fromIterable(<int>[]), false)); | |
| await asyncTest( | |
| () => | |
| emptyTest((StreamController<int>.broadcast()..close()).stream, true), | |
| ); | |
| await asyncTest( | |
| () => emptyTest(Stream<int>.multi((c) => c.close()), false), | |
| ); | |
| }); | |
| await flushMicrotasks(); | |
| } | |
| // Function which fails the test if it gets called. | |
| void unreachable([a, b]) { | |
| Expect.fail("Unreachable"); | |
| } | |
| /// Check that something happens once. | |
| class Checker { | |
| bool checked = false; | |
| void check() { | |
| if (checked) Expect.fail("Checked more than once"); | |
| checked = true; | |
| } | |
| } | |
| Future<void> emptyTest(Stream<int> s, bool broadcast) async { | |
| var checker = Checker(); | |
| // Respects type parameter (not a `Stream<Never>`) | |
| Expect.notType<Stream<String>>(s); | |
| // Has the expected `isBroadcast`. | |
| Expect.equals(broadcast, s.isBroadcast); | |
| StreamSubscription<int> sub = s.listen( | |
| unreachable, | |
| onError: unreachable, | |
| onDone: checker.check, | |
| ); | |
| // Type parameter of subscription respects stream. | |
| // Not a `StreamSubscription<Never>`. | |
| Expect.isFalse(sub is StreamSubscription<String>); | |
| Expect.isFalse(sub.isPaused); | |
| // Doesn't do callback immediately in response to listen. | |
| Expect.isFalse(checker.checked); | |
| await flushMicrotasks(); | |
| // Completes eventually, after a microtask. | |
| Expect.isTrue(checker.checked); | |
| Expect.isFalse(sub.isPaused); | |
| // Can listen more than once, whether broadcast stream or not. | |
| checker = Checker(); | |
| StreamSubscription<int> sub2 = s.listen( | |
| unreachable, | |
| onError: unreachable, | |
| onDone: checker.check, | |
| ); | |
| // Respects pauses. | |
| sub2.pause(); | |
| Expect.isTrue(sub2.isPaused); | |
| sub2.pause(); | |
| Expect.isTrue(sub2.isPaused); | |
| sub2.pause(Future<int>.value(0)); | |
| Expect.isTrue(sub2.isPaused); | |
| await flushMicrotasks(); | |
| Expect.isTrue(sub2.isPaused); | |
| Expect.isFalse(checker.checked); | |
| // Resumes when all pauses resumed. | |
| sub2.resume(); | |
| Expect.isTrue(sub2.isPaused); | |
| await flushMicrotasks(); | |
| Expect.isFalse(checker.checked); | |
| Expect.isTrue(sub2.isPaused); | |
| sub2.resume(); | |
| Expect.isFalse(sub2.isPaused); | |
| await flushMicrotasks(); | |
| Expect.isTrue(checker.checked); | |
| Expect.isFalse(sub2.isPaused); | |
| // Can't pause after done. | |
| sub2.pause(Future<int>.value(0)); | |
| Expect.isFalse(sub2.isPaused); | |
| sub2.pause(); | |
| Expect.isFalse(sub2.isPaused); | |
| // Respects cancel. | |
| var sub3 = s.listen(unreachable, onError: unreachable, onDone: unreachable); | |
| sub3.cancel(); | |
| sub3.onDone(unreachable); | |
| Expect.isFalse(sub3.isPaused); | |
| await flushMicrotasks(); | |
| Expect.isFalse(sub3.isPaused); | |
| // Can't pause after cancel | |
| sub3.pause(); | |
| Expect.isFalse(sub3.isPaused); | |
| sub3.pause(Future<int>.value(0)); | |
| Expect.isFalse(sub3.isPaused); | |
| // No errors. | |
| // Respects cancel while paused. | |
| var sub4 = s.listen(unreachable, onError: unreachable, onDone: unreachable); | |
| sub4.pause(); | |
| sub4.cancel(); | |
| sub4.onDone(unreachable); | |
| await flushMicrotasks(); | |
| sub4.resume(); | |
| await flushMicrotasks(); | |
| // Check that the stream is zone-aware. | |
| // Registers onDone callback. | |
| var log = []; | |
| late final Zone zone; | |
| void callback1() { | |
| // Run in correct zone. | |
| Expect.equals(zone, Zone.current); | |
| log.add("don1"); | |
| } | |
| void callback2() { | |
| // Run in correct zone. | |
| Expect.equals(zone, Zone.current); | |
| log.add("don2"); | |
| } | |
| zone = Zone.current.fork( | |
| specification: ZoneSpecification( | |
| registerCallback: <R>(s, p, z, f) { | |
| if (f == callback1) log.add("reg1"); | |
| if (f == callback2) log.add("reg2"); | |
| return p.registerCallback<R>(z, f); | |
| }, | |
| run: <R>(s, p, z, f) { | |
| if (f == callback1) log.add("run1"); | |
| if (f == callback2) log.add("run2"); | |
| return p.run<R>(z, f); | |
| }, | |
| ), | |
| ); | |
| await zone.run(() async { | |
| var s = Stream<int>.empty(); | |
| var sub = s.listen(unreachable, onError: unreachable, onDone: callback1); | |
| sub.onDone(callback2); | |
| }); | |
| await flushMicrotasks(); | |
| Expect.listEquals(["reg1", "reg2", "run2", "don2"], log); | |
| } | |
| Future flushMicrotasks() => new Future.delayed(Duration.zero); |