Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: pkg/stack_trace/test/chain_test.dart

Issue 812253002: Delete a bunch of packages that are now on GitHub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Un-delete http Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/stack_trace/pubspec.yaml ('k') | pkg/stack_trace/test/frame_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 chain_test;
6
7 import 'dart:async';
8
9 import 'package:path/path.dart' as p;
10 import 'package:stack_trace/stack_trace.dart';
11 import 'package:unittest/unittest.dart';
12
13 import 'utils.dart';
14
15 void main() {
16 group('capture() with onError catches exceptions', () {
17 test('thrown synchronously', () {
18 return captureFuture(() => throw 'error')
19 .then((chain) {
20 expect(chain.traces, hasLength(1));
21 expect(chain.traces.single.frames.first,
22 frameMember(startsWith('main')));
23 });
24 });
25
26 test('thrown in a microtask', () {
27 return captureFuture(() => inMicrotask(() => throw 'error'))
28 .then((chain) {
29 // Since there was only one asynchronous operation, there should be only
30 // two traces in the chain.
31 expect(chain.traces, hasLength(2));
32
33 // The first frame of the first trace should be the line on which the
34 // actual error was thrown.
35 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
36
37 // The second trace should describe the stack when the error callback
38 // was scheduled.
39 expect(chain.traces[1].frames,
40 contains(frameMember(startsWith('inMicrotask'))));
41 });
42 });
43
44 test('thrown in a one-shot timer', () {
45 return captureFuture(() => inOneShotTimer(() => throw 'error'))
46 .then((chain) {
47 expect(chain.traces, hasLength(2));
48 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
49 expect(chain.traces[1].frames,
50 contains(frameMember(startsWith('inOneShotTimer'))));
51 });
52 });
53
54 test('thrown in a periodic timer', () {
55 return captureFuture(() => inPeriodicTimer(() => throw 'error'))
56 .then((chain) {
57 expect(chain.traces, hasLength(2));
58 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
59 expect(chain.traces[1].frames,
60 contains(frameMember(startsWith('inPeriodicTimer'))));
61 });
62 });
63
64 test('thrown in a nested series of asynchronous operations', () {
65 return captureFuture(() {
66 inPeriodicTimer(() {
67 inOneShotTimer(() => inMicrotask(() => throw 'error'));
68 });
69 }).then((chain) {
70 expect(chain.traces, hasLength(4));
71 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
72 expect(chain.traces[1].frames,
73 contains(frameMember(startsWith('inMicrotask'))));
74 expect(chain.traces[2].frames,
75 contains(frameMember(startsWith('inOneShotTimer'))));
76 expect(chain.traces[3].frames,
77 contains(frameMember(startsWith('inPeriodicTimer'))));
78 });
79 });
80
81 test('thrown in a long future chain', () {
82 return captureFuture(() => inFutureChain(() => throw 'error'))
83 .then((chain) {
84 // Despite many asynchronous operations, there's only one level of
85 // nested calls, so there should be only two traces in the chain. This
86 // is important; programmers expect stack trace memory consumption to be
87 // O(depth of program), not O(length of program).
88 expect(chain.traces, hasLength(2));
89
90 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
91 expect(chain.traces[1].frames,
92 contains(frameMember(startsWith('inFutureChain'))));
93 });
94 });
95
96 test('thrown in new Future()', () {
97 return captureFuture(() => inNewFuture(() => throw 'error'))
98 .then((chain) {
99 expect(chain.traces, hasLength(3));
100 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
101
102 // The second trace is the one captured by
103 // [StackZoneSpecification.errorCallback]. Because that runs
104 // asynchronously within [new Future], it doesn't actually refer to the
105 // source file at all.
106 expect(chain.traces[1].frames,
107 everyElement(frameLibrary(isNot(contains('chain_test')))));
108
109 expect(chain.traces[2].frames,
110 contains(frameMember(startsWith('inNewFuture'))));
111 });
112 });
113
114 test('thrown in new Future.sync()', () {
115 return captureFuture(() {
116 inMicrotask(() => inSyncFuture(() => throw 'error'));
117 }).then((chain) {
118 expect(chain.traces, hasLength(3));
119 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
120 expect(chain.traces[1].frames,
121 contains(frameMember(startsWith('inSyncFuture'))));
122 expect(chain.traces[2].frames,
123 contains(frameMember(startsWith('inMicrotask'))));
124 });
125 });
126
127 test('multiple times', () {
128 var completer = new Completer();
129 var first = true;
130
131 Chain.capture(() {
132 inMicrotask(() => throw 'first error');
133 inPeriodicTimer(() => throw 'second error');
134 }, onError: (error, chain) {
135 try {
136 if (first) {
137 expect(error, equals('first error'));
138 expect(chain.traces[1].frames,
139 contains(frameMember(startsWith('inMicrotask'))));
140 first = false;
141 } else {
142 expect(error, equals('second error'));
143 expect(chain.traces[1].frames,
144 contains(frameMember(startsWith('inPeriodicTimer'))));
145 completer.complete();
146 }
147 } catch (error, stackTrace) {
148 completer.completeError(error, stackTrace);
149 }
150 });
151
152 return completer.future;
153 });
154
155 test('passed to a completer', () {
156 var trace = new Trace.current();
157 return captureFuture(() {
158 inMicrotask(() => completerErrorFuture(trace));
159 }).then((chain) {
160 expect(chain.traces, hasLength(3));
161
162 // The first trace is the trace that was manually reported for the
163 // error.
164 expect(chain.traces.first.toString(), equals(trace.toString()));
165
166 // The second trace is the trace that was captured when
167 // [Completer.addError] was called.
168 expect(chain.traces[1].frames,
169 contains(frameMember(startsWith('completerErrorFuture'))));
170
171 // The third trace is the automatically-captured trace from when the
172 // microtask was scheduled.
173 expect(chain.traces[2].frames,
174 contains(frameMember(startsWith('inMicrotask'))));
175 });
176 });
177
178 test('passed to a completer with no stack trace', () {
179 return captureFuture(() {
180 inMicrotask(() => completerErrorFuture());
181 }).then((chain) {
182 expect(chain.traces, hasLength(2));
183
184 // The first trace is the one captured when [Completer.addError] was
185 // called.
186 expect(chain.traces[0].frames,
187 contains(frameMember(startsWith('completerErrorFuture'))));
188
189 // The second trace is the automatically-captured trace from when the
190 // microtask was scheduled.
191 expect(chain.traces[1].frames,
192 contains(frameMember(startsWith('inMicrotask'))));
193 });
194 });
195
196 test('passed to a stream controller', () {
197 var trace = new Trace.current();
198 return captureFuture(() {
199 inMicrotask(() => controllerErrorStream(trace).listen(null));
200 }).then((chain) {
201 expect(chain.traces, hasLength(3));
202 expect(chain.traces.first.toString(), equals(trace.toString()));
203 expect(chain.traces[1].frames,
204 contains(frameMember(startsWith('controllerErrorStream'))));
205 expect(chain.traces[2].frames,
206 contains(frameMember(startsWith('inMicrotask'))));
207 });
208 });
209
210 test('passed to a stream controller with no stack trace', () {
211 return captureFuture(() {
212 inMicrotask(() => controllerErrorStream().listen(null));
213 }).then((chain) {
214 expect(chain.traces, hasLength(2));
215 expect(chain.traces[0].frames,
216 contains(frameMember(startsWith('controllerErrorStream'))));
217 expect(chain.traces[1].frames,
218 contains(frameMember(startsWith('inMicrotask'))));
219 });
220 });
221
222 test('and relays them to the parent zone', () {
223 var completer = new Completer();
224
225 runZoned(() {
226 Chain.capture(() {
227 inMicrotask(() => throw 'error');
228 }, onError: (error, chain) {
229 expect(error, equals('error'));
230 expect(chain.traces[1].frames,
231 contains(frameMember(startsWith('inMicrotask'))));
232 throw error;
233 });
234 }, onError: (error, chain) {
235 try {
236 expect(error, equals('error'));
237 expect(chain, new isInstanceOf<Chain>());
238 expect(chain.traces[1].frames,
239 contains(frameMember(startsWith('inMicrotask'))));
240 completer.complete();
241 } catch (error, stackTrace) {
242 completer.completeError(error, stackTrace);
243 }
244 });
245
246 return completer.future;
247 });
248 });
249
250 test('capture() without onError passes exceptions to parent zone', () {
251 var completer = new Completer();
252
253 runZoned(() {
254 Chain.capture(() => inMicrotask(() => throw 'error'));
255 }, onError: (error, chain) {
256 try {
257 expect(error, equals('error'));
258 expect(chain, new isInstanceOf<Chain>());
259 expect(chain.traces[1].frames,
260 contains(frameMember(startsWith('inMicrotask'))));
261 completer.complete();
262 } catch (error, stackTrace) {
263 completer.completeError(error, stackTrace);
264 }
265 });
266
267 return completer.future;
268 });
269
270 group('current() within capture()', () {
271 test('called in a microtask', () {
272 var completer = new Completer();
273 Chain.capture(() {
274 inMicrotask(() => completer.complete(new Chain.current()));
275 });
276
277 return completer.future.then((chain) {
278 expect(chain.traces, hasLength(2));
279 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
280 expect(chain.traces[1].frames,
281 contains(frameMember(startsWith('inMicrotask'))));
282 });
283 });
284
285 test('called in a one-shot timer', () {
286 var completer = new Completer();
287 Chain.capture(() {
288 inOneShotTimer(() => completer.complete(new Chain.current()));
289 });
290
291 return completer.future.then((chain) {
292 expect(chain.traces, hasLength(2));
293 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
294 expect(chain.traces[1].frames,
295 contains(frameMember(startsWith('inOneShotTimer'))));
296 });
297 });
298
299 test('called in a periodic timer', () {
300 var completer = new Completer();
301 Chain.capture(() {
302 inPeriodicTimer(() => completer.complete(new Chain.current()));
303 });
304
305 return completer.future.then((chain) {
306 expect(chain.traces, hasLength(2));
307 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
308 expect(chain.traces[1].frames,
309 contains(frameMember(startsWith('inPeriodicTimer'))));
310 });
311 });
312
313 test('called in a nested series of asynchronous operations', () {
314 var completer = new Completer();
315 Chain.capture(() {
316 inPeriodicTimer(() {
317 inOneShotTimer(() {
318 inMicrotask(() => completer.complete(new Chain.current()));
319 });
320 });
321 });
322
323 return completer.future.then((chain) {
324 expect(chain.traces, hasLength(4));
325 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
326 expect(chain.traces[1].frames,
327 contains(frameMember(startsWith('inMicrotask'))));
328 expect(chain.traces[2].frames,
329 contains(frameMember(startsWith('inOneShotTimer'))));
330 expect(chain.traces[3].frames,
331 contains(frameMember(startsWith('inPeriodicTimer'))));
332 });
333 });
334
335 test('called in a long future chain', () {
336 var completer = new Completer();
337 Chain.capture(() {
338 inFutureChain(() => completer.complete(new Chain.current()));
339 });
340
341 return completer.future.then((chain) {
342 expect(chain.traces, hasLength(2));
343 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
344 expect(chain.traces[1].frames,
345 contains(frameMember(startsWith('inFutureChain'))));
346 });
347 });
348 });
349
350 test('current() outside of capture() returns a chain wrapping the current '
351 'trace', () {
352 var completer = new Completer();
353 inMicrotask(() => completer.complete(new Chain.current()));
354
355 return completer.future.then((chain) {
356 // Since the chain wasn't loaded within [Chain.capture], the full stack
357 // chain isn't available and it just returns the current stack when
358 // called.
359 expect(chain.traces, hasLength(1));
360 expect(chain.traces.first.frames.first, frameMember(startsWith('main')));
361 });
362 });
363
364 group('forTrace() within capture()', () {
365 test('called for a stack trace from a microtask', () {
366 return Chain.capture(() {
367 return chainForTrace(inMicrotask, () => throw 'error');
368 }).then((chain) {
369 // Because [chainForTrace] has to set up a future chain to capture the
370 // stack trace while still showing it to the zone specification, it adds
371 // an additional level of async nesting and so an additional trace.
372 expect(chain.traces, hasLength(3));
373 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
374 expect(chain.traces[1].frames,
375 contains(frameMember(startsWith('chainForTrace'))));
376 expect(chain.traces[2].frames,
377 contains(frameMember(startsWith('inMicrotask'))));
378 });
379 });
380
381 test('called for a stack trace from a one-shot timer', () {
382 return Chain.capture(() {
383 return chainForTrace(inOneShotTimer, () => throw 'error');
384 }).then((chain) {
385 expect(chain.traces, hasLength(3));
386 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
387 expect(chain.traces[1].frames,
388 contains(frameMember(startsWith('chainForTrace'))));
389 expect(chain.traces[2].frames,
390 contains(frameMember(startsWith('inOneShotTimer'))));
391 });
392 });
393
394 test('called for a stack trace from a periodic timer', () {
395 return Chain.capture(() {
396 return chainForTrace(inPeriodicTimer, () => throw 'error');
397 }).then((chain) {
398 expect(chain.traces, hasLength(3));
399 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
400 expect(chain.traces[1].frames,
401 contains(frameMember(startsWith('chainForTrace'))));
402 expect(chain.traces[2].frames,
403 contains(frameMember(startsWith('inPeriodicTimer'))));
404 });
405 });
406
407 test('called for a stack trace from a nested series of asynchronous '
408 'operations', () {
409 return Chain.capture(() {
410 return chainForTrace((callback) {
411 inPeriodicTimer(() => inOneShotTimer(() => inMicrotask(callback)));
412 }, () => throw 'error');
413 }).then((chain) {
414 expect(chain.traces, hasLength(5));
415 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
416 expect(chain.traces[1].frames,
417 contains(frameMember(startsWith('chainForTrace'))));
418 expect(chain.traces[2].frames,
419 contains(frameMember(startsWith('inMicrotask'))));
420 expect(chain.traces[3].frames,
421 contains(frameMember(startsWith('inOneShotTimer'))));
422 expect(chain.traces[4].frames,
423 contains(frameMember(startsWith('inPeriodicTimer'))));
424 });
425 });
426
427 test('called for a stack trace from a long future chain', () {
428 return Chain.capture(() {
429 return chainForTrace(inFutureChain, () => throw 'error');
430 }).then((chain) {
431 expect(chain.traces, hasLength(3));
432 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
433 expect(chain.traces[1].frames,
434 contains(frameMember(startsWith('chainForTrace'))));
435 expect(chain.traces[2].frames,
436 contains(frameMember(startsWith('inFutureChain'))));
437 });
438 });
439
440 test('called for an unregistered stack trace returns a chain wrapping that '
441 'trace', () {
442 var trace;
443 var chain = Chain.capture(() {
444 try {
445 throw 'error';
446 } catch (_, stackTrace) {
447 trace = stackTrace;
448 return new Chain.forTrace(stackTrace);
449 }
450 });
451
452 expect(chain.traces, hasLength(1));
453 expect(chain.traces.first.toString(),
454 equals(new Trace.from(trace).toString()));
455 });
456 });
457
458 test('forTrace() outside of capture() returns a chain wrapping the given '
459 'trace', () {
460 var trace;
461 var chain = Chain.capture(() {
462 try {
463 throw 'error';
464 } catch (_, stackTrace) {
465 trace = stackTrace;
466 return new Chain.forTrace(stackTrace);
467 }
468 });
469
470 expect(chain.traces, hasLength(1));
471 expect(chain.traces.first.toString(),
472 equals(new Trace.from(trace).toString()));
473 });
474
475 test('Chain.parse() parses a real Chain', () {
476 return captureFuture(() => inMicrotask(() => throw 'error')).then((chain) {
477 expect(new Chain.parse(chain.toString()).toString(),
478 equals(chain.toString()));
479 });
480 });
481
482 var userSlashCode = p.join('user', 'code.dart');
483 group('Chain.terse', () {
484 test('makes each trace terse', () {
485 var chain = new Chain([
486 new Trace.parse(
487 'dart:core 10:11 Foo.bar\n'
488 'dart:core 10:11 Bar.baz\n'
489 'user/code.dart 10:11 Bang.qux\n'
490 'dart:core 10:11 Zip.zap\n'
491 'dart:core 10:11 Zop.zoop'),
492 new Trace.parse(
493 'user/code.dart 10:11 Bang.qux\n'
494 'dart:core 10:11 Foo.bar\n'
495 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
496 'dart:core 10:11 Zip.zap\n'
497 'user/code.dart 10:11 Zop.zoop')
498 ]);
499
500 expect(chain.terse.toString(), equals(
501 'dart:core Bar.baz\n'
502 '$userSlashCode 10:11 Bang.qux\n'
503 'dart:core Zop.zoop\n'
504 '===== asynchronous gap ===========================\n'
505 '$userSlashCode 10:11 Bang.qux\n'
506 'dart:core Zip.zap\n'
507 '$userSlashCode 10:11 Zop.zoop\n'));
508 });
509
510 test('eliminates internal-only traces', () {
511 var chain = new Chain([
512 new Trace.parse(
513 'user/code.dart 10:11 Foo.bar\n'
514 'dart:core 10:11 Bar.baz'),
515 new Trace.parse(
516 'dart:core 10:11 Foo.bar\n'
517 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
518 'dart:core 10:11 Zip.zap'),
519 new Trace.parse(
520 'user/code.dart 10:11 Foo.bar\n'
521 'dart:core 10:11 Bar.baz')
522 ]);
523
524 expect(chain.terse.toString(), equals(
525 '$userSlashCode 10:11 Foo.bar\n'
526 'dart:core Bar.baz\n'
527 '===== asynchronous gap ===========================\n'
528 '$userSlashCode 10:11 Foo.bar\n'
529 'dart:core Bar.baz\n'));
530 });
531
532 test("doesn't return an empty chain", () {
533 var chain = new Chain([
534 new Trace.parse(
535 'dart:core 10:11 Foo.bar\n'
536 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
537 'dart:core 10:11 Zip.zap'),
538 new Trace.parse(
539 'dart:core 10:11 A.b\n'
540 'package:stack_trace/stack_trace.dart 10:11 C.d\n'
541 'dart:core 10:11 E.f')
542 ]);
543
544 expect(chain.terse.toString(), equals('dart:core E.f\n'));
545 });
546 });
547
548 group('Chain.foldFrames', () {
549 test('folds each trace', () {
550 var chain = new Chain([
551 new Trace.parse(
552 'a.dart 10:11 Foo.bar\n'
553 'a.dart 10:11 Bar.baz\n'
554 'b.dart 10:11 Bang.qux\n'
555 'a.dart 10:11 Zip.zap\n'
556 'a.dart 10:11 Zop.zoop'),
557 new Trace.parse(
558 'a.dart 10:11 Foo.bar\n'
559 'a.dart 10:11 Bar.baz\n'
560 'a.dart 10:11 Bang.qux\n'
561 'a.dart 10:11 Zip.zap\n'
562 'b.dart 10:11 Zop.zoop')
563 ]);
564
565 var folded = chain.foldFrames((frame) => frame.library == 'a.dart');
566 expect(folded.toString(), equals(
567 'a.dart 10:11 Bar.baz\n'
568 'b.dart 10:11 Bang.qux\n'
569 'a.dart 10:11 Zop.zoop\n'
570 '===== asynchronous gap ===========================\n'
571 'a.dart 10:11 Zip.zap\n'
572 'b.dart 10:11 Zop.zoop\n'));
573 });
574
575 test('eliminates completely-folded traces', () {
576 var chain = new Chain([
577 new Trace.parse(
578 'a.dart 10:11 Foo.bar\n'
579 'b.dart 10:11 Bang.qux'),
580 new Trace.parse(
581 'a.dart 10:11 Foo.bar\n'
582 'a.dart 10:11 Bang.qux'),
583 new Trace.parse(
584 'a.dart 10:11 Zip.zap\n'
585 'b.dart 10:11 Zop.zoop')
586 ]);
587
588 var folded = chain.foldFrames((frame) => frame.library == 'a.dart');
589 expect(folded.toString(), equals(
590 'a.dart 10:11 Foo.bar\n'
591 'b.dart 10:11 Bang.qux\n'
592 '===== asynchronous gap ===========================\n'
593 'a.dart 10:11 Zip.zap\n'
594 'b.dart 10:11 Zop.zoop\n'));
595 });
596
597 test("doesn't return an empty trace", () {
598 var chain = new Chain([
599 new Trace.parse(
600 'a.dart 10:11 Foo.bar\n'
601 'a.dart 10:11 Bang.qux')
602 ]);
603
604 var folded = chain.foldFrames((frame) => frame.library == 'a.dart');
605 expect(folded.toString(), equals('a.dart 10:11 Bang.qux\n'));
606 });
607 });
608
609 test('Chain.toTrace eliminates asynchronous gaps', () {
610 var trace = new Chain([
611 new Trace.parse(
612 'user/code.dart 10:11 Foo.bar\n'
613 'dart:core 10:11 Bar.baz'),
614 new Trace.parse(
615 'user/code.dart 10:11 Foo.bar\n'
616 'dart:core 10:11 Bar.baz')
617 ]).toTrace();
618
619 expect(trace.toString(), equals(
620 '$userSlashCode 10:11 Foo.bar\n'
621 'dart:core 10:11 Bar.baz\n'
622 '$userSlashCode 10:11 Foo.bar\n'
623 'dart:core 10:11 Bar.baz\n'));
624 });
625
626 group('Chain.track(Future)', () {
627 test('forwards the future value within Chain.capture()', () {
628 Chain.capture(() {
629 expect(Chain.track(new Future.value('value')),
630 completion(equals('value')));
631
632 var trace = new Trace.current();
633 expect(Chain.track(new Future.error('error', trace))
634 .catchError((e, stackTrace) {
635 expect(e, equals('error'));
636 expect(stackTrace.toString(), equals(trace.toString()));
637 }), completes);
638 });
639 });
640
641 test('forwards the future value outside of Chain.capture()', () {
642 expect(Chain.track(new Future.value('value')),
643 completion(equals('value')));
644
645 var trace = new Trace.current();
646 expect(Chain.track(new Future.error('error', trace))
647 .catchError((e, stackTrace) {
648 expect(e, equals('error'));
649 expect(stackTrace.toString(), equals(trace.toString()));
650 }), completes);
651 });
652 });
653
654 group('Chain.track(Stream)', () {
655 test('forwards stream values within Chain.capture()', () {
656 Chain.capture(() {
657 var controller = new StreamController()
658 ..add(1)..add(2)..add(3)..close();
659 expect(Chain.track(controller.stream).toList(),
660 completion(equals([1, 2, 3])));
661
662 var trace = new Trace.current();
663 controller = new StreamController()..addError('error', trace);
664 expect(Chain.track(controller.stream).toList()
665 .catchError((e, stackTrace) {
666 expect(e, equals('error'));
667 expect(stackTrace.toString(), equals(trace.toString()));
668 }), completes);
669 });
670 });
671
672 test('forwards stream values outside of Chain.capture()', () {
673 Chain.capture(() {
674 var controller = new StreamController()
675 ..add(1)..add(2)..add(3)..close();
676 expect(Chain.track(controller.stream).toList(),
677 completion(equals([1, 2, 3])));
678
679 var trace = new Trace.current();
680 controller = new StreamController()..addError('error', trace);
681 expect(Chain.track(controller.stream).toList()
682 .catchError((e, stackTrace) {
683 expect(e, equals('error'));
684 expect(stackTrace.toString(), equals(trace.toString()));
685 }), completes);
686 });
687 });
688 });
689 }
690
691 /// Runs [callback] in a microtask callback.
692 void inMicrotask(callback()) => scheduleMicrotask(callback);
693
694 /// Runs [callback] in a one-shot timer callback.
695 void inOneShotTimer(callback()) => Timer.run(callback);
696
697 /// Runs [callback] once in a periodic timer callback.
698 void inPeriodicTimer(callback()) {
699 var count = 0;
700 new Timer.periodic(new Duration(milliseconds: 1), (timer) {
701 count++;
702 if (count != 5) return;
703 timer.cancel();
704 callback();
705 });
706 }
707
708 /// Runs [callback] within a long asynchronous Future chain.
709 void inFutureChain(callback()) {
710 new Future(() {})
711 .then((_) => new Future(() {}))
712 .then((_) => new Future(() {}))
713 .then((_) => new Future(() {}))
714 .then((_) => new Future(() {}))
715 .then((_) => callback())
716 .then((_) => new Future(() {}));
717 }
718
719 void inNewFuture(callback()) {
720 new Future(callback);
721 }
722
723 void inSyncFuture(callback()) {
724 new Future.sync(callback);
725 }
726
727 /// Returns a Future that completes to an error using a completer.
728 ///
729 /// If [trace] is passed, it's used as the stack trace for the error.
730 Future completerErrorFuture([StackTrace trace]) {
731 var completer = new Completer();
732 completer.completeError('error', trace);
733 return completer.future;
734 }
735
736 /// Returns a Stream that emits an error using a controller.
737 ///
738 /// If [trace] is passed, it's used as the stack trace for the error.
739 Stream controllerErrorStream([StackTrace trace]) {
740 var controller = new StreamController();
741 controller.addError('error', trace);
742 return controller.stream;
743 }
744
745 /// Runs [callback] within [asyncFn], then converts any errors raised into a
746 /// [Chain] with [Chain.forTrace].
747 Future<Chain> chainForTrace(asyncFn(callback()), callback()) {
748 var completer = new Completer();
749 asyncFn(() {
750 // We use `new Future.value().then(...)` here as opposed to [new Future] or
751 // [new Future.sync] because those methods don't pass the exception through
752 // the zone specification before propagating it, so there's no chance to
753 // attach a chain to its stack trace. See issue 15105.
754 new Future.value().then((_) => callback())
755 .catchError(completer.completeError);
756 });
757 return completer.future
758 .catchError((_, stackTrace) => new Chain.forTrace(stackTrace));
759 }
760
761 /// Runs [callback] in a [Chain.capture] zone and returns a Future that
762 /// completes to the stack chain for an error thrown by [callback].
763 ///
764 /// [callback] is expected to throw the string `"error"`.
765 Future<Chain> captureFuture(callback()) {
766 var completer = new Completer<Chain>();
767 Chain.capture(callback, onError: (error, chain) {
768 expect(error, equals('error'));
769 completer.complete(chain);
770 });
771 return completer.future;
772 }
OLDNEW
« no previous file with comments | « pkg/stack_trace/pubspec.yaml ('k') | pkg/stack_trace/test/frame_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698