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

Side by Side Diff: pkg/scheduled_test/lib/src/stream_matcher.dart

Issue 812253002: Delete a bunch of packages that are now on GitHub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Un-delete http Created 6 years 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 scheduled_test.stream_matcher;
6
7 import 'dart:async';
8 import 'dart:collection';
9
10 import '../scheduled_stream.dart';
11 import '../scheduled_test.dart';
12 import 'utils.dart';
13
14 /// An abstract superclass for matchers that validate and consume zero or more
15 /// values emitted by a [ScheduledStream].
16 ///
17 /// [StreamMatcher]s are most commonly used by passing them to
18 /// [ScheduledStream.expect].
19 abstract class StreamMatcher {
20 /// Wrap a [Matcher], [StreamMatcher] or [Object] in a [StreamMatcher].
21 ///
22 /// If this isn't a [StreamMatcher], a [nextValue] matcher is used.
23 factory StreamMatcher.wrap(matcher) =>
24 matcher is StreamMatcher ? matcher : nextValue(matcher);
25
26 StreamMatcher();
27
28 /// Tries to match [this] against [stream].
29 ///
30 /// If the match succeeds, this returns `null`. If it fails, this returns a
31 /// [Description] describing the failure.
32 Future<Description> tryMatch(ScheduledStream stream);
33
34 /// Returns whether [this] would match [stream] without actually consuming
35 /// values from [stream].
36 ///
37 /// If the match succeeds, this returns `null`. If it fails, this returns a
38 /// [Description] describing the failure.
39 Future<Description> hasMatch(ScheduledStream stream) {
40 var fork = stream.fork();
41 return tryMatch(fork).whenComplete(fork.close);
42 }
43
44 String toString();
45 }
46
47 /// A matcher that consumes and matches a single value.
48 ///
49 /// [matcher] can be a [Matcher] or an [Object], but not a [StreamMatcher].
50 StreamMatcher nextValue(matcher) => new _NextValueMatcher(matcher);
51
52 /// A matcher that consumes [n] values and matches a list containing those
53 /// objects against [matcher].
54 ///
55 /// [matcher] can be a [Matcher] or an [Object], but not a [StreamMatcher].
56 StreamMatcher nextValues(int n, matcher) => new _NextValuesMatcher(n, matcher);
57
58 /// A matcher that matches several sub-matchers in sequence.
59 ///
60 /// Each element of [streamMatchers] can be a [StreamMatcher], a [Matcher], or
61 /// an [Object].
62 StreamMatcher inOrder(Iterable streamMatchers) {
63 streamMatchers = streamMatchers.toList();
64 if (streamMatchers.length == 1) {
65 return new StreamMatcher.wrap(streamMatchers.first);
66 } else {
67 return new _InOrderMatcher(streamMatchers);
68 }
69 }
70
71 /// A matcher that consumes values emitted by a stream until one matching
72 /// [streamMatcher] is emitted.
73 ///
74 /// This will fail if the stream never emits a value that matches
75 /// [streamMatcher].
76 ///
77 /// [streamMatcher] can be a [StreamMatcher], a [Matcher] or an [Object].
78 StreamMatcher consumeThrough(streamMatcher) =>
79 new _ConsumeThroughMatcher(streamMatcher);
80
81 /// A matcher that consumes values emitted by a stream as long as they match
82 /// [streamMatcher].
83 ///
84 /// This matcher will always match a stream. It exists to consume values. If
85 /// [streamMatcher] consumes more than one value, the next match will begin
86 /// after all the consumed values.
87 ///
88 /// [streamMatcher] can be a [StreamMatcher], a [Matcher] or an [Object].
89 StreamMatcher consumeWhile(streamMatcher) =>
90 new _ConsumeWhileMatcher(streamMatcher);
91
92 /// A matcher that matches either [streamMatcher1], [streamMatcher2], or both.
93 ///
94 /// If both matchers match the stream, the one that consumed more values will be
95 /// used.
96 ///
97 /// Both [streamMatcher1] and [streamMatcher2] can be a [StreamMatcher], a
98 /// [Matcher], or an [Object].
99 StreamMatcher either(streamMatcher1, streamMatcher2) =>
100 new _EitherMatcher(streamMatcher1, streamMatcher2);
101
102 /// A matcher that consumes [streamMatcher] if it matches, or nothing otherwise.
103 ///
104 /// This matcher will always match a stream. It exists to consume values that
105 /// may or may not be emitted by a stream.
106 ///
107 /// [streamMatcher] can be a [StreamMatcher], a [Matcher], or an [Object].
108 StreamMatcher allow(streamMatcher) => new _AllowMatcher(streamMatcher);
109
110 /// A matcher that asserts that a stream never emits values matching
111 /// [streamMatcher].
112 ///
113 /// This will consume the remainder of a stream.
114 ///
115 /// [streamMatcher] can be a [StreamMatcher], a [Matcher], or an [Object].
116 StreamMatcher never(streamMatcher) => new _NeverMatcher(streamMatcher);
117
118 /// A matcher that matches a stream that emits no more values.
119 StreamMatcher get isDone => new _IsDoneMatcher();
120
121 /// See [nextValue].
122 class _NextValueMatcher extends StreamMatcher {
123 final Matcher _matcher;
124
125 _NextValueMatcher(matcher)
126 : _matcher = wrapMatcher(matcher);
127
128 Future<Description> tryMatch(ScheduledStream stream) {
129 return stream.hasNext.then((hasNext) {
130 if (!hasNext) {
131 return new StringDescription("unexpected end of stream");
132 }
133 return stream.next().then((value) {
134 var matchState = {};
135 if (_matcher.matches(value, matchState)) return null;
136 return _matcher.describeMismatch(value, new StringDescription(),
137 matchState, false);
138 });
139 });
140 }
141
142 String toString() => _matcher.describe(new StringDescription()).toString();
143 }
144
145 /// See [nextValues].
146 class _NextValuesMatcher extends StreamMatcher {
147 final int _n;
148 final Matcher _matcher;
149
150 _NextValuesMatcher(this._n, matcher)
151 : _matcher = wrapMatcher(matcher);
152
153 Future<Description> tryMatch(ScheduledStream stream) {
154 var collectedValues = [];
155 collectValues(count) {
156 if (count == 0) return null;
157
158 return stream.hasNext.then((hasNext) {
159 if (!hasNext) return new StringDescription('unexpected end of stream');
160
161 return stream.next().then((value) {
162 collectedValues.add(value);
163 return collectValues(count - 1);
164 });
165 });
166 }
167
168 return collectValues(_n).then((failure) {
169 if (failure != null) return failure;
170 var matchState = {};
171 if (_matcher.matches(collectedValues, matchState)) return null;
172 return _matcher.describeMismatch(collectedValues, new StringDescription(),
173 matchState, false);
174 });
175 }
176
177 String toString() {
178 return new StringDescription('$_n values that ')
179 .addDescriptionOf(_matcher)
180 .toString();
181 }
182 }
183
184 /// See [inOrder].
185 class _InOrderMatcher extends StreamMatcher {
186 final List<StreamMatcher> _matchers;
187
188 _InOrderMatcher(Iterable streamMatchers)
189 : _matchers = streamMatchers.map((matcher) =>
190 new StreamMatcher.wrap(matcher)).toList();
191
192 Future<Description> tryMatch(ScheduledStream stream) {
193 var matchers = new Queue.from(_matchers);
194
195 matchNext() {
196 if (matchers.isEmpty) return new Future.value();
197 var matcher = matchers.removeFirst();
198 return matcher.tryMatch(stream).then((failure) {
199 if (failure == null) return matchNext();
200 var newFailure = new StringDescription(
201 'matcher #${_matchers.length - matchers.length} failed');
202 if (failure.length != 0) newFailure.add(':\n$failure');
203 return newFailure;
204 });
205 }
206
207 return matchNext();
208 }
209
210 String toString() => _matchers
211 .map((matcher) => prefixLines(matcher.toString(), firstPrefix: '* '))
212 .join('\n');
213 }
214
215 /// See [consumeThrough].
216 class _ConsumeThroughMatcher extends StreamMatcher {
217 final StreamMatcher _matcher;
218
219 _ConsumeThroughMatcher(streamMatcher)
220 : _matcher = new StreamMatcher.wrap(streamMatcher);
221
222 Future<Description> tryMatch(ScheduledStream stream) {
223 consumeNext() {
224 return stream.hasNext.then((hasNext) {
225 if (!hasNext) return new StringDescription("unexpected end of stream");
226
227 return _matcher.hasMatch(stream).then((failure) {
228 if (failure != null) return stream.next().then((_) => consumeNext());
229 return _matcher.tryMatch(stream);
230 });
231 });
232 }
233
234 return consumeNext();
235 }
236
237 String toString() {
238 var matcherString = _matcher.toString();
239 if (matcherString.contains("\n")) {
240 return 'values followed by:\n' + prefixLines(matcherString, prefix: ' ');
241 } else {
242 return 'values followed by $matcherString';
243 }
244 }
245 }
246
247 /// See [consumeWhile].
248 class _ConsumeWhileMatcher extends StreamMatcher {
249 final StreamMatcher _matcher;
250
251 _ConsumeWhileMatcher(matcher)
252 : _matcher = new StreamMatcher.wrap(matcher);
253
254 Future<Description> tryMatch(ScheduledStream stream) {
255 consumeNext() {
256 return stream.hasNext.then((hasNext) {
257 if (!hasNext) return new Future.value();
258
259 return _matcher.hasMatch(stream).then((failure) {
260 if (failure != null) return new Future.value();
261 return _matcher.tryMatch(stream).then((_) => consumeNext());
262 });
263 });
264 }
265
266 return consumeNext();
267 }
268
269 String toString() {
270 var matcherString = _matcher.toString();
271 if (matcherString.contains("\n")) {
272 return 'any number of\n' + prefixLines(matcherString, prefix: ' ');
273 } else {
274 return 'any number of $matcherString';
275 }
276 }
277 }
278
279 /// See [either].
280 class _EitherMatcher extends StreamMatcher {
281 final StreamMatcher _matcher1;
282 final StreamMatcher _matcher2;
283
284 _EitherMatcher(streamMatcher1, streamMatcher2)
285 : _matcher1 = new StreamMatcher.wrap(streamMatcher1),
286 _matcher2 = new StreamMatcher.wrap(streamMatcher2);
287
288 Future<Description> tryMatch(ScheduledStream stream) {
289 var stream1 = stream.fork();
290 var stream2 = stream.fork();
291
292 return Future.wait([
293 _matcher1.tryMatch(stream1).whenComplete(stream1.close),
294 _matcher2.tryMatch(stream2).whenComplete(stream2.close)
295 ]).then((failures) {
296 var failure1 = failures.first;
297 var failure2 = failures.last;
298
299 // If both matchers matched, use the one that consumed more of the stream.
300 if (failure1 == null && failure2 == null) {
301 if (stream1.emittedValues.length >= stream2.emittedValues.length) {
302 return _matcher1.tryMatch(stream);
303 } else {
304 return _matcher2.tryMatch(stream);
305 }
306 } else if (failure1 == null) {
307 return _matcher1.tryMatch(stream);
308 } else if (failure2 == null) {
309 return _matcher2.tryMatch(stream);
310 } else {
311 return new StringDescription('both\n')
312 .add(prefixLines(failure1.toString(), prefix: ' '))
313 .add('\nand\n')
314 .add(prefixLines(failure2.toString(), prefix: ' '))
315 .toString();
316 }
317 });
318 }
319
320 String toString() {
321 return new StringDescription('either\n')
322 .add(prefixLines(_matcher1.toString(), prefix: ' '))
323 .add('\nor\n')
324 .add(prefixLines(_matcher2.toString(), prefix: ' '))
325 .toString();
326 }
327 }
328
329 /// See [allow].
330 class _AllowMatcher extends StreamMatcher {
331 final StreamMatcher _matcher;
332
333 _AllowMatcher(streamMatcher)
334 : _matcher = new StreamMatcher.wrap(streamMatcher);
335
336 Future<Description> tryMatch(ScheduledStream stream) {
337 return _matcher.hasMatch(stream).then((failure) {
338 if (failure != null) return null;
339 return _matcher.tryMatch(stream);
340 });
341 }
342
343 String toString() {
344 return new StringDescription('allow\n')
345 .add(prefixLines(_matcher.toString()))
346 .toString();
347 }
348 }
349
350 /// See [never].
351 class _NeverMatcher extends StreamMatcher {
352 final StreamMatcher _matcher;
353
354 _NeverMatcher(streamMatcher)
355 : _matcher = new StreamMatcher.wrap(streamMatcher);
356
357 Future<Description> tryMatch(ScheduledStream stream) {
358 consumeNext() {
359 return stream.hasNext.then((hasNext) {
360 if (!hasNext) return new Future.value();
361
362 return _matcher.hasMatch(stream).then((failure) {
363 if (failure != null) {
364 return stream.next().then((_) => consumeNext());
365 }
366
367 return new StringDescription("matched\n")
368 .add(prefixLines(_matcher.toString(), prefix: ' '));
369 });
370 });
371 }
372
373 return consumeNext();
374 }
375
376 String toString() =>
377 'never\n${prefixLines(_matcher.toString(), prefix: ' ')}';
378 }
379
380 /// See [isDone].
381 class _IsDoneMatcher extends StreamMatcher {
382 _IsDoneMatcher();
383
384 Future<Description> tryMatch(ScheduledStream stream) {
385 return stream.hasNext.then((hasNext) {
386 if (!hasNext) return null;
387 return new StringDescription("stream wasn't finished");
388 });
389 }
390
391 String toString() => 'is done';
392 }
393
394 /// Returns a [Future] that completes to the next value emitted by [stream]
395 /// without actually consuming that value.
396 Future _peek(ScheduledStream stream) {
397 var fork = stream.fork();
398 return fork.next().whenComplete(fork.close);
399 }
OLDNEW
« no previous file with comments | « pkg/scheduled_test/lib/src/scheduled_server/handler.dart ('k') | pkg/scheduled_test/lib/src/substitute_future.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698