Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: mojo/public/dart/third_party/test/lib/src/frontend/expect_async.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, 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 library test.frontend.expect_async;
6
7 import 'dart:async';
8
9 import '../backend/invoker.dart';
10 import '../backend/state.dart';
11 import 'expect.dart';
12
13 /// An object used to detect unpassed arguments.
14 const _PLACEHOLDER = const Object();
15
16 // Functions used to check how many arguments a callback takes.
17 typedef _Func0();
18 typedef _Func1(a);
19 typedef _Func2(a, b);
20 typedef _Func3(a, b, c);
21 typedef _Func4(a, b, c, d);
22 typedef _Func5(a, b, c, d, e);
23 typedef _Func6(a, b, c, d, e, f);
24
25 typedef bool _IsDoneCallback();
26
27 /// A wrapper for a function that ensures that it's called the appropriate
28 /// number of times.
29 ///
30 /// The containing test won't be considered to have completed successfully until
31 /// this function has been called the appropriate number of times.
32 ///
33 /// The wrapper function is accessible via [func]. It supports up to six
34 /// optional and/or required positional arguments, but no named arguments.
35 class _ExpectedFunction {
36 /// The wrapped callback.
37 final Function _callback;
38
39 /// The minimum number of calls that are expected to be made to the function.
40 ///
41 /// If fewer calls than this are made, the test will fail.
42 final int _minExpectedCalls;
43
44 /// The maximum number of calls that are expected to be made to the function.
45 ///
46 /// If more calls than this are made, the test will fail.
47 final int _maxExpectedCalls;
48
49 /// A callback that should return whether the function is not expected to have
50 /// any more calls.
51 ///
52 /// This will be called after every time the function is run. The test case
53 /// won't be allowed to terminate until it returns `true`.
54 ///
55 /// This may be `null`. If so, the function is considered to be done after
56 /// it's been run once.
57 final _IsDoneCallback _isDone;
58
59 /// A descriptive name for the function.
60 final String _id;
61
62 /// An optional description of why the function is expected to be called.
63 ///
64 /// If not passed, this will be an empty string.
65 final String _reason;
66
67 /// The number of times the function has been called.
68 int _actualCalls = 0;
69
70 /// The test invoker in which this function was wrapped.
71 Invoker get _invoker => _zone[#test.invoker];
72
73 /// The zone in which this function was wrapped.
74 final Zone _zone;
75
76 /// Whether this function has been called the requisite number of times.
77 bool _complete;
78
79 /// Wraps [callback] in a function that asserts that it's called at least
80 /// [minExpected] times and no more than [maxExpected] times.
81 ///
82 /// If passed, [id] is used as a descriptive name fo the function and [reason]
83 /// as a reason it's expected to be called. If [isDone] is passed, the test
84 /// won't be allowed to complete until it returns `true`.
85 _ExpectedFunction(Function callback, int minExpected, int maxExpected,
86 {String id, String reason, bool isDone()})
87 : this._callback = callback,
88 _minExpectedCalls = minExpected,
89 _maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
90 ? minExpected
91 : maxExpected,
92 this._isDone = isDone,
93 this._reason = reason == null ? '' : '\n$reason',
94 this._zone = Zone.current,
95 this._id = _makeCallbackId(id, callback) {
96 if (_invoker == null) {
97 throw new StateError("[expectAsync] was called outside of a test.");
98 } else if (maxExpected > 0 && minExpected > maxExpected) {
99 throw new ArgumentError("max ($maxExpected) may not be less than count "
100 "($minExpected).");
101 }
102
103 if (isDone != null || minExpected > 0) {
104 _invoker.addOutstandingCallback();
105 _complete = false;
106 } else {
107 _complete = true;
108 }
109 }
110
111 /// Tries to find a reasonable name for [callback].
112 ///
113 /// If [id] is passed, uses that. Otherwise, tries to determine a name from
114 /// calling `toString`. If no name can be found, returns the empty string.
115 static String _makeCallbackId(String id, Function callback) {
116 if (id != null) return "$id ";
117
118 // If the callback is not an anonymous closure, try to get the
119 // name.
120 var toString = callback.toString();
121 var prefix = "Function '";
122 var start = toString.indexOf(prefix);
123 if (start == -1) return '';
124
125 start += prefix.length;
126 var end = toString.indexOf("'", start);
127 if (end == -1) return '';
128 return "${toString.substring(start, end)} ";
129 }
130
131 /// Returns a function that has the same number of positional arguments as the
132 /// wrapped function (up to a total of 6).
133 Function get func {
134 if (_callback is _Func6) return _max6;
135 if (_callback is _Func5) return _max5;
136 if (_callback is _Func4) return _max4;
137 if (_callback is _Func3) return _max3;
138 if (_callback is _Func2) return _max2;
139 if (_callback is _Func1) return _max1;
140 if (_callback is _Func0) return _max0;
141
142 _invoker.removeOutstandingCallback();
143 throw new ArgumentError(
144 'The wrapped function has more than 6 required arguments');
145 }
146
147 // This indirection is critical. It ensures the returned function has an
148 // argument count of zero.
149 _max0() => _max6();
150
151 _max1([a0 = _PLACEHOLDER]) => _max6(a0);
152
153 _max2([a0 = _PLACEHOLDER, a1 = _PLACEHOLDER]) => _max6(a0, a1);
154
155 _max3([a0 = _PLACEHOLDER, a1 = _PLACEHOLDER, a2 = _PLACEHOLDER]) =>
156 _max6(a0, a1, a2);
157
158 _max4([a0 = _PLACEHOLDER, a1 = _PLACEHOLDER, a2 = _PLACEHOLDER,
159 a3 = _PLACEHOLDER]) => _max6(a0, a1, a2, a3);
160
161 _max5([a0 = _PLACEHOLDER, a1 = _PLACEHOLDER, a2 = _PLACEHOLDER,
162 a3 = _PLACEHOLDER, a4 = _PLACEHOLDER]) => _max6(a0, a1, a2, a3, a4);
163
164 _max6([a0 = _PLACEHOLDER, a1 = _PLACEHOLDER, a2 = _PLACEHOLDER,
165 a3 = _PLACEHOLDER, a4 = _PLACEHOLDER, a5 = _PLACEHOLDER]) =>
166 _run([a0, a1, a2, a3, a4, a5].where((a) => a != _PLACEHOLDER));
167
168 /// Runs the wrapped function with [args] and returns its return value.
169 _run(Iterable args) {
170 // Note that in the old test, this returned `null` if it encountered an
171 // error, where now it just re-throws that error because Zone machinery will
172 // pass it to the invoker anyway.
173 try {
174 _actualCalls++;
175 if (_invoker.liveTest.isComplete &&
176 _invoker.liveTest.state.result == Result.success) {
177 throw 'Callback ${_id}called ($_actualCalls) after test case '
178 '${_invoker.liveTest.test.name} had already completed.$_reason';
179 } else if (_maxExpectedCalls >= 0 && _actualCalls > _maxExpectedCalls) {
180 throw new TestFailure('Callback ${_id}called more times than expected '
181 '($_maxExpectedCalls).$_reason');
182 }
183
184 return Function.apply(_callback, args.toList());
185 } catch (error, stackTrace) {
186 _zone.handleUncaughtError(error, stackTrace);
187 return null;
188 } finally {
189 _afterRun();
190 }
191 }
192
193 /// After each time the function is run, check to see if it's complete.
194 void _afterRun() {
195 if (_complete) return;
196 if (_minExpectedCalls > 0 && _actualCalls < _minExpectedCalls) return;
197 if (_isDone != null && !_isDone()) return;
198
199 // Mark this callback as complete and remove it from the test case's
200 // oustanding callback count; if that hits zero the test is done.
201 _complete = true;
202 _invoker.removeOutstandingCallback();
203 }
204 }
205
206 /// Indicate that [callback] is expected to be called [count] number of times
207 /// (by default 1).
208 ///
209 /// The test framework will wait for the callback to run the [count] times
210 /// before it considers the current test to be complete. [callback] may take up
211 /// to six optional or required positional arguments; named arguments are not
212 /// supported.
213 ///
214 /// [max] can be used to specify an upper bound on the number of calls; if this
215 /// is exceeded the test will fail. If [max] is `0` (the default), the callback
216 /// is expected to be called exactly [count] times. If [max] is `-1`, the
217 /// callback is allowed to be called any number of times greater than [count].
218 ///
219 /// Both [id] and [reason] are optional and provide extra information about the
220 /// callback when debugging. [id] should be the name of the callback, while
221 /// [reason] should be the reason the callback is expected to be called.
222 Function expectAsync(Function callback,
223 {int count: 1, int max: 0, String id, String reason}) {
224 if (Invoker.current == null) {
225 throw new StateError("expectAsync() may only be called within a test.");
226 }
227
228 return new _ExpectedFunction(callback, count, max, id: id, reason: reason)
229 .func;
230 }
231
232 /// Indicate that [callback] is expected to be called until [isDone] returns
233 /// true.
234 ///
235 /// [isDone] is called after each time the function is run. Only when it returns
236 /// true will the callback be considered complete. [callback] may take up to six
237 /// optional or required positional arguments; named arguments are not
238 /// supported.
239 ///
240 /// Both [id] and [reason] are optional and provide extra information about the
241 /// callback when debugging. [id] should be the name of the callback, while
242 /// [reason] should be the reason the callback is expected to be called.
243 Function expectAsyncUntil(Function callback, bool isDone(),
244 {String id, String reason}) {
245 if (Invoker.current == null) {
246 throw new StateError(
247 "expectAsyncUntil() may only be called within a test.");
248 }
249
250 return new _ExpectedFunction(callback, 0, -1,
251 id: id, reason: reason, isDone: isDone).func;
252 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698