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

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

Issue 556363004: Add an error callback to StackZoneSpecification. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months 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') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library chain_test; 5 library chain_test;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:path/path.dart' as p; 9 import 'package:path/path.dart' as p;
10 import 'package:stack_trace/stack_trace.dart'; 10 import 'package:stack_trace/stack_trace.dart';
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // is important; programmers expect stack trace memory consumption to be 86 // is important; programmers expect stack trace memory consumption to be
87 // O(depth of program), not O(length of program). 87 // O(depth of program), not O(length of program).
88 expect(chain.traces, hasLength(2)); 88 expect(chain.traces, hasLength(2));
89 89
90 expect(chain.traces[0].frames.first, frameMember(startsWith('main'))); 90 expect(chain.traces[0].frames.first, frameMember(startsWith('main')));
91 expect(chain.traces[1].frames, 91 expect(chain.traces[1].frames,
92 contains(frameMember(startsWith('inFutureChain')))); 92 contains(frameMember(startsWith('inFutureChain'))));
93 }); 93 });
94 }); 94 });
95 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
96 test('multiple times', () { 127 test('multiple times', () {
97 var completer = new Completer(); 128 var completer = new Completer();
98 var first = true; 129 var first = true;
99 130
100 Chain.capture(() { 131 Chain.capture(() {
101 inMicrotask(() => throw 'first error'); 132 inMicrotask(() => throw 'first error');
102 inPeriodicTimer(() => throw 'second error'); 133 inPeriodicTimer(() => throw 'second error');
103 }, onError: (error, chain) { 134 }, onError: (error, chain) {
104 try { 135 try {
105 if (first) { 136 if (first) {
106 expect(error, equals('first error')); 137 expect(error, equals('first error'));
107 expect(chain.traces[1].frames, 138 expect(chain.traces[1].frames,
108 contains(frameMember(startsWith('inMicrotask')))); 139 contains(frameMember(startsWith('inMicrotask'))));
109 first = false; 140 first = false;
110 } else { 141 } else {
111 expect(error, equals('second error')); 142 expect(error, equals('second error'));
112 expect(chain.traces[1].frames, 143 expect(chain.traces[1].frames,
113 contains(frameMember(startsWith('inPeriodicTimer')))); 144 contains(frameMember(startsWith('inPeriodicTimer'))));
114 completer.complete(); 145 completer.complete();
115 } 146 }
116 } catch (error, stackTrace) { 147 } catch (error, stackTrace) {
117 completer.completeError(error, stackTrace); 148 completer.completeError(error, stackTrace);
118 } 149 }
119 }); 150 });
120 151
121 return completer.future; 152 return completer.future;
122 }); 153 });
123 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
124 test('and relays them to the parent zone', () { 222 test('and relays them to the parent zone', () {
125 var completer = new Completer(); 223 var completer = new Completer();
126 224
127 runZoned(() { 225 runZoned(() {
128 Chain.capture(() { 226 Chain.capture(() {
129 inMicrotask(() => throw 'error'); 227 inMicrotask(() => throw 'error');
130 }, onError: (error, chain) { 228 }, onError: (error, chain) {
131 expect(error, equals('error')); 229 expect(error, equals('error'));
132 expect(chain.traces[1].frames, 230 expect(chain.traces[1].frames,
133 contains(frameMember(startsWith('inMicrotask')))); 231 contains(frameMember(startsWith('inMicrotask'))));
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 ]).toTrace(); 617 ]).toTrace();
520 618
521 expect(trace.toString(), equals( 619 expect(trace.toString(), equals(
522 '$userSlashCode 10:11 Foo.bar\n' 620 '$userSlashCode 10:11 Foo.bar\n'
523 'dart:core 10:11 Bar.baz\n' 621 'dart:core 10:11 Bar.baz\n'
524 '$userSlashCode 10:11 Foo.bar\n' 622 '$userSlashCode 10:11 Foo.bar\n'
525 'dart:core 10:11 Bar.baz\n')); 623 'dart:core 10:11 Bar.baz\n'));
526 }); 624 });
527 625
528 group('Chain.track(Future)', () { 626 group('Chain.track(Future)', () {
529 test('associates the current chain with a manually-reported exception with '
530 'a stack trace', () {
531 var trace = new Trace.current();
532 return captureFuture(() {
533 inMicrotask(() => trackedErrorFuture(trace));
534 }).then((chain) {
535 expect(chain.traces, hasLength(3));
536
537 // The first trace is the trace that was manually reported for the
538 // error.
539 expect(chain.traces.first.toString(), equals(trace.toString()));
540
541 // The second trace is the trace that was captured when [Chain.track]
542 // was called.
543 expect(chain.traces[1].frames.first,
544 frameMember(startsWith('trackedErrorFuture')));
545
546 // The third trace is the automatically-captured trace from when the
547 // microtask was scheduled.
548 expect(chain.traces[2].frames,
549 contains(frameMember(startsWith('inMicrotask'))));
550 });
551 });
552
553 test('associates the current chain with a manually-reported exception with '
554 'no stack trace', () {
555 return captureFuture(() {
556 inMicrotask(() => trackedErrorFuture());
557 }).then((chain) {
558 expect(chain.traces, hasLength(3));
559
560 // The first trace is the one captured by
561 // [StackZoneSpecification.trackFuture], which should contain only
562 // stack_trace and dart: frames.
563 expect(chain.traces.first.frames,
564 everyElement(frameLibrary(isNot(contains('chain_test')))));
565
566 expect(chain.traces[1].frames.first,
567 frameMember(startsWith('trackedErrorFuture')));
568 expect(chain.traces[2].frames,
569 contains(frameMember(startsWith('inMicrotask'))));
570 });
571 });
572
573 test('forwards the future value within Chain.capture()', () { 627 test('forwards the future value within Chain.capture()', () {
574 Chain.capture(() { 628 Chain.capture(() {
575 expect(Chain.track(new Future.value('value')), 629 expect(Chain.track(new Future.value('value')),
576 completion(equals('value'))); 630 completion(equals('value')));
577 631
578 var trace = new Trace.current(); 632 var trace = new Trace.current();
579 expect(Chain.track(new Future.error('error', trace)) 633 expect(Chain.track(new Future.error('error', trace))
580 .catchError((e, stackTrace) { 634 .catchError((e, stackTrace) {
581 expect(e, equals('error')); 635 expect(e, equals('error'));
582 expect(stackTrace.toString(), equals(trace.toString())); 636 expect(stackTrace.toString(), equals(trace.toString()));
583 }), completes); 637 }), completes);
584 }); 638 });
585 }); 639 });
586 640
587 test('forwards the future value outside of Chain.capture()', () { 641 test('forwards the future value outside of Chain.capture()', () {
588 expect(Chain.track(new Future.value('value')), 642 expect(Chain.track(new Future.value('value')),
589 completion(equals('value'))); 643 completion(equals('value')));
590 644
591 var trace = new Trace.current(); 645 var trace = new Trace.current();
592 expect(Chain.track(new Future.error('error', trace)) 646 expect(Chain.track(new Future.error('error', trace))
593 .catchError((e, stackTrace) { 647 .catchError((e, stackTrace) {
594 expect(e, equals('error')); 648 expect(e, equals('error'));
595 expect(stackTrace.toString(), equals(trace.toString())); 649 expect(stackTrace.toString(), equals(trace.toString()));
596 }), completes); 650 }), completes);
597 }); 651 });
598 }); 652 });
599 653
600 group('Chain.track(Stream)', () { 654 group('Chain.track(Stream)', () {
601 test('associates the current chain with a manually-reported exception with '
602 'a stack trace', () {
603 var trace = new Trace.current();
604 return captureFuture(() {
605 inMicrotask(() => trackedErrorStream(trace).listen(null));
606 }).then((chain) {
607 expect(chain.traces, hasLength(3));
608 expect(chain.traces.first.toString(), equals(trace.toString()));
609 expect(chain.traces[1].frames.first,
610 frameMember(startsWith('trackedErrorStream')));
611 expect(chain.traces[2].frames,
612 contains(frameMember(startsWith('inMicrotask'))));
613 });
614 });
615
616 test('associates the current chain with a manually-reported exception with '
617 'no stack trace', () {
618 return captureFuture(() {
619 inMicrotask(() => trackedErrorStream().listen(null));
620 }).then((chain) {
621 expect(chain.traces, hasLength(3));
622 expect(chain.traces.first.frames,
623 everyElement(frameLibrary(isNot(contains('chain_test')))));
624 expect(chain.traces[1].frames.first,
625 frameMember(startsWith('trackedErrorStream')));
626 expect(chain.traces[2].frames,
627 contains(frameMember(startsWith('inMicrotask'))));
628 });
629 });
630
631 test('forwards stream values within Chain.capture()', () { 655 test('forwards stream values within Chain.capture()', () {
632 Chain.capture(() { 656 Chain.capture(() {
633 var controller = new StreamController() 657 var controller = new StreamController()
634 ..add(1)..add(2)..add(3)..close(); 658 ..add(1)..add(2)..add(3)..close();
635 expect(Chain.track(controller.stream).toList(), 659 expect(Chain.track(controller.stream).toList(),
636 completion(equals([1, 2, 3]))); 660 completion(equals([1, 2, 3])));
637 661
638 var trace = new Trace.current(); 662 var trace = new Trace.current();
639 controller = new StreamController()..addError('error', trace); 663 controller = new StreamController()..addError('error', trace);
640 expect(Chain.track(controller.stream).toList() 664 expect(Chain.track(controller.stream).toList()
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 void inFutureChain(callback()) { 709 void inFutureChain(callback()) {
686 new Future(() {}) 710 new Future(() {})
687 .then((_) => new Future(() {})) 711 .then((_) => new Future(() {}))
688 .then((_) => new Future(() {})) 712 .then((_) => new Future(() {}))
689 .then((_) => new Future(() {})) 713 .then((_) => new Future(() {}))
690 .then((_) => new Future(() {})) 714 .then((_) => new Future(() {}))
691 .then((_) => callback()) 715 .then((_) => callback())
692 .then((_) => new Future(() {})); 716 .then((_) => new Future(() {}));
693 } 717 }
694 718
695 /// Returns a Future that completes to an error and is wrapped in [Chain.track]. 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.
696 /// 728 ///
697 /// If [trace] is passed, it's used as the stack trace for the error. 729 /// If [trace] is passed, it's used as the stack trace for the error.
698 Future trackedErrorFuture([StackTrace trace]) { 730 Future completerErrorFuture([StackTrace trace]) {
699 var completer = new Completer(); 731 var completer = new Completer();
700 completer.completeError('error', trace); 732 completer.completeError('error', trace);
701 return Chain.track(completer.future); 733 return completer.future;
702 } 734 }
703 735
704 /// Returns a Stream that emits an error and is wrapped in [Chain.track]. 736 /// Returns a Stream that emits an error using a controller.
705 /// 737 ///
706 /// If [trace] is passed, it's used as the stack trace for the error. 738 /// If [trace] is passed, it's used as the stack trace for the error.
707 Stream trackedErrorStream([StackTrace trace]) { 739 Stream controllerErrorStream([StackTrace trace]) {
708 var controller = new StreamController(); 740 var controller = new StreamController();
709 controller.addError('error', trace); 741 controller.addError('error', trace);
710 return Chain.track(controller.stream); 742 return controller.stream;
711 } 743 }
712 744
713 /// Runs [callback] within [asyncFn], then converts any errors raised into a 745 /// Runs [callback] within [asyncFn], then converts any errors raised into a
714 /// [Chain] with [Chain.forTrace]. 746 /// [Chain] with [Chain.forTrace].
715 Future<Chain> chainForTrace(asyncFn(callback()), callback()) { 747 Future<Chain> chainForTrace(asyncFn(callback()), callback()) {
716 var completer = new Completer(); 748 var completer = new Completer();
717 asyncFn(() { 749 asyncFn(() {
718 // We use `new Future.value().then(...)` here as opposed to [new Future] or 750 // We use `new Future.value().then(...)` here as opposed to [new Future] or
719 // [new Future.sync] because those methods don't pass the exception through 751 // [new Future.sync] because those methods don't pass the exception through
720 // the zone specification before propagating it, so there's no chance to 752 // the zone specification before propagating it, so there's no chance to
(...skipping 10 matching lines...) Expand all
731 /// 763 ///
732 /// [callback] is expected to throw the string `"error"`. 764 /// [callback] is expected to throw the string `"error"`.
733 Future<Chain> captureFuture(callback()) { 765 Future<Chain> captureFuture(callback()) {
734 var completer = new Completer<Chain>(); 766 var completer = new Completer<Chain>();
735 Chain.capture(callback, onError: (error, chain) { 767 Chain.capture(callback, onError: (error, chain) {
736 expect(error, equals('error')); 768 expect(error, equals('error'));
737 completer.complete(chain); 769 completer.complete(chain);
738 }); 770 });
739 return completer.future; 771 return completer.future;
740 } 772 }
OLDNEW
« no previous file with comments | « pkg/stack_trace/pubspec.yaml ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698