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 'dart:async';
6 :
7 : import 'package:matcher/matcher.dart';
8 :
9 : import '../utils.dart';
10 : import 'async_matcher.dart';
11 : import 'expect.dart';
12 :
13 : /// Matches a [Future] that completes successfully with a value.
14 : ///
15 : /// Note that this creates an asynchronous expectation. The call to `expect()`
16 : /// that includes this will return immediately and execution will continue.
17 : /// Later, when the future completes, the actual expectation will run.
18 : ///
19 : /// To test that a Future completes with an exception, you can use [throws] and
20 : /// [throwsA].
21 : ///
22 : /// This returns an [AsyncMatcher], so [expect] won't complete until the matched
23 : /// future does.
24 : final Matcher completes = const _Completes(null);
25 :
26 : /// Matches a [Future] that completes succesfully with a value that matches
27 : /// [matcher].
28 : ///
29 : /// Note that this creates an asynchronous expectation. The call to
30 : /// `expect()` that includes this will return immediately and execution will
31 : /// continue. Later, when the future completes, the actual expectation will run.
32 : ///
33 : /// To test that a Future completes with an exception, you can use [throws] and
34 : /// [throwsA].
35 : ///
36 : /// The [description] parameter is deprecated and shouldn't be used.
37 : ///
38 : /// This returns an [AsyncMatcher], so [expect] won't complete until the matched
39 : /// future does.
40 : Matcher completion(matcher, [@deprecated String description]) =>
41 0 : new _Completes(wrapMatcher(matcher));
42 :
43 : class _Completes extends AsyncMatcher {
44 : final Matcher _matcher;
45 :
46 0 : const _Completes(this._matcher);
47 :
48 : // Avoid async/await so we synchronously start listening to [item].
49 : /*FutureOr<String>*/ matchAsync(item) {
50 0 : if (item is! Future) return "was not a Future";
51 :
52 0 : return item.then((value) async {
53 0 : if (_matcher == null) return null;
54 :
55 : String result;
56 0 : if (_matcher is AsyncMatcher) {
57 0 : result = await (_matcher as AsyncMatcher).matchAsync(value);
58 : if (result == null) return null;
59 : } else {
60 0 : var matchState = {};
61 0 : if (_matcher.matches(value, matchState)) return null;
62 0 : result = _matcher
63 0 : .describeMismatch(value, new StringDescription(), matchState, false)
64 0 : .toString();
65 : }
66 :
67 0 : var buffer = new StringBuffer();
68 0 : buffer.writeln(indent(prettyPrint(value), first: 'emitted '));
69 0 : if (result.isNotEmpty) buffer.writeln(indent(result, first: ' which '));
70 0 : return buffer.toString().trimRight();
71 0 : });
72 : }
73 :
74 : Description describe(Description description) {
75 0 : if (_matcher == null) {
76 0 : description.add('completes successfully');
77 : } else {
78 0 : description.add('completes to a value that ').addDescriptionOf(_matcher);
79 : }
80 : return description;
81 : }
82 : }
83 :
84 : /// Matches a [Future] that does not complete.
85 : ///
86 : /// Note that this creates an asynchronous expectation. The call to
87 : /// `expect()` that includes this will return immediately and execution will
88 : /// continue.
89 : final Matcher doesNotComplete = const _DoesNotComplete(20);
90 :
91 : class _DoesNotComplete extends Matcher {
92 : final int _timesToPump;
93 0 : const _DoesNotComplete(this._timesToPump);
94 :
95 : // TODO(grouma) - Make this a top level function
96 : Future _pumpEventQueue(times) {
97 0 : if (times == 0) return new Future.value();
98 0 : return new Future(() => _pumpEventQueue(times - 1));
99 : }
100 :
101 : Description describe(Description description) {
102 0 : description.add("does not complete");
103 : return description;
104 : }
105 :
106 : @override
107 : bool matches(item, Map matchState) {
108 0 : if (item is! Future) return false;
109 0 : item.then((value) {
110 0 : fail('Future was not expected to complete but completed with a value of '
111 0 : '$value');
112 : });
113 0 : expect(_pumpEventQueue(_timesToPump), completes);
114 : return true;
115 : }
116 :
117 : Description describeMismatch(
118 : item, Description description, Map matchState, bool verbose) {
119 0 : if (item is! Future) return description.add("$item is not a Future");
120 : return description;
121 : }
122 : }
|