blob: 7551471a21bae8d0fa7741a3ac8865049afcf90d [file] [log] [blame]
// 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;
});
}