| // Copyright (c) 2020, 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. |
| |
| // Checks that `Future<Future<int>>` is a valid type |
| // and that futures can contain and complete other futures. |
| |
| // This essentially checks that `FutureOr<X>` is treated correctly depending |
| // on what `X` is. |
| |
| import 'dart:async'; |
| import 'package:async_helper/async_helper.dart'; |
| import "package:expect/expect.dart"; |
| |
| main() { |
| asyncStart(); |
| |
| // Helper values and factories. |
| Future<Null> nullFuture = Future<Null>.value(null); |
| |
| var stack = StackTrace.current; |
| var error = ArgumentError("yep"); |
| Future<Null> errorFuture = Future<Null>.error(error, stack) |
| ..catchError((_) => null); |
| Future<int> fi(int n) => Future<int>.value(n); |
| Future<Future<int>> ffi(n) => Future<Future<int>>.value(fi(n)); |
| |
| // Tests that `Future<Future<int>>` can be created. |
| asyncTest(() { |
| return expectFutureFutureInt(ffi(0), 0); |
| }); |
| |
| // Check `Future.then`'s callback. |
| |
| asyncTest(() { |
| Future<int> future = nullFuture.then<int>((_) => fi(1)); |
| return expectFutureInt(future, 1); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> future = nullFuture.then<Future<int>>((_) => fi(2)); |
| return expectFutureFutureInt(future, 2); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> future = nullFuture.then<Future<int>>((_) => ffi(3)); |
| return expectFutureFutureInt(future, 3); |
| }); |
| |
| // Check `Future.then`'s `onError`. |
| |
| asyncTest(() { |
| Future<int> future = |
| errorFuture.then<int>((_) => -1, onError: (_) => fi(4)); |
| return expectFutureInt(future, 4); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> future = |
| errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => fi(5)); |
| return expectFutureFutureInt(future, 5); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> future = |
| errorFuture.then<Future<int>>((_) => fi(-1), onError: (_) => ffi(6)); |
| return expectFutureFutureInt(future, 6); |
| }); |
| |
| // Check `Future.catchError`. |
| // Its implied `FutureOr` return type is based on the original future's type. |
| |
| asyncTest(() { |
| Future<int> errorFuture = Future<int>.error(error, stack); |
| Future<int> future = errorFuture.catchError((_) => fi(7)); |
| return expectFutureInt(future, 7); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack); |
| Future<Future<int>> future = errorFuture.catchError((_) => fi(8)); |
| return expectFutureFutureInt(future, 8); |
| }); |
| |
| asyncTest(() { |
| Future<Future<int>> errorFuture = Future<Future<int>>.error(error, stack); |
| Future<Future<int>> future = errorFuture.catchError((_) => ffi(9)); |
| return expectFutureFutureInt(future, 9); |
| }); |
| |
| // Check `Completer.complete`. |
| |
| asyncTest(() { |
| var completer = Completer<int>()..complete(fi(10)); |
| return expectFutureInt(completer.future, 10); |
| }); |
| |
| asyncTest(() { |
| var completer = Completer<Future<int>>()..complete(fi(11)); |
| return expectFutureFutureInt(completer.future, 11); |
| }); |
| |
| asyncTest(() { |
| var completer = Completer<Future<int>>()..complete(ffi(12)); |
| return expectFutureFutureInt(completer.future, 12); |
| }); |
| |
| // Future<Object> works correctly when Object is another Future. |
| asyncTest(() { |
| Future<Object> future = nullFuture.then<Object>((_) => fi(13)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| return future.then<void>((o) { |
| Expect.equals(13, o); |
| }); |
| }); |
| |
| asyncTest(() { |
| Future<Object> future = nullFuture.then<Object>((_) => ffi(14)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| Expect.notType<Future<Future<int>>>(future); |
| return future.then<void>((v) => expectFutureInt(v, 14)); |
| }); |
| |
| asyncTest(() { |
| Future<Object> future = |
| errorFuture.then<Object>((_) => -1, onError: (_) => fi(15)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| return future.then<void>((o) { |
| Expect.equals(15, o); |
| }); |
| }); |
| |
| asyncTest(() { |
| Future<Object> future = |
| errorFuture.then<Object>((_) => -1, onError: (_) => ffi(16)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| Expect.notType<Future<Future<int>>>(future); |
| return future.then<void>((v) => expectFutureInt(v, 16)); |
| }); |
| |
| asyncTest(() { |
| Future<Object> errorFuture = Future<Object>.error(error, stack); |
| Future<Object> future = errorFuture.catchError((_) => fi(17)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| return future.then<void>((o) { |
| Expect.equals(17, o); |
| }); |
| }); |
| |
| asyncTest(() { |
| Future<Object> errorFuture = Future<Object>.error(error, stack); |
| Future<Object> future = errorFuture.catchError((_) => ffi(18)); |
| Expect.type<Future<Object>>(future); |
| Expect.notType<Future<int>>(future); |
| Expect.notType<Future<Future<int>>>(future); |
| return future.then<void>((v) => expectFutureInt(v, 18)); |
| }); |
| |
| asyncEnd(); |
| } |
| |
| // Checks that future is a Future<Future<int>> containing the value Future<int> |
| // which then contains the value 42. |
| Future<void> expectFutureFutureInt(dynamic future, int n) { |
| Expect.type<Future<Future<int>>>(future); |
| asyncStart(); |
| return future.then<void>((dynamic v) { |
| Expect.type<Future<int>>(v, "$n"); |
| return expectFutureInt(v, n).then(asyncSuccess); |
| }); |
| } |
| |
| Future<void> expectFutureInt(dynamic future, int n) { |
| Expect.type<Future<int>>(future); |
| asyncStart(); |
| return future.then<void>((dynamic v) { |
| Expect.type<int>(v, "$n"); |
| Expect.equals(n, v); |
| asyncEnd(); |
| }); |
| } |