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