| // Copyright (c) 2017, 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 'dart:math' show Random; |
| |
| import 'package:async/async.dart'; |
| import 'package:test/test.dart'; |
| |
| final someStack = StackTrace.current; |
| Result<int> res(int n) => Result<int>.value(n); |
| Result err(n) => ErrorResult('$n', someStack); |
| |
| /// Helper function creating an iterable of futures. |
| Iterable<Future<int>> futures(int count, |
| {bool Function(int index)? throwWhen}) sync* { |
| for (var i = 0; i < count; i++) { |
| if (throwWhen != null && throwWhen(i)) { |
| yield Future<int>.error('$i', someStack); |
| } else { |
| yield Future<int>.value(i); |
| } |
| } |
| } |
| |
| void main() { |
| test('empty', () async { |
| var all = await Result.captureAll<int>(futures(0)); |
| expect(all, []); |
| }); |
| |
| group('futures only,', () { |
| test('single', () async { |
| var all = await Result.captureAll<int>(futures(1)); |
| expect(all, [res(0)]); |
| }); |
| |
| test('multiple', () async { |
| var all = await Result.captureAll<int>(futures(3)); |
| expect(all, [res(0), res(1), res(2)]); |
| }); |
| |
| test('error only', () async { |
| var all = |
| await Result.captureAll<int>(futures(1, throwWhen: (_) => true)); |
| expect(all, [err(0)]); |
| }); |
| |
| test('multiple error only', () async { |
| var all = |
| await Result.captureAll<int>(futures(3, throwWhen: (_) => true)); |
| expect(all, [err(0), err(1), err(2)]); |
| }); |
| |
| test('mixed error and value', () async { |
| var all = |
| await Result.captureAll<int>(futures(4, throwWhen: (x) => x.isOdd)); |
| expect(all, [res(0), err(1), res(2), err(3)]); |
| }); |
| |
| test('completion permutation 1-2-3', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[0].complete(1); |
| await 0; |
| cs[1].complete(2); |
| await 0; |
| cs[2].completeError('3', someStack); |
| }); |
| |
| test('completion permutation 1-3-2', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[0].complete(1); |
| await 0; |
| cs[2].completeError('3', someStack); |
| await 0; |
| cs[1].complete(2); |
| }); |
| |
| test('completion permutation 2-1-3', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[1].complete(2); |
| await 0; |
| cs[0].complete(1); |
| await 0; |
| cs[2].completeError('3', someStack); |
| }); |
| |
| test('completion permutation 2-3-1', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[1].complete(2); |
| await 0; |
| cs[2].completeError('3', someStack); |
| await 0; |
| cs[0].complete(1); |
| }); |
| |
| test('completion permutation 3-1-2', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[2].completeError('3', someStack); |
| await 0; |
| cs[0].complete(1); |
| await 0; |
| cs[1].complete(2); |
| }); |
| |
| test('completion permutation 3-2-1', () async { |
| var cs = List.generate(3, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| expect(all, completion([res(1), res(2), err(3)])); |
| await 0; |
| cs[2].completeError('3', someStack); |
| await 0; |
| cs[1].complete(2); |
| await 0; |
| cs[0].complete(1); |
| }); |
| |
| var seed = Random().nextInt(0x100000000); |
| var n = 25; // max 32, otherwise rnd.nextInt(1<<n) won't work. |
| test('randomized #$n seed:${seed.toRadixString(16)}', () async { |
| var cs = List.generate(n, (_) => Completer<int>()); |
| var all = Result.captureAll<int>(cs.map((c) => c.future)); |
| var rnd = Random(seed); |
| var throwFlags = rnd.nextInt(1 << n); // Bit-flag for throwing. |
| bool throws(int index) => (throwFlags & (1 << index)) != 0; |
| var expected = List.generate(n, (x) => throws(x) ? err(x) : res(x)); |
| |
| expect(all, completion(expected)); |
| |
| var completeFunctions = List<Function()>.generate(n, (i) { |
| var c = cs[i]; |
| return () => |
| throws(i) ? c.completeError('$i', someStack) : c.complete(i); |
| }); |
| completeFunctions.shuffle(rnd); |
| for (var i = 0; i < n; i++) { |
| await 0; |
| completeFunctions[i](); |
| } |
| }); |
| }); |
| group('values only,', () { |
| test('single', () async { |
| var all = await Result.captureAll<int>(<int>[1]); |
| expect(all, [res(1)]); |
| }); |
| test('multiple', () async { |
| var all = await Result.captureAll<int>(<int>[1, 2, 3]); |
| expect(all, [res(1), res(2), res(3)]); |
| }); |
| }); |
| group('mixed futures and values,', () { |
| test('no error', () async { |
| var all = await Result.captureAll<int>(<FutureOr<int>>[ |
| 1, |
| Future<int>(() => 2), |
| 3, |
| Future<int>.value(4), |
| ]); |
| expect(all, [res(1), res(2), res(3), res(4)]); |
| }); |
| test('error', () async { |
| var all = await Result.captureAll<int>(<FutureOr<int>>[ |
| 1, |
| Future<int>(() => 2), |
| 3, |
| Future<int>(() async => await Future.error('4', someStack)), |
| Future<int>.value(5) |
| ]); |
| expect(all, [res(1), res(2), res(3), err(4), res(5)]); |
| }); |
| }); |
| } |