OLD | NEW |
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 error_group_test; | 1 library error_group_test; |
6 | |
7 import 'dart:async'; | 2 import 'dart:async'; |
8 | |
9 import 'package:unittest/unittest.dart'; | 3 import 'package:unittest/unittest.dart'; |
10 | |
11 import '../lib/src/error_group.dart'; | 4 import '../lib/src/error_group.dart'; |
12 import '../lib/src/utils.dart'; | 5 import '../lib/src/utils.dart'; |
13 | |
14 ErrorGroup errorGroup; | 6 ErrorGroup errorGroup; |
15 | |
16 // TODO(nweiz): once there's a global error handler, we should test that it does | |
17 // and does not get called at appropriate times. See issue 5958. | |
18 // | |
19 // One particular thing we should test that has no tests now is that a stream | |
20 // that has a subscription added and subsequently canceled counts as having no | |
21 // listeners. | |
22 | |
23 main() { | 7 main() { |
24 group('with no futures or streams', () { | 8 group('with no futures or streams', () { |
25 setUp(() { | 9 setUp(() { |
26 errorGroup = new ErrorGroup(); | 10 errorGroup = new ErrorGroup(); |
27 }); | 11 }); |
28 | |
29 test('should pass signaled errors to .done', () { | 12 test('should pass signaled errors to .done', () { |
30 expect(errorGroup.done, throwsFormatException); | 13 expect(errorGroup.done, throwsFormatException); |
31 errorGroup.signalError(new FormatException()); | 14 errorGroup.signalError(new FormatException()); |
32 }); | 15 }); |
33 | 16 test( |
34 test("shouldn't allow additional futures or streams once an error has been " | 17 "shouldn't allow additional futures or streams once an error has been " |
35 "signaled", () { | 18 "signaled", |
| 19 () { |
36 expect(errorGroup.done, throwsFormatException); | 20 expect(errorGroup.done, throwsFormatException); |
37 errorGroup.signalError(new FormatException()); | 21 errorGroup.signalError(new FormatException()); |
38 | 22 expect( |
39 expect(() => errorGroup.registerFuture(new Future.value()), | 23 () => errorGroup.registerFuture(new Future.value()), |
40 throwsStateError); | 24 throwsStateError); |
41 expect(() => errorGroup.registerStream( | 25 expect( |
42 new StreamController(sync: true).stream), | 26 () => errorGroup.registerStream(new StreamController(sync: true).strea
m), |
43 throwsStateError); | 27 throwsStateError); |
44 }); | 28 }); |
45 }); | 29 }); |
46 | |
47 group('with a single future', () { | 30 group('with a single future', () { |
48 Completer completer; | 31 Completer completer; |
49 Future future; | 32 Future future; |
50 | |
51 setUp(() { | 33 setUp(() { |
52 errorGroup = new ErrorGroup(); | 34 errorGroup = new ErrorGroup(); |
53 completer = new Completer(); | 35 completer = new Completer(); |
54 future = errorGroup.registerFuture(completer.future); | 36 future = errorGroup.registerFuture(completer.future); |
55 }); | 37 }); |
56 | |
57 test('should pass through a value from the future', () { | 38 test('should pass through a value from the future', () { |
58 expect(future, completion(equals('value'))); | 39 expect(future, completion(equals('value'))); |
59 expect(errorGroup.done, completes); | 40 expect(errorGroup.done, completes); |
60 completer.complete('value'); | 41 completer.complete('value'); |
61 }); | 42 }); |
62 | 43 test( |
63 test("shouldn't allow additional futures or streams once .done has " | 44 "shouldn't allow additional futures or streams once .done has " "been ca
lled", |
64 "been called", () { | 45 () { |
65 completer.complete('value'); | 46 completer.complete('value'); |
66 | 47 expect( |
67 expect(completer.future | 48 completer.future.then((_) => errorGroup.registerFuture(new Future.valu
e())), |
68 .then((_) => errorGroup.registerFuture(new Future.value())), | 49 throwsStateError); |
69 throwsStateError); | 50 expect( |
70 expect(completer.future | 51 completer.future.then( |
71 .then((_) => errorGroup.registerStream( | 52 (_) => errorGroup.registerStream(new StreamController(sync: true).
stream)), |
72 new StreamController(sync: true).stream)), | 53 throwsStateError); |
73 throwsStateError); | |
74 }); | 54 }); |
75 | 55 test( |
76 test('should pass through an exception from the future if it has a ' | 56 'should pass through an exception from the future if it has a ' 'listene
r', |
77 'listener', () { | 57 () { |
78 expect(future, throwsFormatException); | 58 expect(future, throwsFormatException); |
79 // errorGroup shouldn't top-level the exception | |
80 completer.completeError(new FormatException()); | 59 completer.completeError(new FormatException()); |
81 }); | 60 }); |
82 | 61 test( |
83 test('should notify the error group of an exception from the future even ' | 62 'should notify the error group of an exception from the future even ' |
84 'if it has a listener', () { | 63 'if it has a listener', |
| 64 () { |
85 expect(future, throwsFormatException); | 65 expect(future, throwsFormatException); |
86 expect(errorGroup.done, throwsFormatException); | 66 expect(errorGroup.done, throwsFormatException); |
87 completer.completeError(new FormatException()); | 67 completer.completeError(new FormatException()); |
88 }); | 68 }); |
89 | 69 test( |
90 test('should pass a signaled exception to the future if it has a listener ' | 70 'should pass a signaled exception to the future if it has a listener ' |
91 'and should ignore a subsequent value from that future', () { | 71 'and should ignore a subsequent value from that future', |
| 72 () { |
92 expect(future, throwsFormatException); | 73 expect(future, throwsFormatException); |
93 // errorGroup shouldn't top-level the exception | |
94 errorGroup.signalError(new FormatException()); | 74 errorGroup.signalError(new FormatException()); |
95 completer.complete('value'); | 75 completer.complete('value'); |
96 }); | 76 }); |
97 | 77 test( |
98 test('should pass a signaled exception to the future if it has a listener ' | 78 'should pass a signaled exception to the future if it has a listener ' |
99 'and should ignore a subsequent exception from that future', () { | 79 'and should ignore a subsequent exception from that future', |
| 80 () { |
100 expect(future, throwsFormatException); | 81 expect(future, throwsFormatException); |
101 // errorGroup shouldn't top-level the exception | |
102 errorGroup.signalError(new FormatException()); | 82 errorGroup.signalError(new FormatException()); |
103 completer.completeError(new ArgumentError()); | 83 completer.completeError(new ArgumentError()); |
104 }); | 84 }); |
105 | 85 test( |
106 test('should notify the error group of a signaled exception even if the ' | 86 'should notify the error group of a signaled exception even if the ' |
107 'future has a listener', () { | 87 'future has a listener', |
| 88 () { |
108 expect(future, throwsFormatException); | 89 expect(future, throwsFormatException); |
109 expect(errorGroup.done, throwsFormatException); | 90 expect(errorGroup.done, throwsFormatException); |
110 errorGroup.signalError(new FormatException()); | 91 errorGroup.signalError(new FormatException()); |
111 }); | 92 }); |
112 | 93 test( |
113 test("should complete .done if the future receives a value even if the " | 94 "should complete .done if the future receives a value even if the " |
114 "future doesn't have a listener", () { | 95 "future doesn't have a listener", |
| 96 () { |
115 expect(errorGroup.done, completes); | 97 expect(errorGroup.done, completes); |
116 completer.complete('value'); | 98 completer.complete('value'); |
117 | 99 expect(errorGroup.done.then((_) => future), completion(equals('value'))); |
118 // A listener added afterwards should receive the value | |
119 expect(errorGroup.done.then((_) => future), | |
120 completion(equals('value'))); | |
121 }); | 100 }); |
122 | 101 test( |
123 test("should pipe an exception from the future to .done if the future " | 102 "should pipe an exception from the future to .done if the future " |
124 "doesn't have a listener", () { | 103 "doesn't have a listener", |
| 104 () { |
125 expect(errorGroup.done, throwsFormatException); | 105 expect(errorGroup.done, throwsFormatException); |
126 completer.completeError(new FormatException()); | 106 completer.completeError(new FormatException()); |
127 | |
128 // A listener added afterwards should receive the exception | |
129 expect(errorGroup.done.catchError((_) { | 107 expect(errorGroup.done.catchError((_) { |
130 expect(future, throwsFormatException); | 108 expect(future, throwsFormatException); |
131 }), completes); | 109 }), completes); |
132 }); | 110 }); |
133 | 111 test( |
134 test("should pass a signaled exception to .done if the future doesn't have " | 112 "should pass a signaled exception to .done if the future doesn't have " |
135 "a listener", | 113 "a listener", |
136 () { | 114 () { |
137 expect(errorGroup.done, throwsFormatException); | 115 expect(errorGroup.done, throwsFormatException); |
138 errorGroup.signalError(new FormatException()); | 116 errorGroup.signalError(new FormatException()); |
139 | |
140 // A listener added afterwards should receive the exception | |
141 expect(errorGroup.done.catchError((_) { | 117 expect(errorGroup.done.catchError((_) { |
142 completer.complete('value'); // should be ignored | 118 completer.complete('value'); |
143 expect(future, throwsFormatException); | 119 expect(future, throwsFormatException); |
144 }), completes); | 120 }), completes); |
145 }); | 121 }); |
146 }); | 122 }); |
147 | |
148 group('with multiple futures', () { | 123 group('with multiple futures', () { |
149 Completer completer1; | 124 Completer completer1; |
150 Completer completer2; | 125 Completer completer2; |
151 Future future1; | 126 Future future1; |
152 Future future2; | 127 Future future2; |
153 | |
154 setUp(() { | 128 setUp(() { |
155 errorGroup = new ErrorGroup(); | 129 errorGroup = new ErrorGroup(); |
156 completer1 = new Completer(); | 130 completer1 = new Completer(); |
157 completer2 = new Completer(); | 131 completer2 = new Completer(); |
158 future1 = errorGroup.registerFuture(completer1.future); | 132 future1 = errorGroup.registerFuture(completer1.future); |
159 future2 = errorGroup.registerFuture(completer2.future); | 133 future2 = errorGroup.registerFuture(completer2.future); |
160 }); | 134 }); |
161 | 135 test( |
162 test("should pipe exceptions from one future to the other and to " | 136 "should pipe exceptions from one future to the other and to " ".complete
", |
163 ".complete", () { | 137 () { |
164 expect(future1, throwsFormatException); | 138 expect(future1, throwsFormatException); |
165 expect(future2, throwsFormatException); | 139 expect(future2, throwsFormatException); |
166 expect(errorGroup.done, throwsFormatException); | 140 expect(errorGroup.done, throwsFormatException); |
167 | |
168 completer1.completeError(new FormatException()); | 141 completer1.completeError(new FormatException()); |
169 }); | 142 }); |
170 | 143 test( |
171 test("each future should be able to complete with a value " | 144 "each future should be able to complete with a value " "independently", |
172 "independently", () { | 145 () { |
173 expect(future1, completion(equals('value1'))); | 146 expect(future1, completion(equals('value1'))); |
174 expect(future2, completion(equals('value2'))); | 147 expect(future2, completion(equals('value2'))); |
175 expect(errorGroup.done, completes); | 148 expect(errorGroup.done, completes); |
176 | |
177 completer1.complete('value1'); | 149 completer1.complete('value1'); |
178 completer2.complete('value2'); | 150 completer2.complete('value2'); |
179 }); | 151 }); |
180 | 152 test( |
181 test("shouldn't throw a top-level exception if a future receives an error " | 153 "shouldn't throw a top-level exception if a future receives an error " |
182 "after the other listened future completes", () { | 154 "after the other listened future completes", |
| 155 () { |
183 expect(future1, completion(equals('value'))); | 156 expect(future1, completion(equals('value'))); |
184 completer1.complete('value'); | 157 completer1.complete('value'); |
185 | |
186 expect(future1.then((_) { | 158 expect(future1.then((_) { |
187 // shouldn't cause a top-level exception | |
188 completer2.completeError(new FormatException()); | 159 completer2.completeError(new FormatException()); |
189 }), completes); | 160 }), completes); |
190 }); | 161 }); |
191 | 162 test( |
192 test("shouldn't throw a top-level exception if an error is signaled after " | 163 "shouldn't throw a top-level exception if an error is signaled after " |
193 "one listened future completes", () { | 164 "one listened future completes", |
| 165 () { |
194 expect(future1, completion(equals('value'))); | 166 expect(future1, completion(equals('value'))); |
195 completer1.complete('value'); | 167 completer1.complete('value'); |
196 | |
197 expect(future1.then((_) { | 168 expect(future1.then((_) { |
198 // shouldn't cause a top-level exception | |
199 errorGroup.signalError(new FormatException()); | 169 errorGroup.signalError(new FormatException()); |
200 }), completes); | 170 }), completes); |
201 }); | 171 }); |
202 }); | 172 }); |
203 | |
204 group('with a single stream', () { | 173 group('with a single stream', () { |
205 StreamController controller; | 174 StreamController controller; |
206 Stream stream; | 175 Stream stream; |
207 | |
208 setUp(() { | 176 setUp(() { |
209 errorGroup = new ErrorGroup(); | 177 errorGroup = new ErrorGroup(); |
210 controller = new StreamController.broadcast(sync: true); | 178 controller = new StreamController.broadcast(sync: true); |
211 stream = errorGroup.registerStream(controller.stream); | 179 stream = errorGroup.registerStream(controller.stream); |
212 }); | 180 }); |
213 | |
214 test('should pass through values from the stream', () { | 181 test('should pass through values from the stream', () { |
215 StreamIterator iter = new StreamIterator(stream); | 182 StreamIterator iter = new StreamIterator(stream); |
216 iter.moveNext().then((hasNext) { | 183 iter.moveNext().then((hasNext) { |
217 expect(hasNext, isTrue); | 184 expect(hasNext, isTrue); |
218 expect(iter.current, equals(1)); | 185 expect(iter.current, equals(1)); |
219 iter.moveNext().then((hasNext) { | 186 iter.moveNext().then((hasNext) { |
220 expect(hasNext, isTrue); | 187 expect(hasNext, isTrue); |
221 expect(iter.current, equals(2)); | 188 expect(iter.current, equals(2)); |
222 expect(iter.moveNext(), completion(isFalse)); | 189 expect(iter.moveNext(), completion(isFalse)); |
223 }); | 190 }); |
224 }); | 191 }); |
225 expect(errorGroup.done, completes); | 192 expect(errorGroup.done, completes); |
226 | 193 controller |
227 controller..add(1)..add(2)..close(); | 194 ..add(1) |
| 195 ..add(2) |
| 196 ..close(); |
228 }); | 197 }); |
229 | 198 test( |
230 test('should pass through an error from the stream if it has a ' | 199 'should pass through an error from the stream if it has a ' 'listener', |
231 'listener', () { | 200 () { |
232 expect(stream.first, throwsFormatException); | 201 expect(stream.first, throwsFormatException); |
233 // errorGroup shouldn't top-level the exception | |
234 controller.addError(new FormatException()); | 202 controller.addError(new FormatException()); |
235 }); | 203 }); |
236 | 204 test( |
237 test('should notify the error group of an exception from the stream even ' | 205 'should notify the error group of an exception from the stream even ' |
238 'if it has a listener', () { | 206 'if it has a listener', |
| 207 () { |
239 expect(stream.first, throwsFormatException); | 208 expect(stream.first, throwsFormatException); |
240 expect(errorGroup.done, throwsFormatException); | 209 expect(errorGroup.done, throwsFormatException); |
241 controller.addError(new FormatException()); | 210 controller.addError(new FormatException()); |
242 }); | 211 }); |
243 | 212 test( |
244 test('should pass a signaled exception to the stream if it has a listener ' | 213 'should pass a signaled exception to the stream if it has a listener ' |
245 'and should unsubscribe that stream', () { | 214 'and should unsubscribe that stream', |
246 // errorGroup shouldn't top-level the exception | 215 () { |
247 expect(stream.first, throwsFormatException); | 216 expect(stream.first, throwsFormatException); |
248 errorGroup.signalError(new FormatException()); | 217 errorGroup.signalError(new FormatException()); |
249 | |
250 expect(newFuture(() { | 218 expect(newFuture(() { |
251 controller.add('value'); | 219 controller.add('value'); |
252 }), completes); | 220 }), completes); |
253 }); | 221 }); |
254 | 222 test( |
255 test('should notify the error group of a signaled exception even if the ' | 223 'should notify the error group of a signaled exception even if the ' |
256 'stream has a listener', () { | 224 'stream has a listener', |
| 225 () { |
257 expect(stream.first, throwsFormatException); | 226 expect(stream.first, throwsFormatException); |
258 expect(errorGroup.done, throwsFormatException); | 227 expect(errorGroup.done, throwsFormatException); |
259 errorGroup.signalError(new FormatException()); | 228 errorGroup.signalError(new FormatException()); |
260 }); | 229 }); |
261 | 230 test( |
262 test("should see one value and complete .done when the stream is done even " | 231 "should see one value and complete .done when the stream is done even " |
263 "if the stream doesn't have a listener", () { | 232 "if the stream doesn't have a listener", |
| 233 () { |
264 expect(errorGroup.done, completes); | 234 expect(errorGroup.done, completes); |
265 controller.add('value'); | 235 controller.add('value'); |
266 controller.close(); | 236 controller.close(); |
267 | 237 expect( |
268 // Now that broadcast controllers have been removed a listener should | 238 errorGroup.done.then((_) => stream.toList()), |
269 // see the value that has been put into the controller. | |
270 expect(errorGroup.done.then((_) => stream.toList()), | |
271 completion(equals(['value']))); | 239 completion(equals(['value']))); |
272 }); | 240 }); |
273 | |
274 }); | 241 }); |
275 | |
276 group('with a single single-subscription stream', () { | 242 group('with a single single-subscription stream', () { |
277 StreamController controller; | 243 StreamController controller; |
278 Stream stream; | 244 Stream stream; |
279 | |
280 setUp(() { | 245 setUp(() { |
281 errorGroup = new ErrorGroup(); | 246 errorGroup = new ErrorGroup(); |
282 controller = new StreamController(sync: true); | 247 controller = new StreamController(sync: true); |
283 stream = errorGroup.registerStream(controller.stream); | 248 stream = errorGroup.registerStream(controller.stream); |
284 }); | 249 }); |
285 | 250 test( |
286 test("should complete .done when the stream is done even if the stream " | 251 "should complete .done when the stream is done even if the stream " |
287 "doesn't have a listener", () { | 252 "doesn't have a listener", |
| 253 () { |
288 expect(errorGroup.done, completes); | 254 expect(errorGroup.done, completes); |
289 controller.add('value'); | 255 controller.add('value'); |
290 controller.close(); | 256 controller.close(); |
291 | 257 expect( |
292 // A listener added afterwards should receive the value | 258 errorGroup.done.then((_) => stream.toList()), |
293 expect(errorGroup.done.then((_) => stream.toList()), | |
294 completion(equals(['value']))); | 259 completion(equals(['value']))); |
295 }); | 260 }); |
296 | 261 test( |
297 test("should pipe an exception from the stream to .done if the stream " | 262 "should pipe an exception from the stream to .done if the stream " |
298 "doesn't have a listener", () { | 263 "doesn't have a listener", |
| 264 () { |
299 expect(errorGroup.done, throwsFormatException); | 265 expect(errorGroup.done, throwsFormatException); |
300 controller.addError(new FormatException()); | 266 controller.addError(new FormatException()); |
301 | |
302 // A listener added afterwards should receive the exception | |
303 expect(errorGroup.done.catchError((_) { | 267 expect(errorGroup.done.catchError((_) { |
304 controller.add('value'); // should be ignored | 268 controller.add('value'); |
305 expect(stream.first, throwsFormatException); | 269 expect(stream.first, throwsFormatException); |
306 }), completes); | 270 }), completes); |
307 }); | 271 }); |
308 | 272 test( |
309 test("should pass a signaled exception to .done if the stream doesn't " | 273 "should pass a signaled exception to .done if the stream doesn't " |
310 "have a listener", | 274 "have a listener", |
311 () { | 275 () { |
312 expect(errorGroup.done, throwsFormatException); | 276 expect(errorGroup.done, throwsFormatException); |
313 errorGroup.signalError(new FormatException()); | 277 errorGroup.signalError(new FormatException()); |
314 | |
315 // A listener added afterwards should receive the exception | |
316 expect(errorGroup.done.catchError((_) { | 278 expect(errorGroup.done.catchError((_) { |
317 controller.add('value'); // should be ignored | 279 controller.add('value'); |
318 expect(stream.first, throwsFormatException); | 280 expect(stream.first, throwsFormatException); |
319 }), completes); | 281 }), completes); |
320 }); | 282 }); |
321 }); | 283 }); |
322 | |
323 group('with multiple streams', () { | 284 group('with multiple streams', () { |
324 StreamController controller1; | 285 StreamController controller1; |
325 StreamController controller2; | 286 StreamController controller2; |
326 Stream stream1; | 287 Stream stream1; |
327 Stream stream2; | 288 Stream stream2; |
328 | |
329 setUp(() { | 289 setUp(() { |
330 errorGroup = new ErrorGroup(); | 290 errorGroup = new ErrorGroup(); |
331 controller1 = new StreamController.broadcast(sync: true); | 291 controller1 = new StreamController.broadcast(sync: true); |
332 controller2 = new StreamController.broadcast(sync: true); | 292 controller2 = new StreamController.broadcast(sync: true); |
333 stream1 = errorGroup.registerStream(controller1.stream); | 293 stream1 = errorGroup.registerStream(controller1.stream); |
334 stream2 = errorGroup.registerStream(controller2.stream); | 294 stream2 = errorGroup.registerStream(controller2.stream); |
335 }); | 295 }); |
336 | 296 test( |
337 test("should pipe exceptions from one stream to the other and to .done", | 297 "should pipe exceptions from one stream to the other and to .done", |
338 () { | 298 () { |
339 expect(stream1.first, throwsFormatException); | 299 expect(stream1.first, throwsFormatException); |
340 expect(stream2.first, throwsFormatException); | 300 expect(stream2.first, throwsFormatException); |
341 expect(errorGroup.done, throwsFormatException); | 301 expect(errorGroup.done, throwsFormatException); |
342 | |
343 controller1.addError(new FormatException()); | 302 controller1.addError(new FormatException()); |
344 }); | 303 }); |
345 | |
346 test("each future should be able to emit values independently", () { | 304 test("each future should be able to emit values independently", () { |
347 expect(stream1.toList(), completion(equals(['value1.1', 'value1.2']))); | 305 expect(stream1.toList(), completion(equals(['value1.1', 'value1.2']))); |
348 expect(stream2.toList(), completion(equals(['value2.1', 'value2.2']))); | 306 expect(stream2.toList(), completion(equals(['value2.1', 'value2.2']))); |
349 expect(errorGroup.done, completes); | 307 expect(errorGroup.done, completes); |
350 | 308 controller1 |
351 controller1..add('value1.1')..add('value1.2')..close(); | 309 ..add('value1.1') |
352 controller2..add('value2.1')..add('value2.2')..close(); | 310 ..add('value1.2') |
| 311 ..close(); |
| 312 controller2 |
| 313 ..add('value2.1') |
| 314 ..add('value2.2') |
| 315 ..close(); |
353 }); | 316 }); |
354 | 317 test( |
355 test("shouldn't throw a top-level exception if a stream receives an error " | 318 "shouldn't throw a top-level exception if a stream receives an error " |
356 "after the other listened stream completes", () { | 319 "after the other listened stream completes", |
| 320 () { |
357 var signal = new Completer(); | 321 var signal = new Completer(); |
358 expect(stream1.toList().whenComplete(signal.complete), | 322 expect( |
359 completion(equals(['value1', 'value2']))); | 323 stream1.toList().whenComplete(signal.complete), |
360 controller1..add('value1')..add('value2')..close(); | 324 completion(equals(['value1', 'value2']))); |
361 | 325 controller1 |
| 326 ..add('value1') |
| 327 ..add('value2') |
| 328 ..close(); |
362 expect(signal.future.then((_) { | 329 expect(signal.future.then((_) { |
363 // shouldn't cause a top-level exception | |
364 controller2.addError(new FormatException()); | 330 controller2.addError(new FormatException()); |
365 }), completes); | 331 }), completes); |
366 }); | 332 }); |
367 | 333 test( |
368 test("shouldn't throw a top-level exception if an error is signaled after " | 334 "shouldn't throw a top-level exception if an error is signaled after " |
369 "one listened stream completes", () { | 335 "one listened stream completes", |
| 336 () { |
370 var signal = new Completer(); | 337 var signal = new Completer(); |
371 expect(stream1.toList().whenComplete(signal.complete), | 338 expect( |
372 completion(equals(['value1', 'value2']))); | 339 stream1.toList().whenComplete(signal.complete), |
373 controller1..add('value1')..add('value2')..close(); | 340 completion(equals(['value1', 'value2']))); |
374 | 341 controller1 |
| 342 ..add('value1') |
| 343 ..add('value2') |
| 344 ..close(); |
375 expect(signal.future.then((_) { | 345 expect(signal.future.then((_) { |
376 // shouldn't cause a top-level exception | |
377 errorGroup.signalError(new FormatException()); | 346 errorGroup.signalError(new FormatException()); |
378 }), completes); | 347 }), completes); |
379 }); | 348 }); |
380 }); | 349 }); |
381 | |
382 group('with a stream and a future', () { | 350 group('with a stream and a future', () { |
383 StreamController controller; | 351 StreamController controller; |
384 Stream stream; | 352 Stream stream; |
385 Completer completer; | 353 Completer completer; |
386 Future future; | 354 Future future; |
387 | |
388 setUp(() { | 355 setUp(() { |
389 errorGroup = new ErrorGroup(); | 356 errorGroup = new ErrorGroup(); |
390 controller = new StreamController.broadcast(sync: true); | 357 controller = new StreamController.broadcast(sync: true); |
391 stream = errorGroup.registerStream(controller.stream); | 358 stream = errorGroup.registerStream(controller.stream); |
392 completer = new Completer(); | 359 completer = new Completer(); |
393 future = errorGroup.registerFuture(completer.future); | 360 future = errorGroup.registerFuture(completer.future); |
394 }); | 361 }); |
395 | |
396 test("should pipe exceptions from the stream to the future", () { | 362 test("should pipe exceptions from the stream to the future", () { |
397 expect(stream.first, throwsFormatException); | 363 expect(stream.first, throwsFormatException); |
398 expect(future, throwsFormatException); | 364 expect(future, throwsFormatException); |
399 expect(errorGroup.done, throwsFormatException); | 365 expect(errorGroup.done, throwsFormatException); |
400 | |
401 controller.addError(new FormatException()); | 366 controller.addError(new FormatException()); |
402 }); | 367 }); |
403 | |
404 test("should pipe exceptions from the future to the stream", () { | 368 test("should pipe exceptions from the future to the stream", () { |
405 expect(stream.first, throwsFormatException); | 369 expect(stream.first, throwsFormatException); |
406 expect(future, throwsFormatException); | 370 expect(future, throwsFormatException); |
407 expect(errorGroup.done, throwsFormatException); | 371 expect(errorGroup.done, throwsFormatException); |
408 | |
409 completer.completeError(new FormatException()); | 372 completer.completeError(new FormatException()); |
410 }); | 373 }); |
411 | 374 test( |
412 test("the stream and the future should be able to complete/emit values " | 375 "the stream and the future should be able to complete/emit values " |
413 "independently", () { | 376 "independently", |
| 377 () { |
414 expect(stream.toList(), completion(equals(['value1.1', 'value1.2']))); | 378 expect(stream.toList(), completion(equals(['value1.1', 'value1.2']))); |
415 expect(future, completion(equals('value2.0'))); | 379 expect(future, completion(equals('value2.0'))); |
416 expect(errorGroup.done, completes); | 380 expect(errorGroup.done, completes); |
417 | 381 controller |
418 controller..add('value1.1')..add('value1.2')..close(); | 382 ..add('value1.1') |
| 383 ..add('value1.2') |
| 384 ..close(); |
419 completer.complete('value2.0'); | 385 completer.complete('value2.0'); |
420 }); | 386 }); |
421 | 387 test( |
422 test("shouldn't throw a top-level exception if the stream receives an error
" | 388 "shouldn't throw a top-level exception if the stream receives an error " |
423 "after the listened future completes", () { | 389 "after the listened future completes", |
| 390 () { |
424 expect(future, completion(equals('value'))); | 391 expect(future, completion(equals('value'))); |
425 completer.complete('value'); | 392 completer.complete('value'); |
426 | |
427 expect(future.then((_) { | 393 expect(future.then((_) { |
428 // shouldn't cause a top-level exception | |
429 controller.addError(new FormatException()); | 394 controller.addError(new FormatException()); |
430 }), completes); | 395 }), completes); |
431 }); | 396 }); |
432 | 397 test( |
433 test("shouldn't throw a top-level exception if the future receives an " | 398 "shouldn't throw a top-level exception if the future receives an " |
434 "error after the listened stream completes", () { | 399 "error after the listened stream completes", |
| 400 () { |
435 var signal = new Completer(); | 401 var signal = new Completer(); |
436 expect(stream.toList().whenComplete(signal.complete), | 402 expect( |
437 completion(equals(['value1', 'value2']))); | 403 stream.toList().whenComplete(signal.complete), |
438 controller..add('value1')..add('value2')..close(); | 404 completion(equals(['value1', 'value2']))); |
439 | 405 controller |
| 406 ..add('value1') |
| 407 ..add('value2') |
| 408 ..close(); |
440 expect(signal.future.then((_) { | 409 expect(signal.future.then((_) { |
441 // shouldn't cause a top-level exception | |
442 completer.completeError(new FormatException()); | 410 completer.completeError(new FormatException()); |
443 }), completes); | 411 }), completes); |
444 }); | 412 }); |
445 }); | 413 }); |
446 } | 414 } |
OLD | NEW |