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