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 stream_state_helper; | 5 library stream_state_helper; |
6 | 6 |
7 import "../../../pkg/unittest/lib/unittest.dart"; | 7 import "../../../pkg/unittest/lib/unittest.dart"; |
8 import "dart:async"; | 8 import "dart:async"; |
9 import "dart:collection"; | 9 import "dart:collection"; |
10 | 10 |
11 class StreamProtocolTest { | 11 class StreamProtocolTest { |
12 bool trace = false; | |
13 StreamController _controller; | 12 StreamController _controller; |
14 Stream _controllerStream; | 13 Stream _controllerStream; |
15 StreamSubscription _subscription; | 14 StreamSubscription _subscription; |
16 List<Event> _expectations = new List<Event>(); | 15 List<Event> _expectations = new List<Event>(); |
17 int _nextExpectationIndex = 0; | 16 int _nextExpectationIndex = 0; |
18 Function _onComplete; | 17 Function _onComplete; |
19 | 18 |
20 StreamProtocolTest([bool broadcast = false]) { | 19 StreamProtocolTest([bool broadcast = false]) { |
21 _controller = new StreamController( | 20 _controller = new StreamController( |
22 onListen: _onSubcription, | 21 onListen: _onSubcription, |
23 onPause: _onPause, | 22 onPause: _onPause, |
24 onResume: _onResume, | 23 onResume: _onPause, |
25 onCancel: _onCancel); | 24 onCancel: _onSubcription); |
| 25 // TODO(lrn): Make it work with multiple subscribers too. |
26 if (broadcast) { | 26 if (broadcast) { |
27 _controllerStream = _controller.stream.asBroadcastStream(); | 27 _controllerStream = _controller.stream.asBroadcastStream(); |
28 } else { | 28 } else { |
29 _controllerStream = _controller.stream; | 29 _controllerStream = _controller.stream; |
30 } | 30 } |
31 _onComplete = expectAsync0((){ | 31 _onComplete = expectAsync0((){ |
32 _onComplete = null; // Being null marks the test to be complete. | 32 _onComplete = null; // Being null marks the test to be complete. |
33 }); | 33 }); |
34 } | 34 } |
35 | 35 |
(...skipping 11 matching lines...) Expand all Loading... |
47 onDone: _onDone, | 47 onDone: _onDone, |
48 cancelOnError: | 48 cancelOnError: |
49 cancelOnError); | 49 cancelOnError); |
50 } | 50 } |
51 | 51 |
52 void pause([Future resumeSignal]) { | 52 void pause([Future resumeSignal]) { |
53 if (_subscription == null) throw new StateError("Not subscribed"); | 53 if (_subscription == null) throw new StateError("Not subscribed"); |
54 _subscription.pause(resumeSignal); | 54 _subscription.pause(resumeSignal); |
55 } | 55 } |
56 | 56 |
57 void resume() { | 57 void resume([Future resumeSignal]) { |
58 if (_subscription == null) throw new StateError("Not subscribed"); | 58 if (_subscription == null) throw new StateError("Not subscribed"); |
59 _subscription.resume(); | 59 _subscription.resume(); |
60 } | 60 } |
61 | 61 |
62 void cancel() { | 62 void cancel() { |
63 if (_subscription == null) throw new StateError("Not subscribed"); | 63 if (_subscription == null) throw new StateError("Not subscribed"); |
64 _subscription.cancel(); | 64 _subscription.cancel(); |
65 _subscription = null; | 65 _subscription = null; |
66 } | 66 } |
67 | 67 |
68 // Handling of stream events. | 68 // Handling of stream events. |
69 void _onData(var data) { | 69 void _onData(var data) { |
70 if (trace) print("[Data : $data]"); | |
71 _withNextExpectation((Event expect) { | 70 _withNextExpectation((Event expect) { |
72 if (!expect.matchData(data)) { | 71 if (!expect.matchData(data)) { |
73 _fail("Expected: $expect\n" | 72 _fail("Expected: $expect\n" |
74 "Found : [Data: $data]"); | 73 "Found : [Data: $data]"); |
75 } | 74 } |
76 }); | 75 }); |
77 } | 76 } |
78 | 77 |
79 void _onError(error) { | 78 void _onError(error) { |
80 if (trace) print("[Error : $error]"); | |
81 _withNextExpectation((Event expect) { | 79 _withNextExpectation((Event expect) { |
82 if (!expect.matchError(error)) { | 80 if (!expect.matchError(error)) { |
83 _fail("Expected: $expect\n" | 81 _fail("Expected: $expect\n" |
84 "Found : [Error: ${error}]"); | 82 "Found : [Data: ${error}]"); |
85 } | 83 } |
86 }); | 84 }); |
87 } | 85 } |
88 | 86 |
89 void _onDone() { | 87 void _onDone() { |
90 if (trace) print("[Done]"); | |
91 _subscription = null; | 88 _subscription = null; |
92 _withNextExpectation((Event expect) { | 89 _withNextExpectation((Event expect) { |
93 if (!expect.matchDone()) { | 90 if (!expect.matchDone()) { |
94 _fail("Expected: $expect\n" | 91 _fail("Expected: $expect\n" |
95 "Found : [Done]"); | 92 "Found : [Done]"); |
96 } | 93 } |
97 }); | 94 }); |
98 } | 95 } |
99 | 96 |
100 void _onPause() { | 97 void _onPause() { |
101 if (trace) print("[Pause]"); | |
102 _withNextExpectation((Event expect) { | 98 _withNextExpectation((Event expect) { |
103 if (!expect.matchPause()) { | 99 if (!expect.matchPauseChange(_controller)) { |
104 _fail("Expected: $expect\n" | 100 _fail("Expected: $expect\n" |
105 "Found : [Paused]"); | 101 "Found : [Paused:${_controller.isPaused}]"); |
106 } | |
107 }); | |
108 } | |
109 | |
110 void _onResume() { | |
111 if (trace) print("[Resumed]"); | |
112 _withNextExpectation((Event expect) { | |
113 if (!expect.matchResume()) { | |
114 _fail("Expected: $expect\n" | |
115 "Found : [Resumed]"); | |
116 } | 102 } |
117 }); | 103 }); |
118 } | 104 } |
119 | 105 |
120 void _onSubcription() { | 106 void _onSubcription() { |
121 if (trace) print("[Subscribed]"); | |
122 _withNextExpectation((Event expect) { | 107 _withNextExpectation((Event expect) { |
123 if (!expect.matchSubscribe()) { | 108 if (!expect.matchSubscriptionChange(_controller)) { |
124 _fail("Expected: $expect\n" | 109 _fail("Expected: $expect\n" |
125 "Found: [Subscribed]"); | 110 "Found: [Has listener:${_controller.hasListener}, " |
| 111 "Paused:${_controller.isPaused}]"); |
126 } | 112 } |
127 }); | 113 }); |
128 } | 114 } |
129 | |
130 void _onCancel() { | |
131 if (trace) print("[Cancelled]"); | |
132 _withNextExpectation((Event expect) { | |
133 if (!expect.matchCancel()) { | |
134 _fail("Expected: $expect\n" | |
135 "Found: [Cancelled]"); | |
136 } | |
137 }); | |
138 } | |
139 | 115 |
140 void _withNextExpectation(void action(Event expect)) { | 116 void _withNextExpectation(void action(Event expect)) { |
141 if (_nextExpectationIndex == _expectations.length) { | 117 if (_nextExpectationIndex == _expectations.length) { |
142 action(new MismatchEvent()); | 118 action(new MismatchEvent()); |
143 } else { | 119 } else { |
144 Event next = _expectations[_nextExpectationIndex]; | 120 Event next = _expectations[_nextExpectationIndex++]; |
145 action(next); | 121 action(next); |
146 } | 122 } |
147 _nextExpectationIndex++; | |
148 _checkDone(); | 123 _checkDone(); |
149 } | 124 } |
150 | 125 |
151 void _checkDone() { | 126 void _checkDone() { |
152 if (_nextExpectationIndex == _expectations.length) { | 127 if (_nextExpectationIndex == _expectations.length) { |
153 _onComplete(); | 128 _onComplete(); |
154 } | 129 } |
155 } | 130 } |
156 | 131 |
157 | 132 |
(...skipping 15 matching lines...) Expand all Loading... |
173 _fail("Adding expectation after completing"); | 148 _fail("Adding expectation after completing"); |
174 } | 149 } |
175 _expectations.add(new ErrorEvent(error, action)); | 150 _expectations.add(new ErrorEvent(error, action)); |
176 } | 151 } |
177 void expectDone([void action()]) { | 152 void expectDone([void action()]) { |
178 if (_onComplete == null) { | 153 if (_onComplete == null) { |
179 _fail("Adding expectation after completing"); | 154 _fail("Adding expectation after completing"); |
180 } | 155 } |
181 _expectations.add(new DoneEvent(action)); | 156 _expectations.add(new DoneEvent(action)); |
182 } | 157 } |
183 void expectPause([void action()]) { | 158 void expectPause(bool isPaused, [void action()]) { |
184 if (_onComplete == null) { | 159 if (_onComplete == null) { |
185 _fail("Adding expectation after completing"); | 160 _fail("Adding expectation after completing"); |
186 } | 161 } |
187 _expectations.add(new PauseCallbackEvent(action)); | 162 _expectations.add(new PauseCallbackEvent(isPaused, action)); |
188 } | 163 } |
189 void expectResume([void action()]) { | 164 void expectSubscription(bool hasListener, bool isPaused, [void action()]) { |
190 if (_onComplete == null) { | |
191 _fail("Adding expectation after completing"); | |
192 } | |
193 _expectations.add(new ResumeCallbackEvent(action)); | |
194 } | |
195 void expectSubscription([void action()]) { | |
196 if (_onComplete == null) { | 165 if (_onComplete == null) { |
197 _fail("Adding expectation after completing"); | 166 _fail("Adding expectation after completing"); |
198 } | 167 } |
199 _expectations.add( | 168 _expectations.add( |
200 new SubscriptionCallbackEvent(action)); | 169 new SubscriptionCallbackEvent(hasListener, isPaused, action)); |
201 } | |
202 void expectCancel([void action()]) { | |
203 if (_onComplete == null) { | |
204 _fail("Adding expectation after completing"); | |
205 } | |
206 _expectations.add( | |
207 new CancelCallbackEvent(action)); | |
208 } | 170 } |
209 | 171 |
210 void _fail(String message) { | 172 void _fail(String message) { |
211 if (_nextExpectationIndex == 0) { | 173 if (_nextExpectationIndex == 0) { |
212 throw "Unexpected event:\n$message\nNo earlier events matched."; | 174 throw "Unexpected event:\n$message\nNo earlier events matched."; |
213 } | 175 } |
214 throw "Unexpected event:\n$message\nMatched so far:\n" | 176 throw "Unexpected event:\n$message\nMatched so far:\n" |
215 " ${_expectations.take(_nextExpectationIndex).join("\n ")}"; | 177 " ${_expectations.take(_nextExpectationIndex).join("\n ")}"; |
216 } | 178 } |
217 } | 179 } |
218 | 180 |
| 181 class EventCollector { |
| 182 final Queue<Event> events = new Queue<Event>(); |
| 183 |
| 184 } |
| 185 |
219 class Event { | 186 class Event { |
220 Function _action; | 187 Function _action; |
221 Event(void this._action()); | 188 Event(void this._action()); |
222 | 189 |
223 bool matchData(var data) { | 190 bool matchData(var data) { |
224 if (!_testData(data)) return false; | 191 if (!_testData(data)) return false; |
225 if (_action != null) _action(); | 192 if (_action != null) _action(); |
226 return true; | 193 return true; |
227 } | 194 } |
228 bool matchError(e) { | 195 bool matchError(e) { |
229 if (!_testError(e)) return false; | 196 if (!_testError(e)) return false; |
230 if (_action != null) _action(); | 197 if (_action != null) _action(); |
231 return true; | 198 return true; |
232 } | 199 } |
233 bool matchDone() { | 200 bool matchDone() { |
234 if (!_testDone()) return false; | 201 if (!_testDone()) return false; |
235 if (_action != null) _action(); | 202 if (_action != null) _action(); |
236 return true; | 203 return true; |
237 } | 204 } |
238 bool matchPause() { | 205 bool matchPauseChange(StreamController c) { |
239 if (!_testPause()) return false; | 206 if (!_testPause(c)) return false; |
240 if (_action != null) _action(); | 207 if (_action != null) _action(); |
241 return true; | 208 return true; |
242 } | 209 } |
243 bool matchResume() { | 210 bool matchSubscriptionChange(StreamController c) { |
244 if (!_testResume()) return false; | 211 if (!_testSubscribe(c)) return false; |
245 if (_action != null) _action(); | 212 if (_action != null) _action(); |
246 return true; | 213 return true; |
247 } | 214 } |
248 bool matchSubscribe() { | |
249 if (!_testSubscribe()) return false; | |
250 if (_action != null) _action(); | |
251 return true; | |
252 } | |
253 bool matchCancel() { | |
254 if (!_testCancel()) return false; | |
255 if (_action != null) _action(); | |
256 return true; | |
257 } | |
258 | 215 |
259 bool _testData(_) => false; | 216 bool _testData(_) => false; |
260 bool _testError(_) => false; | 217 bool _testError(_) => false; |
261 bool _testDone() => false; | 218 bool _testDone() => false; |
262 bool _testPause() => false; | 219 bool _testPause(_) => false; |
263 bool _testResume() => false; | 220 bool _testSubscribe(_) => false; |
264 bool _testSubscribe() => false; | |
265 bool _testCancel() => false; | |
266 } | 221 } |
267 | 222 |
268 class MismatchEvent extends Event { | 223 class MismatchEvent extends Event { |
269 MismatchEvent() : super(null); | 224 MismatchEvent() : super(null); |
270 toString() => "[No event expected]"; | 225 toString() => "[No event expected]"; |
271 } | 226 } |
272 | 227 |
273 class DataEvent extends Event { | 228 class DataEvent extends Event { |
274 final data; | 229 final data; |
275 DataEvent(this.data, void action()) : super(action); | 230 DataEvent(this.data, void action()) : super(action); |
276 bool _testData(var data) => this.data == data; | 231 bool _testData(var data) => this.data == data; |
277 String toString() => "[Data: $data]"; | 232 String toString() => "[Data: $data]"; |
278 } | 233 } |
279 | 234 |
280 class ErrorEvent extends Event { | 235 class ErrorEvent extends Event { |
281 final error; | 236 final error; |
282 ErrorEvent(this.error, void action()) : super(action); | 237 ErrorEvent(this.error, void action()) : super(action); |
283 bool _testError(error) => this.error == error; | 238 bool _testError(error) => this.error == error; |
284 String toString() => "[Error: $error]"; | 239 String toString() => "[Error: $error]"; |
285 } | 240 } |
286 | 241 |
287 class DoneEvent extends Event { | 242 class DoneEvent extends Event { |
288 DoneEvent(void action()) : super(action); | 243 DoneEvent(void action()) : super(action); |
289 bool _testDone() => true; | 244 bool _testDone() => true; |
290 String toString() => "[Done]"; | 245 String toString() => "[Done]"; |
291 } | 246 } |
292 | 247 |
293 class PauseCallbackEvent extends Event { | 248 class PauseCallbackEvent extends Event { |
294 PauseCallbackEvent(void action()) : super(action); | 249 final bool isPaused; |
295 bool _testPause() => true; | 250 PauseCallbackEvent(this.isPaused, void action()) |
296 String toString() => "[Paused]"; | 251 : super(action); |
297 } | 252 bool _testPause(StreamController c) => isPaused == c.isPaused; |
298 | 253 String toString() => "[Paused:$isPaused]"; |
299 class ResumeCallbackEvent extends Event { | |
300 ResumeCallbackEvent(void action()) : super(action); | |
301 bool _testResume() => true; | |
302 String toString() => "[Resumed]"; | |
303 } | 254 } |
304 | 255 |
305 class SubscriptionCallbackEvent extends Event { | 256 class SubscriptionCallbackEvent extends Event { |
306 SubscriptionCallbackEvent(void action()) : super(action); | 257 final bool hasListener; |
307 bool _testSubscribe() => true; | 258 final bool isPaused; |
308 String toString() => "[Subscribed]"; | 259 SubscriptionCallbackEvent(this.hasListener, this.isPaused, void action()) |
309 } | 260 : super(action); |
310 | 261 bool _testSubscribe(StreamController c) { |
311 class CancelCallbackEvent extends Event { | 262 return hasListener == c.hasListener && isPaused == c.isPaused; |
312 CancelCallbackEvent(void action()) : super(action); | 263 } |
313 bool _testCancel() => true; | 264 String toString() => "[Has listener:$hasListener, Paused:$isPaused]"; |
314 String toString() => "[Cancelled]"; | |
315 } | 265 } |
316 | 266 |
317 | 267 |
318 class LogAnyEvent extends Event { | 268 class LogAnyEvent extends Event { |
319 String _actual = "*Not matched yet*"; | 269 String _actual = "*Not matched yet*"; |
320 LogAnyEvent(void action()) : super(action); | 270 LogAnyEvent(void action()) : super(action); |
321 bool _testData(var data) { | 271 bool _testData(var data) { |
322 _actual = "*[Data $data]"; | 272 _actual = "*[Data $data]"; |
323 return true; | 273 return true; |
324 } | 274 } |
325 bool _testError(error) { | 275 bool _testError(error) { |
326 _actual = "*[Error ${error}]"; | 276 _actual = "*[Error ${error}]"; |
327 return true; | 277 return true; |
328 } | 278 } |
329 bool _testDone() { | 279 bool _testDone() { |
330 _actual = "*[Done]"; | 280 _actual = "*[Done]"; |
331 return true; | 281 return true; |
332 } | 282 } |
333 bool _testPause() { | 283 bool _testPause(StreamController c) { |
334 _actual = "*[Paused]"; | 284 _actual = "*[Paused:${c.isPaused}]"; |
335 return true; | 285 return true; |
336 } | 286 } |
337 bool _testResume() { | 287 bool _testSubcribe(StreamController c) { |
338 _actual = "*[Resumed]"; | 288 _actual = "*[Has listener:${c.hasListener}, Paused:${c.isPaused}]"; |
339 return true; | |
340 } | |
341 bool _testSubcribe() { | |
342 _actual = "*[Subscribed]"; | |
343 return true; | |
344 } | |
345 bool _testCancel() { | |
346 _actual = "*[Cancelled]"; | |
347 return true; | 289 return true; |
348 } | 290 } |
349 | 291 |
350 String toString() => _actual; | 292 String toString() => _actual; |
351 } | 293 } |
OLD | NEW |