OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, 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 future_test; | |
6 | |
7 import 'package:async_helper/async_helper.dart'; | |
8 import "package:expect/expect.dart"; | |
9 import 'dart:async'; | |
10 | |
11 const Duration MS = const Duration(milliseconds: 1); | |
12 | |
13 void testValue() { | |
14 final future = new Future<String>.value("42"); | |
15 asyncStart(); | |
16 future.then((x) { | |
17 Expect.equals("42", x); | |
18 asyncEnd(); | |
19 }); | |
20 } | |
21 | |
22 void testSync() { | |
23 compare(func) { | |
24 // Compare the results of the following two futures. | |
25 Future f1 = new Future.sync(func); | |
26 Future f2 = new Future.value().then((_) => func()); | |
27 f2.catchError((_) {}); // I'll get the error later. | |
28 f1.then((v1) { | |
29 f2.then((v2) { | |
30 Expect.equals(v1, v2); | |
31 }); | |
32 }, onError: (e1) { | |
33 f2.then((_) { | |
34 Expect.fail("Expected error"); | |
35 }, onError: (e2) { | |
36 Expect.equals(e1, e2); | |
37 }); | |
38 }); | |
39 } | |
40 | |
41 Future val = new Future.value(42); | |
42 Future err1 = new Future.error("Error")..catchError((_) {}); | |
43 try { | |
44 throw new List(0); | |
45 } catch (e, st) { | |
46 Future err2 = new Future.error(e, st)..catchError((_) {}); | |
47 } | |
48 compare(() => 42); | |
49 compare(() => val); | |
50 compare(() { | |
51 throw "Flif"; | |
52 }); | |
53 compare(() => err1); | |
54 bool hasExecuted = false; | |
55 compare(() { | |
56 hasExecuted = true; | |
57 return 499; | |
58 }); | |
59 Expect.isTrue(hasExecuted); | |
60 } | |
61 | |
62 void testNeverComplete() { | |
63 final completer = new Completer<int>(); | |
64 final future = completer.future; | |
65 future.then((v) => Expect.fail("Value not expected")); | |
66 future.catchError((e) => Expect.fail("Value not expected")); | |
67 } | |
68 | |
69 void testComplete() { | |
70 final completer = new Completer<int>(); | |
71 final future = completer.future; | |
72 Expect.isFalse(completer.isCompleted); | |
73 | |
74 completer.complete(3); | |
75 Expect.isTrue(completer.isCompleted); | |
76 | |
77 future.then((v) => Expect.equals(3, v)); | |
78 } | |
79 | |
80 // Tests for [then] | |
81 | |
82 void testCompleteWithSuccessHandlerBeforeComplete() { | |
83 final completer = new Completer<int>(); | |
84 final future = completer.future; | |
85 | |
86 int after; | |
87 | |
88 asyncStart(); | |
89 future.then((int v) { | |
90 after = v; | |
91 }).then((_) { | |
92 Expect.equals(3, after); | |
93 asyncEnd(); | |
94 }); | |
95 | |
96 completer.complete(3); | |
97 Expect.isNull(after); | |
98 } | |
99 | |
100 void testCompleteWithSuccessHandlerAfterComplete() { | |
101 final completer = new Completer<int>(); | |
102 final future = completer.future; | |
103 | |
104 int after; | |
105 completer.complete(3); | |
106 Expect.isNull(after); | |
107 | |
108 asyncStart(); | |
109 future.then((int v) { | |
110 after = v; | |
111 }).then((_) { | |
112 Expect.equals(3, after); | |
113 asyncEnd(); | |
114 }); | |
115 } | |
116 | |
117 void testCompleteManySuccessHandlers() { | |
118 final completer = new Completer<int>(); | |
119 final future = completer.future; | |
120 int before; | |
121 int after1; | |
122 int after2; | |
123 | |
124 var futures = []; | |
125 futures.add(future.then((int v) { | |
126 before = v; | |
127 })); | |
128 completer.complete(3); | |
129 futures.add(future.then((int v) { | |
130 after1 = v; | |
131 })); | |
132 futures.add(future.then((int v) { | |
133 after2 = v; | |
134 })); | |
135 | |
136 asyncStart(); | |
137 Future.wait(futures).then((_) { | |
138 Expect.equals(3, before); | |
139 Expect.equals(3, after1); | |
140 Expect.equals(3, after2); | |
141 asyncEnd(); | |
142 }); | |
143 } | |
144 | |
145 // Tests for [catchError] | |
146 | |
147 void testException() { | |
148 final completer = new Completer<int>(); | |
149 final future = completer.future; | |
150 final ex = new Exception(); | |
151 | |
152 asyncStart(); | |
153 future.then((v) { | |
154 throw "Value not expected"; | |
155 }).catchError((error) { | |
156 Expect.equals(error, ex); | |
157 asyncEnd(); | |
158 }, test: (e) => e == ex); | |
159 completer.completeError(ex); | |
160 } | |
161 | |
162 void testExceptionHandler() { | |
163 final completer = new Completer<int>(); | |
164 final future = completer.future; | |
165 final ex = new Exception(); | |
166 | |
167 var ex2; | |
168 var done = future.catchError((error) { | |
169 ex2 = error; | |
170 }); | |
171 | |
172 Expect.isFalse(completer.isCompleted); | |
173 completer.completeError(ex); | |
174 Expect.isTrue(completer.isCompleted); | |
175 | |
176 asyncStart(); | |
177 done.then((_) { | |
178 Expect.equals(ex, ex2); | |
179 asyncEnd(); | |
180 }); | |
181 } | |
182 | |
183 void testExceptionHandlerReturnsTrue() { | |
184 final completer = new Completer<int>(); | |
185 final future = completer.future; | |
186 final ex = new Exception(); | |
187 | |
188 bool reached = false; | |
189 future.catchError((e) {}); | |
190 future.catchError((e) { | |
191 reached = true; | |
192 }, test: (e) => false).catchError((e) {}); | |
193 Expect.isFalse(completer.isCompleted); | |
194 completer.completeError(ex); | |
195 Expect.isTrue(completer.isCompleted); | |
196 Expect.isFalse(reached); | |
197 } | |
198 | |
199 void testExceptionHandlerReturnsTrue2() { | |
200 final completer = new Completer<int>(); | |
201 final future = completer.future; | |
202 final ex = new Exception(); | |
203 | |
204 bool reached = false; | |
205 var done = future.catchError((e) {}, test: (e) => false).catchError((e) { | |
206 reached = true; | |
207 }); | |
208 completer.completeError(ex); | |
209 | |
210 asyncStart(); | |
211 done.then((_) { | |
212 Expect.isTrue(reached); | |
213 asyncEnd(); | |
214 }); | |
215 } | |
216 | |
217 void testExceptionHandlerReturnsFalse() { | |
218 final completer = new Completer<int>(); | |
219 final future = completer.future; | |
220 final ex = new Exception(); | |
221 | |
222 bool reached = false; | |
223 | |
224 future.catchError((e) {}); | |
225 | |
226 future.catchError((e) { | |
227 reached = true; | |
228 }, test: (e) => false).catchError((e) {}); | |
229 | |
230 completer.completeError(ex); | |
231 | |
232 Expect.isFalse(reached); | |
233 } | |
234 | |
235 void testFutureAsStreamCompleteAfter() { | |
236 var completer = new Completer(); | |
237 bool gotValue = false; | |
238 asyncStart(); | |
239 completer.future.asStream().listen((data) { | |
240 Expect.isFalse(gotValue); | |
241 gotValue = true; | |
242 Expect.equals("value", data); | |
243 }, onDone: () { | |
244 Expect.isTrue(gotValue); | |
245 asyncEnd(); | |
246 }); | |
247 completer.complete("value"); | |
248 } | |
249 | |
250 void testFutureAsStreamCompleteBefore() { | |
251 var completer = new Completer(); | |
252 bool gotValue = false; | |
253 asyncStart(); | |
254 completer.complete("value"); | |
255 completer.future.asStream().listen((data) { | |
256 Expect.isFalse(gotValue); | |
257 gotValue = true; | |
258 Expect.equals("value", data); | |
259 }, onDone: () { | |
260 Expect.isTrue(gotValue); | |
261 asyncEnd(); | |
262 }); | |
263 } | |
264 | |
265 void testFutureAsStreamCompleteImmediate() { | |
266 bool gotValue = false; | |
267 asyncStart(); | |
268 new Future.value("value").asStream().listen((data) { | |
269 Expect.isFalse(gotValue); | |
270 gotValue = true; | |
271 Expect.equals("value", data); | |
272 }, onDone: () { | |
273 Expect.isTrue(gotValue); | |
274 asyncEnd(); | |
275 }); | |
276 } | |
277 | |
278 void testFutureAsStreamCompleteErrorAfter() { | |
279 var completer = new Completer(); | |
280 bool gotError = false; | |
281 asyncStart(); | |
282 completer.future.asStream().listen((data) { | |
283 Expect.fail("Unexpected data"); | |
284 }, onError: (error) { | |
285 Expect.isFalse(gotError); | |
286 gotError = true; | |
287 Expect.equals("error", error); | |
288 }, onDone: () { | |
289 Expect.isTrue(gotError); | |
290 asyncEnd(); | |
291 }); | |
292 completer.completeError("error"); | |
293 } | |
294 | |
295 void testFutureAsStreamWrapper() { | |
296 var completer = new Completer(); | |
297 bool gotValue = false; | |
298 asyncStart(); | |
299 completer.complete("value"); | |
300 completer.future | |
301 .catchError((_) { | |
302 throw "not possible"; | |
303 }) // Returns a future wrapper. | |
304 .asStream() | |
305 .listen((data) { | |
306 Expect.isFalse(gotValue); | |
307 gotValue = true; | |
308 Expect.equals("value", data); | |
309 }, onDone: () { | |
310 Expect.isTrue(gotValue); | |
311 asyncEnd(); | |
312 }); | |
313 } | |
314 | |
315 void testFutureWhenCompleteValue() { | |
316 asyncStart(); | |
317 int counter = 2; | |
318 countDown() { | |
319 if (--counter == 0) asyncEnd(); | |
320 } | |
321 | |
322 var completer = new Completer(); | |
323 Future future = completer.future; | |
324 Future later = future.whenComplete(countDown); | |
325 later.then((v) { | |
326 Expect.equals(42, v); | |
327 countDown(); | |
328 }); | |
329 completer.complete(42); | |
330 } | |
331 | |
332 void testFutureWhenCompleteError() { | |
333 asyncStart(); | |
334 int counter = 2; | |
335 countDown() { | |
336 if (--counter == 0) asyncEnd(); | |
337 } | |
338 | |
339 var completer = new Completer(); | |
340 Future future = completer.future; | |
341 Future later = future.whenComplete(countDown); | |
342 later.catchError((error) { | |
343 Expect.equals("error", error); | |
344 countDown(); | |
345 }); | |
346 completer.completeError("error"); | |
347 } | |
348 | |
349 void testFutureWhenCompleteValueNewError() { | |
350 asyncStart(); | |
351 int counter = 2; | |
352 countDown() { | |
353 if (--counter == 0) asyncEnd(); | |
354 } | |
355 | |
356 var completer = new Completer(); | |
357 Future future = completer.future; | |
358 Future later = future.whenComplete(() { | |
359 countDown(); | |
360 throw "new error"; | |
361 }); | |
362 later.catchError((error) { | |
363 Expect.equals("new error", error); | |
364 countDown(); | |
365 }); | |
366 completer.complete(42); | |
367 } | |
368 | |
369 void testFutureWhenCompleteErrorNewError() { | |
370 asyncStart(); | |
371 int counter = 2; | |
372 countDown() { | |
373 if (--counter == 0) asyncEnd(); | |
374 } | |
375 | |
376 var completer = new Completer(); | |
377 Future future = completer.future; | |
378 Future later = future.whenComplete(() { | |
379 countDown(); | |
380 throw "new error"; | |
381 }); | |
382 later.catchError((error) { | |
383 Expect.equals("new error", error); | |
384 countDown(); | |
385 }); | |
386 completer.completeError("error"); | |
387 } | |
388 | |
389 void testFutureWhenCompletePreValue() { | |
390 asyncStart(); | |
391 int counter = 2; | |
392 countDown() { | |
393 if (--counter == 0) asyncEnd(); | |
394 } | |
395 | |
396 var completer = new Completer(); | |
397 Future future = completer.future; | |
398 completer.complete(42); | |
399 Timer.run(() { | |
400 Future later = future.whenComplete(countDown); | |
401 later.then((v) { | |
402 Expect.equals(42, v); | |
403 countDown(); | |
404 }); | |
405 }); | |
406 } | |
407 | |
408 void testFutureWhenValueFutureValue() { | |
409 asyncStart(); | |
410 int counter = 3; | |
411 countDown(int expect) { | |
412 Expect.equals(expect, counter); | |
413 if (--counter == 0) asyncEnd(); | |
414 } | |
415 | |
416 var completer = new Completer(); | |
417 completer.future.whenComplete(() { | |
418 countDown(3); | |
419 var completer2 = new Completer(); | |
420 new Timer(MS * 10, () { | |
421 countDown(2); | |
422 completer2.complete(37); | |
423 }); | |
424 return completer2.future; | |
425 }).then((v) { | |
426 Expect.equals(42, v); | |
427 countDown(1); | |
428 }); | |
429 | |
430 completer.complete(42); | |
431 } | |
432 | |
433 void testFutureWhenValueFutureError() { | |
434 asyncStart(); | |
435 int counter = 3; | |
436 countDown(int expect) { | |
437 Expect.equals(expect, counter); | |
438 if (--counter == 0) asyncEnd(); | |
439 } | |
440 | |
441 var completer = new Completer(); | |
442 completer.future.whenComplete(() { | |
443 countDown(3); | |
444 var completer2 = new Completer(); | |
445 new Timer(MS * 10, () { | |
446 countDown(2); | |
447 completer2.completeError("Fail"); | |
448 }); | |
449 return completer2.future; | |
450 }).then((v) { | |
451 Expect.fail("should fail async"); | |
452 }, onError: (error) { | |
453 Expect.equals("Fail", error); | |
454 countDown(1); | |
455 }); | |
456 | |
457 completer.complete(42); | |
458 } | |
459 | |
460 void testFutureWhenErrorFutureValue() { | |
461 asyncStart(); | |
462 int counter = 3; | |
463 countDown(int expect) { | |
464 Expect.equals(expect, counter); | |
465 if (--counter == 0) asyncEnd(); | |
466 } | |
467 | |
468 var completer = new Completer(); | |
469 completer.future.whenComplete(() { | |
470 countDown(3); | |
471 var completer2 = new Completer(); | |
472 new Timer(MS * 10, () { | |
473 countDown(2); | |
474 completer2.complete(37); | |
475 }); | |
476 return completer2.future; | |
477 }).then((v) { | |
478 Expect.fail("should fail async"); | |
479 }, onError: (error) { | |
480 Expect.equals("Error", error); | |
481 countDown(1); | |
482 }); | |
483 | |
484 completer.completeError("Error"); | |
485 } | |
486 | |
487 void testFutureWhenErrorFutureError() { | |
488 asyncStart(); | |
489 int counter = 3; | |
490 countDown(int expect) { | |
491 Expect.equals(expect, counter); | |
492 if (--counter == 0) asyncEnd(); | |
493 } | |
494 | |
495 var completer = new Completer(); | |
496 completer.future.whenComplete(() { | |
497 countDown(3); | |
498 var completer2 = new Completer(); | |
499 new Timer(MS * 10, () { | |
500 countDown(2); | |
501 completer2.completeError("Fail"); | |
502 }); | |
503 return completer2.future; | |
504 }).then((v) { | |
505 Expect.fail("should fail async"); | |
506 }, onError: (error) { | |
507 Expect.equals("Fail", error); | |
508 countDown(1); | |
509 }); | |
510 | |
511 completer.completeError("Error"); | |
512 } | |
513 | |
514 void testFutureThenThrowsAsync() { | |
515 final completer = new Completer<int>(); | |
516 final future = completer.future; | |
517 int error = 42; | |
518 | |
519 asyncStart(); | |
520 future.then((v) { | |
521 throw error; | |
522 }).catchError((e) { | |
523 Expect.identical(error, e); | |
524 asyncEnd(); | |
525 }); | |
526 completer.complete(0); | |
527 } | |
528 | |
529 void testFutureCatchThrowsAsync() { | |
530 final completer = new Completer<int>(); | |
531 final future = completer.future; | |
532 int error = 42; | |
533 | |
534 asyncStart(); | |
535 future.catchError((e) { | |
536 throw error; | |
537 }).catchError((e) { | |
538 Expect.identical(error, e); | |
539 asyncEnd(); | |
540 }); | |
541 completer.completeError(0); | |
542 } | |
543 | |
544 void testFutureCatchRethrowsAsync() { | |
545 final completer = new Completer<int>(); | |
546 final future = completer.future; | |
547 var error; | |
548 | |
549 asyncStart(); | |
550 future.catchError((e) { | |
551 error = e; | |
552 throw e; | |
553 }).catchError((e) { | |
554 Expect.identical(error, e); | |
555 asyncEnd(); | |
556 }); | |
557 completer.completeError(0); | |
558 } | |
559 | |
560 void testFutureWhenThrowsAsync() { | |
561 final completer = new Completer<int>(); | |
562 final future = completer.future; | |
563 var error = 42; | |
564 | |
565 asyncStart(); | |
566 future.whenComplete(() { | |
567 throw error; | |
568 }).catchError((e) { | |
569 Expect.identical(error, e); | |
570 asyncEnd(); | |
571 }); | |
572 completer.complete(0); | |
573 } | |
574 | |
575 void testCompleteWithError() { | |
576 final completer = new Completer<int>(); | |
577 final future = completer.future; | |
578 var error = 42; | |
579 | |
580 asyncStart(); | |
581 future.catchError((e) { | |
582 Expect.identical(error, e); | |
583 asyncEnd(); | |
584 }); | |
585 | |
586 completer.completeError(error); | |
587 } | |
588 | |
589 void testCompleteWithFutureSuccess() { | |
590 asyncStart(); | |
591 final completer = new Completer<int>(); | |
592 final completer2 = new Completer<int>(); | |
593 completer.complete(completer2.future); | |
594 completer.future.then((v) { | |
595 Expect.equals(42, v); | |
596 asyncEnd(); | |
597 }); | |
598 completer2.complete(42); | |
599 } | |
600 | |
601 void testCompleteWithFutureSuccess2() { | |
602 asyncStart(); | |
603 final completer = new Completer<int>(); | |
604 Future result = new Future.value(42); | |
605 completer.complete(result); | |
606 completer.future.then((v) { | |
607 Expect.equals(42, v); | |
608 asyncEnd(); | |
609 }); | |
610 } | |
611 | |
612 void testCompleteWithFutureError() { | |
613 asyncStart(); | |
614 final completer = new Completer<int>(); | |
615 final completer2 = new Completer<int>(); | |
616 completer.complete(completer2.future); | |
617 completer.future.then((v) { | |
618 Expect.fail("Should not happen"); | |
619 asyncEnd(); | |
620 }, onError: (e) { | |
621 Expect.equals("ERROR-tcwfe", e); | |
622 asyncEnd(); | |
623 }); | |
624 completer2.completeError("ERROR-tcwfe"); | |
625 } | |
626 | |
627 void testCompleteWithFutureError2() { | |
628 asyncStart(); | |
629 final completer = new Completer<int>(); | |
630 Future result = new Future.error("ERROR-tcwfe2"); | |
631 completer.complete(result); | |
632 completer.future.then((v) { | |
633 Expect.fail("Should not happen"); | |
634 asyncEnd(); | |
635 }, onError: (e) { | |
636 Expect.equals("ERROR-tcwfe2", e); | |
637 asyncEnd(); | |
638 }); | |
639 } | |
640 | |
641 void testCompleteErrorWithFuture() { | |
642 asyncStart(); | |
643 final completer = new Completer<int>(); | |
644 completer.completeError(new Future.value(42)); | |
645 completer.future.then((_) { | |
646 Expect.fail("Shouldn't happen"); | |
647 }, onError: (e, s) { | |
648 Future f = e; | |
649 f.then((v) { | |
650 Expect.equals(42, v); | |
651 asyncEnd(); | |
652 }); | |
653 }); | |
654 } | |
655 | |
656 void testCompleteWithCustomFutureSuccess() { | |
657 asyncStart(); | |
658 final completer = new Completer<int>(); | |
659 final completer2 = new Completer<int>(); | |
660 completer.complete(new CustomFuture(completer2.future)); | |
661 completer.future.then((v) { | |
662 Expect.equals(42, v); | |
663 asyncEnd(); | |
664 }); | |
665 completer2.complete(42); | |
666 } | |
667 | |
668 void testCompleteWithCustomFutureError() { | |
669 asyncStart(); | |
670 final completer = new Completer<int>(); | |
671 final completer2 = new Completer<int>(); | |
672 completer.complete(new CustomFuture(completer2.future)); | |
673 completer.future.then((v) { | |
674 Expect.fail("Should not happen"); | |
675 asyncEnd(); | |
676 }, onError: (e) { | |
677 Expect.equals("ERROR-tcwcfe", e); | |
678 asyncEnd(); | |
679 }); | |
680 completer2.completeError("ERROR-tcwcfe"); | |
681 } | |
682 | |
683 void testCompleteErrorWithCustomFuture() { | |
684 asyncStart(); | |
685 final completer = new Completer<int>(); | |
686 var future = new CustomFuture(new Future.value(42)); | |
687 completer.completeError(future); | |
688 completer.future.then((_) { | |
689 Expect.fail("Shouldn't happen"); | |
690 }, onError: (Future f) { | |
691 f.then((v) { | |
692 Expect.equals(42, v); | |
693 asyncEnd(); | |
694 }); | |
695 }); | |
696 } | |
697 | |
698 void testCompleteErrorWithNull() { | |
699 asyncStart(); | |
700 final completer = new Completer<int>(); | |
701 completer.future.catchError((e) { | |
702 Expect.isTrue(e is NullThrownError); | |
703 asyncEnd(); | |
704 }); | |
705 completer.completeError(null); | |
706 } | |
707 | |
708 void testChainedFutureValue() { | |
709 final completer = new Completer(); | |
710 final future = completer.future; | |
711 asyncStart(); | |
712 | |
713 future.then((v) => new Future.value(v * 2)).then((v) { | |
714 Expect.equals(42, v); | |
715 asyncEnd(); | |
716 }); | |
717 completer.complete(21); | |
718 } | |
719 | |
720 void testChainedFutureValueDelay() { | |
721 final completer = new Completer(); | |
722 final future = completer.future; | |
723 asyncStart(); | |
724 | |
725 future | |
726 .then((v) => | |
727 new Future.delayed(const Duration(milliseconds: 10), () => v * 2)) | |
728 .then((v) { | |
729 Expect.equals(42, v); | |
730 asyncEnd(); | |
731 }); | |
732 completer.complete(21); | |
733 } | |
734 | |
735 void testChainedFutureValue2Delay() { | |
736 asyncStart(); | |
737 | |
738 new Future.delayed(const Duration(milliseconds: 10)).then((v) { | |
739 Expect.isNull(v); | |
740 asyncEnd(); | |
741 }); | |
742 } | |
743 | |
744 void testChainedFutureError() { | |
745 final completer = new Completer(); | |
746 final future = completer.future; | |
747 asyncStart(); | |
748 | |
749 future.then((v) => new Future.error("Fehler")).then((v) { | |
750 Expect.fail("unreachable!"); | |
751 }, onError: (error) { | |
752 Expect.equals("Fehler", error); | |
753 asyncEnd(); | |
754 }); | |
755 completer.complete(21); | |
756 } | |
757 | |
758 void testSyncFuture_i13368() { | |
759 asyncStart(); | |
760 | |
761 final future = new Future<int>.sync(() { | |
762 return new Future<int>.value(42); | |
763 }); | |
764 | |
765 future.then((int val) { | |
766 Expect.equals(val, 42); | |
767 asyncEnd(); | |
768 }); | |
769 } | |
770 | |
771 void testWaitCleanUp() { | |
772 asyncStart(); | |
773 // Creates three futures with different completion times, and where some fail. | |
774 // The `mask` specifies which futures fail (values 1-7), | |
775 // and `permute` defines the order of completion. values 0-5. | |
776 void doTest(int mask, int permute) { | |
777 asyncStart(); | |
778 String stringId = "waitCleanup-$mask-$permute"; | |
779 List futures = new List(3); | |
780 List cleanup = new List(3); | |
781 int permuteTmp = permute; | |
782 for (int i = 0; i < 3; i++) { | |
783 bool throws = (mask & (1 << i)) != 0; | |
784 var future = new Future.delayed(new Duration(milliseconds: 100 * (i + 1)), | |
785 () => (throws ? throw "Error $i($mask-$permute)" : i)); | |
786 int mod = 3 - i; | |
787 int position = permuteTmp % mod; | |
788 permuteTmp = permuteTmp ~/ mod; | |
789 while (futures[position] != null) position++; | |
790 futures[position] = future; | |
791 cleanup[i] = throws; | |
792 } | |
793 void cleanUp(index) { | |
794 Expect.isFalse(cleanup[index]); | |
795 cleanup[index] = true; | |
796 } | |
797 | |
798 Future.wait(futures, cleanUp: cleanUp).then((_) { | |
799 Expect.fail("No error: $stringId"); | |
800 }, onError: (e, s) { | |
801 Expect.listEquals([true, true, true], cleanup); | |
802 asyncEnd(); | |
803 }); | |
804 } | |
805 | |
806 for (int i = 1; i < 8; i++) { | |
807 for (int j = 0; j < 6; j++) { | |
808 doTest(i, j); | |
809 } | |
810 } | |
811 asyncEnd(); | |
812 } | |
813 | |
814 void testWaitCleanUpEager() { | |
815 asyncStart(); | |
816 // Creates three futures with different completion times, and where some fail. | |
817 // The `mask` specifies which futures fail (values 1-7), | |
818 // and `permute` defines the order of completion. values 0-5. | |
819 void doTest(int mask, int permute) { | |
820 asyncStart(); | |
821 asyncStart(); | |
822 bool done = false; | |
823 String stringId = "waitCleanup-$mask-$permute"; | |
824 List futures = new List(3); | |
825 List cleanup = new List(3); | |
826 int permuteTmp = permute; | |
827 for (int i = 0; i < 3; i++) { | |
828 bool throws = (mask & (1 << i)) != 0; | |
829 var future = new Future.delayed(new Duration(milliseconds: 100 * (i + 1)), | |
830 () => (throws ? throw "Error $i($mask-$permute)" : i)); | |
831 int mod = 3 - i; | |
832 int position = permuteTmp % mod; | |
833 permuteTmp = permuteTmp ~/ mod; | |
834 while (futures[position] != null) position++; | |
835 futures[position] = future; | |
836 cleanup[i] = throws; | |
837 } | |
838 void checkDone() { | |
839 if (done) return; | |
840 if (cleanup.every((v) => v)) { | |
841 done = true; | |
842 asyncEnd(); | |
843 } | |
844 } | |
845 | |
846 void cleanUp(index) { | |
847 Expect.isFalse(cleanup[index]); | |
848 cleanup[index] = true; | |
849 // Cleanup might happen before and after the wait().then() callback. | |
850 checkDone(); | |
851 } | |
852 | |
853 Future.wait(futures, eagerError: true, cleanUp: cleanUp).then((_) { | |
854 Expect.fail("No error: $stringId"); | |
855 }, onError: (e, s) { | |
856 asyncEnd(); | |
857 checkDone(); | |
858 }); | |
859 } | |
860 | |
861 for (int i = 1; i < 8; i++) { | |
862 for (int j = 0; j < 6; j++) { | |
863 doTest(i, j); | |
864 } | |
865 } | |
866 asyncEnd(); | |
867 } | |
868 | |
869 void testWaitCleanUpError() { | |
870 var cms = const Duration(milliseconds: 100); | |
871 var cleanups = new List.filled(3, false); | |
872 var uncaughts = new List.filled(3, false); | |
873 asyncStart(); | |
874 asyncStart(); | |
875 asyncStart(); | |
876 runZoned(() { | |
877 Future.wait([ | |
878 new Future.delayed(cms, () => 0), | |
879 new Future.delayed(cms * 2, () => throw 1), | |
880 new Future.delayed(cms * 3, () => 2) | |
881 ], cleanUp: (index) { | |
882 Expect.isTrue(index == 0 || index == 2, "$index"); | |
883 Expect.isFalse(cleanups[index]); | |
884 cleanups[index] = true; | |
885 throw index; | |
886 }).catchError((e) { | |
887 Expect.equals(e, 1); | |
888 asyncEnd(); | |
889 }); | |
890 }, onError: (int index, s) { | |
891 Expect.isTrue(index == 0 || index == 2, "$index"); | |
892 Expect.isFalse(uncaughts[index]); | |
893 uncaughts[index] = true; | |
894 asyncEnd(); | |
895 }); | |
896 } | |
897 | |
898 void testWaitSyncError() { | |
899 var cms = const Duration(milliseconds: 100); | |
900 var cleanups = new List.filled(3, false); | |
901 asyncStart(); | |
902 asyncStart(); | |
903 runZoned(() { | |
904 Future.wait( | |
905 new Iterable.generate(5, (i) { | |
906 if (i != 3) return new Future.delayed(cms * (i + 1), () => i); | |
907 throw "throwing synchronously in iterable"; | |
908 }), cleanUp: (index) { | |
909 Expect.isFalse(cleanups[index]); | |
910 cleanups[index] = true; | |
911 if (cleanups.every((x) => x)) asyncEnd(); | |
912 }); | |
913 }, onError: (e, s) { | |
914 asyncEnd(); | |
915 }); | |
916 } | |
917 | |
918 void testWaitSyncError2() { | |
919 asyncStart(); | |
920 Future.wait([null]).catchError((e, st) { | |
921 // Makes sure that the `catchError` is invoked. | |
922 // Regression test: an earlier version of `Future.wait` would propagate | |
923 // the error too soon for the code to install an error handler. | |
924 // `testWaitSyncError` didn't show this problem, because the `runZoned` | |
925 // was already installed. | |
926 asyncEnd(); | |
927 }); | |
928 } | |
929 | |
930 // Future.wait transforms synchronous errors into asynchronous ones. | |
931 // This function tests that zones can intercept them. | |
932 void testWaitSyncError3() { | |
933 var caughtError; | |
934 var count = 0; | |
935 | |
936 AsyncError errorCallback(Zone self, ZoneDelegate parent, Zone zone, | |
937 Object error, StackTrace stackTrace) { | |
938 Expect.equals(0, count); | |
939 count++; | |
940 caughtError = error; | |
941 return parent.errorCallback(zone, error, stackTrace); | |
942 } | |
943 | |
944 asyncStart(); | |
945 runZoned(() { | |
946 Future.wait([null]).catchError((e, st) { | |
947 Expect.identical(e, caughtError); | |
948 Expect.equals(1, count); | |
949 asyncEnd(); | |
950 }); | |
951 }, zoneSpecification: new ZoneSpecification(errorCallback: errorCallback)); | |
952 } | |
953 | |
954 void testBadFuture() { | |
955 var bad = new BadFuture(); | |
956 // Completing with bad future (then call throws) puts error in result. | |
957 asyncStart(); | |
958 Completer completer = new Completer(); | |
959 completer.complete(bad); | |
960 completer.future.then((_) { | |
961 Expect.fail("unreachable"); | |
962 }, onError: (e, s) { | |
963 Expect.isTrue(completer.isCompleted); | |
964 asyncEnd(); | |
965 }); | |
966 | |
967 asyncStart(); | |
968 var f = new Future.value().then((_) => bad); | |
969 f.then((_) { | |
970 Expect.fail("unreachable"); | |
971 }, onError: (e, s) { | |
972 asyncEnd(); | |
973 }); | |
974 } | |
975 | |
976 void testTypes() { | |
977 // Test that future is a Future<int> and not something less precise. | |
978 testType(name, future, [depth = 2]) { | |
979 var desc = "$name${".whenComplete"*(2-depth)}"; | |
980 Expect.isTrue(future is Future<int>, "$desc is Future<int>"); | |
981 Expect.isFalse(future is Future<String>, "$desc is! Future<String>"); | |
982 var stream = future.asStream(); | |
983 Expect.isTrue(stream is Stream<int>, "$desc.asStream() is Stream<int>"); | |
984 Expect.isFalse( | |
985 stream is Stream<String>, "$desc.asStream() is! Stream<String>"); | |
986 if (depth > 0) { | |
987 testType(name, future.whenComplete(() {}), depth - 1); | |
988 } | |
989 } | |
990 | |
991 for (var value in [42, null]) { | |
992 testType("Future($value)", new Future<int>(() => value)); | |
993 testType("Future.delayed($value)", | |
994 new Future<int>.delayed(Duration.ZERO, () => value)); | |
995 testType( | |
996 "Future.microtask($value)", new Future<int>.microtask(() => value)); | |
997 testType("Future.sync($value)", new Future<int>.sync(() => value)); //# 01:
ok | |
998 testType("Future.sync(future($value))", // //# 01:
continued | |
999 new Future<int>.sync(() => new Future<int>.value(value))); //# 01:
continued | |
1000 testType("Future.value($value)", new Future<int>.value(value)); | |
1001 } | |
1002 testType("Completer.future", new Completer<int>().future); | |
1003 testType("Future.error", new Future<int>.error("ERR")..catchError((_) {})); | |
1004 } | |
1005 | |
1006 void testAnyValue() { | |
1007 asyncStart(); | |
1008 var cs = new List.generate(3, (_) => new Completer()); | |
1009 var result = Future.any(cs.map((x) => x.future)); | |
1010 | |
1011 result.then((v) { | |
1012 Expect.equals(42, v); | |
1013 asyncEnd(); | |
1014 }, onError: (e, s) { | |
1015 Expect.fail("Unexpected error: $e"); | |
1016 }); | |
1017 | |
1018 cs[1].complete(42); | |
1019 cs[2].complete(10); | |
1020 cs[0].complete(20); | |
1021 } | |
1022 | |
1023 void testAnyError() { | |
1024 asyncStart(); | |
1025 var cs = new List.generate(3, (_) => new Completer()); | |
1026 var result = Future.any(cs.map((x) => x.future)); | |
1027 | |
1028 result.then((v) { | |
1029 Expect.fail("Unexpected value: $v"); | |
1030 }, onError: (e, s) { | |
1031 Expect.equals(42, e); | |
1032 asyncEnd(); | |
1033 }); | |
1034 | |
1035 cs[1].completeError(42); | |
1036 cs[2].complete(10); | |
1037 cs[0].complete(20); | |
1038 } | |
1039 | |
1040 void testAnyIgnoreIncomplete() { | |
1041 asyncStart(); | |
1042 var cs = new List.generate(3, (_) => new Completer()); | |
1043 var result = Future.any(cs.map((x) => x.future)); | |
1044 | |
1045 result.then((v) { | |
1046 Expect.equals(42, v); | |
1047 asyncEnd(); | |
1048 }, onError: (e, s) { | |
1049 Expect.fail("Unexpected error: $e"); | |
1050 }); | |
1051 | |
1052 cs[1].complete(42); | |
1053 // The other two futures never complete. | |
1054 } | |
1055 | |
1056 void testAnyIgnoreError() { | |
1057 asyncStart(); | |
1058 var cs = new List.generate(3, (_) => new Completer()); | |
1059 var result = Future.any(cs.map((x) => x.future)); | |
1060 | |
1061 result.then((v) { | |
1062 Expect.equals(42, v); | |
1063 asyncEnd(); | |
1064 }, onError: (e, s) { | |
1065 Expect.fail("Unexpected error: $e"); | |
1066 }); | |
1067 | |
1068 cs[1].complete(42); | |
1069 // The errors are ignored, not uncaught. | |
1070 cs[2].completeError("BAD"); | |
1071 cs[0].completeError("BAD"); | |
1072 } | |
1073 | |
1074 void testFutureResult() { | |
1075 asyncStart(); | |
1076 () async { | |
1077 var f = new UglyFuture(5); | |
1078 // Sanity check that our future is as mis-behaved as we think. | |
1079 f.then((v) { | |
1080 Expect.isTrue(v is Future); | |
1081 }); | |
1082 | |
1083 var v = await f; | |
1084 // The static type of await is Flatten(static-type-of-expression), so it | |
1085 // suggests that it flattens. In practice it currently doesn't. | |
1086 // The specification doesn't say anything special, so v should be the | |
1087 // completion value of the UglyFuture future which is a future. | |
1088 Expect.isTrue(v is Future); | |
1089 | |
1090 // This used to hit an assert in checked mode. | |
1091 // The CL adding this test changed the behavior to actually flatten the | |
1092 // the future returned by the then-callback. | |
1093 var w = new Future.value(42).then((_) => f); | |
1094 Expect.equals(42, await w); | |
1095 asyncEnd(); | |
1096 }(); | |
1097 } | |
1098 | |
1099 main() { | |
1100 asyncStart(); | |
1101 | |
1102 testValue(); | |
1103 testSync(); | |
1104 testNeverComplete(); | |
1105 | |
1106 testComplete(); | |
1107 testCompleteWithSuccessHandlerBeforeComplete(); | |
1108 testCompleteWithSuccessHandlerAfterComplete(); | |
1109 testCompleteManySuccessHandlers(); | |
1110 testCompleteWithError(); | |
1111 | |
1112 testCompleteWithFutureSuccess(); | |
1113 testCompleteWithFutureSuccess2(); | |
1114 testCompleteWithFutureError(); | |
1115 testCompleteWithFutureError2(); | |
1116 testCompleteErrorWithFuture(); | |
1117 testCompleteWithCustomFutureSuccess(); | |
1118 testCompleteWithCustomFutureError(); | |
1119 testCompleteErrorWithCustomFuture(); | |
1120 testCompleteErrorWithNull(); | |
1121 | |
1122 testException(); | |
1123 testExceptionHandler(); | |
1124 testExceptionHandlerReturnsTrue(); | |
1125 testExceptionHandlerReturnsTrue2(); | |
1126 testExceptionHandlerReturnsFalse(); | |
1127 | |
1128 testFutureAsStreamCompleteAfter(); | |
1129 testFutureAsStreamCompleteBefore(); | |
1130 testFutureAsStreamCompleteImmediate(); | |
1131 testFutureAsStreamCompleteErrorAfter(); | |
1132 testFutureAsStreamWrapper(); | |
1133 | |
1134 testFutureWhenCompleteValue(); | |
1135 testFutureWhenCompleteError(); | |
1136 testFutureWhenCompleteValueNewError(); | |
1137 testFutureWhenCompleteErrorNewError(); | |
1138 | |
1139 testFutureWhenValueFutureValue(); | |
1140 testFutureWhenErrorFutureValue(); | |
1141 testFutureWhenValueFutureError(); | |
1142 testFutureWhenErrorFutureError(); | |
1143 | |
1144 testFutureThenThrowsAsync(); | |
1145 testFutureCatchThrowsAsync(); | |
1146 testFutureWhenThrowsAsync(); | |
1147 testFutureCatchRethrowsAsync(); | |
1148 | |
1149 testChainedFutureValue(); | |
1150 testChainedFutureValueDelay(); | |
1151 testChainedFutureError(); | |
1152 | |
1153 testSyncFuture_i13368(); | |
1154 | |
1155 testWaitCleanUp(); | |
1156 testWaitCleanUpError(); | |
1157 testWaitSyncError(); | |
1158 testWaitSyncError2(); | |
1159 testWaitSyncError3(); | |
1160 | |
1161 testBadFuture(); | |
1162 | |
1163 testTypes(); | |
1164 | |
1165 testAnyValue(); | |
1166 testAnyError(); | |
1167 testAnyIgnoreIncomplete(); | |
1168 testAnyIgnoreError(); | |
1169 | |
1170 testFutureResult(); | |
1171 | |
1172 asyncEnd(); | |
1173 } | |
1174 | |
1175 /// A well-behaved Future that isn't recognizable as a _Future. | |
1176 class CustomFuture<T> implements Future<T> { | |
1177 Future _realFuture; | |
1178 CustomFuture(this._realFuture); | |
1179 Future then(action(result), {Function onError}) => | |
1180 _realFuture.then(action, onError: onError); | |
1181 Future catchError(Function onError, {bool test(e)}) => | |
1182 _realFuture.catchError(onError, test: test); | |
1183 Future whenComplete(action()) => _realFuture.whenComplete(action); | |
1184 Future timeout(Duration timeLimit, {void onTimeout()}) => | |
1185 _realFuture.timeout(timeLimit, onTimeout: onTimeout); | |
1186 Stream asStream() => _realFuture.asStream(); | |
1187 String toString() => "CustomFuture@${_realFuture.hashCode}"; | |
1188 int get hashCode => _realFuture.hashCode; | |
1189 } | |
1190 | |
1191 /// A bad future that throws on every method. | |
1192 class BadFuture<T> implements Future<T> { | |
1193 Future then(action(T result), {Function onError}) { | |
1194 throw "then GOTCHA!"; | |
1195 } | |
1196 | |
1197 Future catchError(Function onError, {bool test(e)}) { | |
1198 throw "catch GOTCHA!"; | |
1199 } | |
1200 | |
1201 Future whenComplete(action()) { | |
1202 throw "finally GOTCHA!"; | |
1203 } | |
1204 | |
1205 Stream<T> asStream() { | |
1206 throw "asStream GOTCHA!"; | |
1207 } | |
1208 | |
1209 Future timeout(Duration duration, {onTimeout()}) { | |
1210 throw "timeout GOTCHA!"; | |
1211 } | |
1212 } | |
1213 | |
1214 // An evil future that completes with another future. | |
1215 class UglyFuture implements Future<dynamic> { | |
1216 final _result; | |
1217 UglyFuture(int badness) | |
1218 : _result = (badness == 0) ? 42 : new UglyFuture(badness - 1); | |
1219 Future then(action(value), {onError(error, StackTrace stack)}) { | |
1220 var c = new Completer(); | |
1221 c.complete(new Future.microtask(() => action(_result))); | |
1222 return c.future; | |
1223 } | |
1224 | |
1225 Future catchError(onError, {test}) => this; // Never an error. | |
1226 Future whenComplete(action()) { | |
1227 return new Future.microtask(action).then((_) => this); | |
1228 } | |
1229 | |
1230 Stream asStream() { | |
1231 return (new StreamController() | |
1232 ..add(_result) | |
1233 ..close()) | |
1234 .stream; | |
1235 } | |
1236 | |
1237 Future timeout(Duration duration, {onTimeout()}) { | |
1238 return this; | |
1239 } | |
1240 } | |
OLD | NEW |