Line data Source code
1 : // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'package:matcher/matcher.dart'; 6 : import 'package:test_api/hooks.dart' show pumpEventQueue; 7 : 8 : import 'async_matcher.dart'; 9 : import 'expect.dart'; 10 : import 'util/pretty_print.dart'; 11 : 12 : /// Matches a [Future] that completes successfully with any value. 13 : /// 14 : /// This creates an asynchronous expectation. The call to [expect] will return 15 : /// immediately and execution will continue. Later, when the future completes, 16 : /// the expectation against [matcher] will run. To wait for the future to 17 : /// complete and the expectation to run use [expectLater] and wait on the 18 : /// returned future. 19 : /// 20 : /// To test that a Future completes with an exception, you can use [throws] and 21 : /// [throwsA]. 22 0 : final Matcher completes = const _Completes(null); 23 : 24 : /// Matches a [Future] that completes succesfully with a value that matches 25 : /// [matcher]. 26 : /// 27 : /// This creates an asynchronous expectation. The call to [expect] will return 28 : /// immediately and execution will continue. Later, when the future completes, 29 : /// the expectation against [matcher] will run. To wait for the future to 30 : /// complete and the expectation to run use [expectLater] and wait on the 31 : /// returned future. 32 : /// 33 : /// To test that a Future completes with an exception, you can use [throws] and 34 : /// [throwsA]. 35 0 : Matcher completion(matcher, 36 : [@Deprecated('this parameter is ignored') String? description]) => 37 0 : _Completes(wrapMatcher(matcher)); 38 : 39 : class _Completes extends AsyncMatcher { 40 : final Matcher? _matcher; 41 : 42 11 : const _Completes(this._matcher); 43 : 44 : // Avoid async/await so we synchronously start listening to [item]. 45 0 : @override 46 : dynamic /*FutureOr<String>*/ matchAsync(item) { 47 0 : if (item is! Future) return 'was not a Future'; 48 : 49 0 : return item.then((value) async { 50 0 : if (_matcher == null) return null; 51 : 52 : String? result; 53 0 : if (_matcher is AsyncMatcher) { 54 0 : result = await (_matcher as AsyncMatcher).matchAsync(value) as String?; 55 : if (result == null) return null; 56 : } else { 57 0 : var matchState = {}; 58 0 : if (_matcher!.matches(value, matchState)) return null; 59 0 : result = _matcher! 60 0 : .describeMismatch(value, StringDescription(), matchState, false) 61 0 : .toString(); 62 : } 63 : 64 0 : var buffer = StringBuffer(); 65 0 : buffer.writeln(indent(prettyPrint(value), first: 'emitted ')); 66 0 : if (result.isNotEmpty) buffer.writeln(indent(result, first: ' which ')); 67 0 : return buffer.toString().trimRight(); 68 : }); 69 : } 70 : 71 0 : @override 72 : Description describe(Description description) { 73 0 : if (_matcher == null) { 74 0 : description.add('completes successfully'); 75 : } else { 76 0 : description.add('completes to a value that ').addDescriptionOf(_matcher); 77 : } 78 : return description; 79 : } 80 : } 81 : 82 : /// Matches a [Future] that does not complete. 83 : /// 84 : /// Note that this creates an asynchronous expectation. The call to 85 : /// `expect()` that includes this will return immediately and execution will 86 : /// continue. 87 0 : final Matcher doesNotComplete = const _DoesNotComplete(); 88 : 89 : class _DoesNotComplete extends Matcher { 90 11 : const _DoesNotComplete(); 91 : 92 0 : @override 93 : Description describe(Description description) { 94 0 : description.add('does not complete'); 95 : return description; 96 : } 97 : 98 0 : @override 99 : bool matches(item, Map matchState) { 100 0 : if (item is! Future) return false; 101 0 : item.then((value) { 102 0 : fail('Future was not expected to complete but completed with a value of ' 103 : '$value'); 104 : }); 105 0 : expect(pumpEventQueue(), completes); 106 : return true; 107 : } 108 : 109 0 : @override 110 : Description describeMismatch( 111 : item, Description description, Map matchState, bool verbose) { 112 0 : if (item is! Future) return description.add('$item is not a Future'); 113 : return description; 114 : } 115 : }