Index: tests/language/regress_23996_test.dart |
diff --git a/tests/language/regress_23996_test.dart b/tests/language/regress_23996_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4401a468d4e8e444dc54aa70b3973678026cdee8 |
--- /dev/null |
+++ b/tests/language/regress_23996_test.dart |
@@ -0,0 +1,77 @@ |
+// 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. |
+ |
+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; |
+ }); |
+} |