blob: 09ea29a0abd0a364fce633b92c92c9d6dc5835de [file] [log] [blame]
// 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.
import 'dart:async';
import 'package:async/src/future_group.dart';
import 'package:test/test.dart';
import 'utils.dart';
void main() {
var futureGroup;
setUp(() {
futureGroup = new FutureGroup();
});
group("with no futures", () {
test("never completes if nothing happens", () async {
var completed = false;
futureGroup.future.then((_) => completed = true);
await flushMicrotasks();
expect(completed, isFalse);
});
test("completes once it's closed", () {
expect(futureGroup.future, completion(isEmpty));
futureGroup.close();
});
});
group("with a future that already completed", () {
test("never completes if nothing happens", () async {
futureGroup.add(new Future.value());
await flushMicrotasks();
var completed = false;
futureGroup.future.then((_) => completed = true);
await flushMicrotasks();
expect(completed, isFalse);
});
test("completes once it's closed", () async {
futureGroup.add(new Future.value());
await flushMicrotasks();
expect(futureGroup.future, completes);
futureGroup.close();
});
test("completes to that future's value", () {
futureGroup.add(new Future.value(1));
futureGroup.close();
expect(futureGroup.future, completion(equals([1])));
});
test("completes to that future's error, even if it's not closed", () {
futureGroup.add(new Future.error("error"));
expect(futureGroup.future, throwsA("error"));
});
});
test("completes once all contained futures complete", () async {
var completer1 = new Completer();
var completer2 = new Completer();
var completer3 = new Completer();
futureGroup.add(completer1.future);
futureGroup.add(completer2.future);
futureGroup.add(completer3.future);
futureGroup.close();
var completed = false;
futureGroup.future.then((_) => completed = true);
completer1.complete();
await flushMicrotasks();
expect(completed, isFalse);
completer2.complete();
await flushMicrotasks();
expect(completed, isFalse);
completer3.complete();
await flushMicrotasks();
expect(completed, isTrue);
});
test("completes to the values of the futures in order of addition", () {
var completer1 = new Completer();
var completer2 = new Completer();
var completer3 = new Completer();
futureGroup.add(completer1.future);
futureGroup.add(completer2.future);
futureGroup.add(completer3.future);
futureGroup.close();
// Complete the completers in reverse order to prove that that doesn't
// affect the result order.
completer3.complete(3);
completer2.complete(2);
completer1.complete(1);
expect(futureGroup.future, completion(equals([1, 2, 3])));
});
test("completes to the first error to be emitted, even if it's not closed",
() {
var completer1 = new Completer();
var completer2 = new Completer();
var completer3 = new Completer();
futureGroup.add(completer1.future);
futureGroup.add(completer2.future);
futureGroup.add(completer3.future);
completer2.completeError("error 2");
completer1.completeError("error 1");
expect(futureGroup.future, throwsA("error 2"));
});
group("onIdle:", () {
test("emits an event when the last pending future completes", () async {
var idle = false;
futureGroup.onIdle.listen((_) => idle = true);
var completer1 = new Completer();
var completer2 = new Completer();
var completer3 = new Completer();
futureGroup.add(completer1.future);
futureGroup.add(completer2.future);
futureGroup.add(completer3.future);
await flushMicrotasks();
expect(idle, isFalse);
expect(futureGroup.isIdle, isFalse);
completer1.complete();
await flushMicrotasks();
expect(idle, isFalse);
expect(futureGroup.isIdle, isFalse);
completer2.complete();
await flushMicrotasks();
expect(idle, isFalse);
expect(futureGroup.isIdle, isFalse);
completer3.complete();
await flushMicrotasks();
expect(idle, isTrue);
expect(futureGroup.isIdle, isTrue);
});
test("emits an event each time it becomes idle", () async {
var idle = false;
futureGroup.onIdle.listen((_) => idle = true);
var completer = new Completer();
futureGroup.add(completer.future);
completer.complete();
await flushMicrotasks();
expect(idle, isTrue);
expect(futureGroup.isIdle, isTrue);
idle = false;
completer = new Completer();
futureGroup.add(completer.future);
await flushMicrotasks();
expect(idle, isFalse);
expect(futureGroup.isIdle, isFalse);
completer.complete();
await flushMicrotasks();
expect(idle, isTrue);
expect(futureGroup.isIdle, isTrue);
});
test("emits an event when the group closes", () async {
// It's important that the order of events here stays consistent over
// time, since code may rely on it in subtle ways.
var idle = false;
var onIdleDone = false;
var futureFired = false;
futureGroup.onIdle.listen(expectAsync((_) {
expect(futureFired, isFalse);
idle = true;
}), onDone: expectAsync(() {
expect(idle, isTrue);
expect(futureFired, isFalse);
onIdleDone = true;
}));
futureGroup.future.then(expectAsync((_) {
expect(idle, isTrue);
expect(onIdleDone, isTrue);
futureFired = true;
}));
var completer = new Completer();
futureGroup.add(completer.future);
futureGroup.close();
await flushMicrotasks();
expect(idle, isFalse);
expect(futureGroup.isIdle, isFalse);
completer.complete();
await flushMicrotasks();
expect(idle, isTrue);
expect(futureGroup.isIdle, isTrue);
expect(futureFired, isTrue);
});
});
}