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