OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library scheduled_test.stream_matcher; | 5 library scheduled_test.stream_matcher; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
10 import '../scheduled_stream.dart'; | 10 import '../scheduled_stream.dart'; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 } | 57 } |
58 | 58 |
59 /// A matcher that consumes values emitted by a stream until one matching | 59 /// A matcher that consumes values emitted by a stream until one matching |
60 /// [matcher] is emitted. | 60 /// [matcher] is emitted. |
61 /// | 61 /// |
62 /// This will fail if the stream never emits a value that matches [matcher]. | 62 /// This will fail if the stream never emits a value that matches [matcher]. |
63 /// | 63 /// |
64 /// [matcher] can be a [Matcher] or an [Object], but not a [StreamMatcher]. | 64 /// [matcher] can be a [Matcher] or an [Object], but not a [StreamMatcher]. |
65 StreamMatcher consumeThrough(matcher) => new _ConsumeThroughMatcher(matcher); | 65 StreamMatcher consumeThrough(matcher) => new _ConsumeThroughMatcher(matcher); |
66 | 66 |
| 67 /// A matcher that consumes values emitted by a stream as long as they match |
| 68 /// [matcher]. |
| 69 /// |
| 70 /// This matcher will always match a stream. It exists to consume values. |
| 71 /// |
| 72 /// [matcher] can be a [Matcher] or an [Object], but not a [StreamMatcher]. |
| 73 StreamMatcher consumeWhile(matcher) => new _ConsumeWhileMatcher(matcher); |
| 74 |
67 /// A matcher that matches either [streamMatcher1], [streamMatcher2], or both. | 75 /// A matcher that matches either [streamMatcher1], [streamMatcher2], or both. |
68 /// | 76 /// |
69 /// If both matchers match the stream, the one that consumed more values will be | 77 /// If both matchers match the stream, the one that consumed more values will be |
70 /// used. | 78 /// used. |
71 /// | 79 /// |
72 /// Both [streamMatcher1] and [streamMatcher2] can be a [StreamMatcher], a | 80 /// Both [streamMatcher1] and [streamMatcher2] can be a [StreamMatcher], a |
73 /// [Matcher], or an [Object]. | 81 /// [Matcher], or an [Object]. |
74 StreamMatcher either(streamMatcher1, streamMatcher2) => | 82 StreamMatcher either(streamMatcher1, streamMatcher2) => |
75 new _EitherMatcher(streamMatcher1, streamMatcher2); | 83 new _EitherMatcher(streamMatcher1, streamMatcher2); |
76 | 84 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 return consumeNext(); | 212 return consumeNext(); |
205 }); | 213 }); |
206 }); | 214 }); |
207 } | 215 } |
208 | 216 |
209 return consumeNext(); | 217 return consumeNext(); |
210 } | 218 } |
211 | 219 |
212 String toString() { | 220 String toString() { |
213 return new StringDescription('values followed by ') | 221 return new StringDescription('values followed by ') |
214 .addDescriptionOf(_matcher).toString(); | 222 .addDescriptionOf(_matcher).toString(); |
215 } | 223 } |
216 } | 224 } |
217 | 225 |
| 226 /// See [consumeWhile]. |
| 227 class _ConsumeWhileMatcher implements StreamMatcher { |
| 228 final Matcher _matcher; |
| 229 |
| 230 _ConsumeWhileMatcher(matcher) |
| 231 : _matcher = wrapMatcher(matcher); |
| 232 |
| 233 Future<Description> tryMatch(ScheduledStream stream) { |
| 234 consumeNext() { |
| 235 return stream.hasNext.then((hasNext) { |
| 236 if (!hasNext) return new Future.value(); |
| 237 |
| 238 return _peek(stream).then((value) { |
| 239 if (!_matcher.matches(value, {})) return null; |
| 240 return stream.next().then((_) => consumeNext()); |
| 241 }); |
| 242 }); |
| 243 } |
| 244 |
| 245 return consumeNext(); |
| 246 } |
| 247 |
| 248 String toString() { |
| 249 return new StringDescription('any number of ') |
| 250 .addDescriptionOf(_matcher).toString(); |
| 251 } |
| 252 } |
| 253 |
218 /// See [either]. | 254 /// See [either]. |
219 class _EitherMatcher implements StreamMatcher { | 255 class _EitherMatcher implements StreamMatcher { |
220 final StreamMatcher _matcher1; | 256 final StreamMatcher _matcher1; |
221 final StreamMatcher _matcher2; | 257 final StreamMatcher _matcher2; |
222 | 258 |
223 _EitherMatcher(streamMatcher1, streamMatcher2) | 259 _EitherMatcher(streamMatcher1, streamMatcher2) |
224 : _matcher1 = new StreamMatcher.wrap(streamMatcher1), | 260 : _matcher1 = new StreamMatcher.wrap(streamMatcher1), |
225 _matcher2 = new StreamMatcher.wrap(streamMatcher2); | 261 _matcher2 = new StreamMatcher.wrap(streamMatcher2); |
226 | 262 |
227 Future<Description> tryMatch(ScheduledStream stream) { | 263 Future<Description> tryMatch(ScheduledStream stream) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 | 361 |
326 Future<Description> tryMatch(ScheduledStream stream) { | 362 Future<Description> tryMatch(ScheduledStream stream) { |
327 return stream.hasNext.then((hasNext) { | 363 return stream.hasNext.then((hasNext) { |
328 if (!hasNext) return null; | 364 if (!hasNext) return null; |
329 return new StringDescription("stream wasn't finished"); | 365 return new StringDescription("stream wasn't finished"); |
330 }); | 366 }); |
331 } | 367 } |
332 | 368 |
333 String toString() => 'is done'; | 369 String toString() => 'is done'; |
334 } | 370 } |
| 371 |
| 372 /// Returns a [Future] that completes to the next value emitted by [stream] |
| 373 /// without actually consuming that value. |
| 374 Future _peek(ScheduledStream stream) { |
| 375 var fork = stream.fork(); |
| 376 return fork.next().whenComplete(fork.close); |
| 377 } |
OLD | NEW |