| // Copyright (c) 2016, 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. |
| |
| // @dart = 2.9 |
| |
| import "dart:async"; |
| import "package:async_helper/async_helper.dart"; |
| |
| /// This test verifies that an await for loop sends the correct |
| /// signals to the stream it iterates over: |
| /// 1) A listen event. |
| /// 2) A pause event when the loop body is awaiting something, |
| /// and more elements arrive on the stream. See issue |
| /// https://github.com/dart-lang/sdk/issues/23996 . |
| /// 3) A resume event, when the loop is again ready to iterate. |
| main() { |
| Completer listenEventReceived = new Completer(); |
| Completer pauseEventReceived = new Completer(); |
| Completer resumeEventReceived = new Completer(); |
| StreamController controller = new StreamController( |
| onListen: () => listenEventReceived.complete(), |
| onPause: () => pauseEventReceived.complete(), |
| onResume: () => resumeEventReceived.complete()); |
| |
| Completer forLoopEntered = new Completer(); |
| |
| /// The send function puts items on the stream. It waits for a |
| /// listener, puts "first" on the stream, waits for the for loop |
| /// to start (and eventually block), puts "second" on the stream |
| /// multiple times, letting the event loop run, until the for loop |
| /// pauses the stream because it it blocked. |
| /// The for loop unblocks after the pause message is received, and |
| /// reads the stream items, sending a stream resume message when it |
| /// is ready for more. |
| /// Then the send function puts a final "third" on the stream, and |
| /// closes the stream. |
| send() async { |
| await listenEventReceived.future; |
| controller.add('first'); |
| await forLoopEntered.future; |
| var timer = new Timer.periodic(new Duration(milliseconds: 10), (timer) { |
| controller.add('second'); |
| }); |
| await pauseEventReceived.future; |
| // pauseEventReceived.future completes when controller.stream is |
| // paused by the await-for loop below. What's specified is that |
| // await-for must pause immediately on an "await", but instead |
| // the implementations agree on not pausing until receiving the |
| // next event. For this reason, [timer] will call its callback at |
| // least once before we cancel it again. |
| timer.cancel(); |
| await resumeEventReceived.future; |
| controller.add('third'); |
| controller.close(); |
| } |
| |
| receive() async { |
| bool thirdReceived = false; |
| await for (var entry in controller.stream) { |
| if (entry == 'first') { |
| forLoopEntered.complete(); |
| await pauseEventReceived.future; |
| } else if (entry == 'third') { |
| thirdReceived = true; |
| } |
| } |
| if (!thirdReceived) { |
| throw "Error in await-for loop: 'third' not received"; |
| } |
| } |
| |
| asyncTest(() async { |
| // We need to start both functions in parallel, and wait on them both. |
| var f = send(); |
| await receive(); |
| await f; |
| }); |
| } |