| // 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() { |
| FutureGroup 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(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 = 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); |
| }); |
| }); |
| } |