blob: 22e90f89fa5e7be80fc002e9c9be4dbb1dd9e24a [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() {
late FutureGroup futureGroup;
setUp(() {
futureGroup = 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(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(Future.value());
await flushMicrotasks();
expect(futureGroup.future, completes);
futureGroup.close();
});
test("completes to that future's value", () {
futureGroup.add(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(Future.error('error'));
expect(futureGroup.future, throwsA('error'));
});
});
test('completes once all contained futures complete', () async {
var completer1 = Completer();
var completer2 = Completer();
var completer3 = 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 = Completer();
var completer2 = Completer();
var completer3 = 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 = Completer();
var completer2 = Completer();
var completer3 = 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 = Completer();
var completer2 = Completer();
var completer3 = 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 = Completer();
futureGroup.add(completer.future);
completer.complete();
await flushMicrotasks();
expect(idle, isTrue);
expect(futureGroup.isIdle, isTrue);
idle = false;
completer = 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(expectAsync1((_) {
expect(futureFired, isFalse);
idle = true;
}), onDone: expectAsync0(() {
expect(idle, isTrue);
expect(futureFired, isFalse);
onIdleDone = true;
}));
futureGroup.future.then(expectAsync1((_) {
expect(idle, isTrue);
expect(onIdleDone, isTrue);
futureFired = true;
}));
var completer = 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);
});
});
}