| Index: packages/stack_trace/test/chain/chain_test.dart
|
| diff --git a/packages/stack_trace/test/chain/chain_test.dart b/packages/stack_trace/test/chain/chain_test.dart
|
| index 0eb3f008723608be3c777c15730504f14dcc79be..407cc2b9c82bdd78950725ecac096df3638c5aac 100644
|
| --- a/packages/stack_trace/test/chain/chain_test.dart
|
| +++ b/packages/stack_trace/test/chain/chain_test.dart
|
| @@ -10,6 +10,8 @@ import 'package:test/test.dart';
|
|
|
| import 'utils.dart';
|
|
|
| +typedef void ChainErrorCallback(stack, Chain chain);
|
| +
|
| void main() {
|
| group('Chain.parse()', () {
|
| test('parses a real Chain', () {
|
| @@ -26,9 +28,9 @@ void main() {
|
| });
|
|
|
| test('parses a chain containing empty traces', () {
|
| - var chain = new Chain.parse(
|
| - '===== asynchronous gap ===========================\n'
|
| - '===== asynchronous gap ===========================\n');
|
| + var chain =
|
| + new Chain.parse('===== asynchronous gap ===========================\n'
|
| + '===== asynchronous gap ===========================\n');
|
| expect(chain.traces, hasLength(3));
|
| expect(chain.traces[0].frames, isEmpty);
|
| expect(chain.traces[1].frames, isEmpty);
|
| @@ -36,92 +38,193 @@ void main() {
|
| });
|
| });
|
|
|
| + group("Chain.capture() with when: false", () {
|
| + test("with no onError doesn't block errors", () {
|
| + expect(Chain.capture(() => new Future.error("oh no"), when: false),
|
| + throwsA("oh no"));
|
| + });
|
| +
|
| + test("with onError blocks errors", () {
|
| + Chain.capture(() {
|
| + return new Future.error("oh no");
|
| + }, onError: expectAsync2((error, chain) {
|
| + expect(error, equals("oh no"));
|
| + expect(chain, new isInstanceOf<Chain>());
|
| + }), when: false);
|
| + });
|
| +
|
| + test("doesn't enable chain-tracking", () {
|
| + return Chain.disable(() {
|
| + return Chain.capture(() {
|
| + var completer = new Completer();
|
| + inMicrotask(() {
|
| + completer.complete(new Chain.current());
|
| + });
|
| +
|
| + return completer.future.then((chain) {
|
| + expect(chain.traces, hasLength(1));
|
| + });
|
| + }, when: false);
|
| + });
|
| + });
|
| + });
|
| +
|
| + group("Chain.disable()", () {
|
| + test("disables chain-tracking", () {
|
| + return Chain.disable(() {
|
| + var completer = new Completer();
|
| + inMicrotask(() => completer.complete(new Chain.current()));
|
| +
|
| + return completer.future.then((chain) {
|
| + expect(chain.traces, hasLength(1));
|
| + });
|
| + });
|
| + });
|
| +
|
| + test("Chain.capture() re-enables chain-tracking", () {
|
| + return Chain.disable(() {
|
| + return Chain.capture(() {
|
| + var completer = new Completer();
|
| + inMicrotask(() => completer.complete(new Chain.current()));
|
| +
|
| + return completer.future.then((chain) {
|
| + expect(chain.traces, hasLength(2));
|
| + });
|
| + });
|
| + });
|
| + });
|
| +
|
| + test("preserves parent zones of the capture zone", () {
|
| + // The outer disable call turns off the test package's chain-tracking.
|
| + return Chain.disable(() {
|
| + return runZoned(() {
|
| + return Chain.capture(() {
|
| + expect(Chain.disable(() => Zone.current[#enabled]), isTrue);
|
| + });
|
| + }, zoneValues: {#enabled: true});
|
| + });
|
| + });
|
| +
|
| + test("preserves child zones of the capture zone", () {
|
| + // The outer disable call turns off the test package's chain-tracking.
|
| + return Chain.disable(() {
|
| + return Chain.capture(() {
|
| + return runZoned(() {
|
| + expect(Chain.disable(() => Zone.current[#enabled]), isTrue);
|
| + }, zoneValues: {#enabled: true});
|
| + });
|
| + });
|
| + });
|
| +
|
| + test("with when: false doesn't disable", () {
|
| + return Chain.capture(() {
|
| + return Chain.disable(() {
|
| + var completer = new Completer();
|
| + inMicrotask(() => completer.complete(new Chain.current()));
|
| +
|
| + return completer.future.then((chain) {
|
| + expect(chain.traces, hasLength(2));
|
| + });
|
| + }, when: false);
|
| + });
|
| + });
|
| + });
|
| +
|
| test("toString() ensures that all traces are aligned", () {
|
| var chain = new Chain([
|
| new Trace.parse('short 10:11 Foo.bar\n'),
|
| new Trace.parse('loooooooooooong 10:11 Zop.zoop')
|
| ]);
|
|
|
| - expect(chain.toString(), equals(
|
| - 'short 10:11 Foo.bar\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - 'loooooooooooong 10:11 Zop.zoop\n'));
|
| + expect(
|
| + chain.toString(),
|
| + equals('short 10:11 Foo.bar\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + 'loooooooooooong 10:11 Zop.zoop\n'));
|
| });
|
|
|
| var userSlashCode = p.join('user', 'code.dart');
|
| group('Chain.terse', () {
|
| test('makes each trace terse', () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'dart:core 10:11 Foo.bar\n'
|
| + new Trace.parse('dart:core 10:11 Foo.bar\n'
|
| 'dart:core 10:11 Bar.baz\n'
|
| 'user/code.dart 10:11 Bang.qux\n'
|
| 'dart:core 10:11 Zip.zap\n'
|
| 'dart:core 10:11 Zop.zoop'),
|
| - new Trace.parse(
|
| - 'user/code.dart 10:11 Bang.qux\n'
|
| + new Trace.parse('user/code.dart 10:11 Bang.qux\n'
|
| 'dart:core 10:11 Foo.bar\n'
|
| 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
|
| 'dart:core 10:11 Zip.zap\n'
|
| 'user/code.dart 10:11 Zop.zoop')
|
| ]);
|
|
|
| - expect(chain.terse.toString(), equals(
|
| - 'dart:core Bar.baz\n'
|
| - '$userSlashCode 10:11 Bang.qux\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - '$userSlashCode 10:11 Bang.qux\n'
|
| - 'dart:core Zip.zap\n'
|
| - '$userSlashCode 10:11 Zop.zoop\n'));
|
| + expect(
|
| + chain.terse.toString(),
|
| + equals('dart:core Bar.baz\n'
|
| + '$userSlashCode 10:11 Bang.qux\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + '$userSlashCode 10:11 Bang.qux\n'
|
| + 'dart:core Zip.zap\n'
|
| + '$userSlashCode 10:11 Zop.zoop\n'));
|
| });
|
|
|
| test('eliminates internal-only traces', () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'user/code.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('user/code.dart 10:11 Foo.bar\n'
|
| 'dart:core 10:11 Bar.baz'),
|
| - new Trace.parse(
|
| - 'dart:core 10:11 Foo.bar\n'
|
| + new Trace.parse('dart:core 10:11 Foo.bar\n'
|
| 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
|
| 'dart:core 10:11 Zip.zap'),
|
| - new Trace.parse(
|
| - 'user/code.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('user/code.dart 10:11 Foo.bar\n'
|
| 'dart:core 10:11 Bar.baz')
|
| ]);
|
|
|
| - expect(chain.terse.toString(), equals(
|
| - '$userSlashCode 10:11 Foo.bar\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - '$userSlashCode 10:11 Foo.bar\n'));
|
| + expect(
|
| + chain.terse.toString(),
|
| + equals('$userSlashCode 10:11 Foo.bar\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + '$userSlashCode 10:11 Foo.bar\n'));
|
| });
|
|
|
| test("doesn't return an empty chain", () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'dart:core 10:11 Foo.bar\n'
|
| + new Trace.parse('dart:core 10:11 Foo.bar\n'
|
| 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
|
| 'dart:core 10:11 Zip.zap'),
|
| - new Trace.parse(
|
| - 'dart:core 10:11 A.b\n'
|
| + new Trace.parse('dart:core 10:11 A.b\n'
|
| 'package:stack_trace/stack_trace.dart 10:11 C.d\n'
|
| 'dart:core 10:11 E.f')
|
| ]);
|
|
|
| expect(chain.terse.toString(), equals('dart:core E.f\n'));
|
| });
|
| +
|
| + // Regression test for #9
|
| + test("doesn't crash on empty traces", () {
|
| + var chain = new Chain([
|
| + new Trace.parse('user/code.dart 10:11 Bang.qux'),
|
| + new Trace([]),
|
| + new Trace.parse('user/code.dart 10:11 Bang.qux')
|
| + ]);
|
| +
|
| + expect(
|
| + chain.terse.toString(),
|
| + equals('$userSlashCode 10:11 Bang.qux\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + '$userSlashCode 10:11 Bang.qux\n'));
|
| + });
|
| });
|
|
|
| group('Chain.foldFrames', () {
|
| test('folds each trace', () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'a.dart 10:11 Bar.baz\n'
|
| 'b.dart 10:11 Bang.qux\n'
|
| 'a.dart 10:11 Zip.zap\n'
|
| 'a.dart 10:11 Zop.zoop'),
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'a.dart 10:11 Bar.baz\n'
|
| 'a.dart 10:11 Bang.qux\n'
|
| 'a.dart 10:11 Zip.zap\n'
|
| @@ -129,68 +232,64 @@ void main() {
|
| ]);
|
|
|
| var folded = chain.foldFrames((frame) => frame.library == 'a.dart');
|
| - expect(folded.toString(), equals(
|
| - 'a.dart 10:11 Bar.baz\n'
|
| - 'b.dart 10:11 Bang.qux\n'
|
| - 'a.dart 10:11 Zop.zoop\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - 'a.dart 10:11 Zip.zap\n'
|
| - 'b.dart 10:11 Zop.zoop\n'));
|
| + expect(
|
| + folded.toString(),
|
| + equals('a.dart 10:11 Bar.baz\n'
|
| + 'b.dart 10:11 Bang.qux\n'
|
| + 'a.dart 10:11 Zop.zoop\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + 'a.dart 10:11 Zip.zap\n'
|
| + 'b.dart 10:11 Zop.zoop\n'));
|
| });
|
|
|
| test('with terse: true, folds core frames as well', () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'dart:async-patch/future.dart 10:11 Zip.zap\n'
|
| 'b.dart 10:11 Bang.qux\n'
|
| 'dart:core 10:11 Bar.baz\n'
|
| 'a.dart 10:11 Zop.zoop'),
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'a.dart 10:11 Bar.baz\n'
|
| 'a.dart 10:11 Bang.qux\n'
|
| 'a.dart 10:11 Zip.zap\n'
|
| 'b.dart 10:11 Zop.zoop')
|
| ]);
|
|
|
| - var folded = chain.foldFrames((frame) => frame.library == 'a.dart',
|
| - terse: true);
|
| - expect(folded.toString(), equals(
|
| - 'dart:async Zip.zap\n'
|
| - 'b.dart 10:11 Bang.qux\n'
|
| - 'a.dart Zop.zoop\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - 'a.dart Zip.zap\n'
|
| - 'b.dart 10:11 Zop.zoop\n'));
|
| + var folded =
|
| + chain.foldFrames((frame) => frame.library == 'a.dart', terse: true);
|
| + expect(
|
| + folded.toString(),
|
| + equals('dart:async Zip.zap\n'
|
| + 'b.dart 10:11 Bang.qux\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + 'a.dart Zip.zap\n'
|
| + 'b.dart 10:11 Zop.zoop\n'));
|
| });
|
|
|
| test('eliminates completely-folded traces', () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'b.dart 10:11 Bang.qux'),
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'a.dart 10:11 Bang.qux'),
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Zip.zap\n'
|
| + new Trace.parse('a.dart 10:11 Zip.zap\n'
|
| 'b.dart 10:11 Zop.zoop')
|
| ]);
|
|
|
| var folded = chain.foldFrames((frame) => frame.library == 'a.dart');
|
| - expect(folded.toString(), equals(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| - 'b.dart 10:11 Bang.qux\n'
|
| - '===== asynchronous gap ===========================\n'
|
| - 'a.dart 10:11 Zip.zap\n'
|
| - 'b.dart 10:11 Zop.zoop\n'));
|
| + expect(
|
| + folded.toString(),
|
| + equals('a.dart 10:11 Foo.bar\n'
|
| + 'b.dart 10:11 Bang.qux\n'
|
| + '===== asynchronous gap ===========================\n'
|
| + 'a.dart 10:11 Zip.zap\n'
|
| + 'b.dart 10:11 Zop.zoop\n'));
|
| });
|
|
|
| test("doesn't return an empty trace", () {
|
| var chain = new Chain([
|
| - new Trace.parse(
|
| - 'a.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('a.dart 10:11 Foo.bar\n'
|
| 'a.dart 10:11 Bang.qux')
|
| ]);
|
|
|
| @@ -201,82 +300,17 @@ void main() {
|
|
|
| test('Chain.toTrace eliminates asynchronous gaps', () {
|
| var trace = new Chain([
|
| - new Trace.parse(
|
| - 'user/code.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('user/code.dart 10:11 Foo.bar\n'
|
| 'dart:core 10:11 Bar.baz'),
|
| - new Trace.parse(
|
| - 'user/code.dart 10:11 Foo.bar\n'
|
| + new Trace.parse('user/code.dart 10:11 Foo.bar\n'
|
| 'dart:core 10:11 Bar.baz')
|
| ]).toTrace();
|
|
|
| - expect(trace.toString(), equals(
|
| - '$userSlashCode 10:11 Foo.bar\n'
|
| - 'dart:core 10:11 Bar.baz\n'
|
| - '$userSlashCode 10:11 Foo.bar\n'
|
| - 'dart:core 10:11 Bar.baz\n'));
|
| - });
|
| -
|
| - group('Chain.track(Future)', () {
|
| - test('forwards the future value within Chain.capture()', () {
|
| - Chain.capture(() {
|
| - expect(Chain.track(new Future.value('value')),
|
| - completion(equals('value')));
|
| -
|
| - var trace = new Trace.current();
|
| - expect(Chain.track(new Future.error('error', trace))
|
| - .catchError((e, stackTrace) {
|
| - expect(e, equals('error'));
|
| - expect(stackTrace.toString(), equals(trace.toString()));
|
| - }), completes);
|
| - });
|
| - });
|
| -
|
| - test('forwards the future value outside of Chain.capture()', () {
|
| - expect(Chain.track(new Future.value('value')),
|
| - completion(equals('value')));
|
| -
|
| - var trace = new Trace.current();
|
| - expect(Chain.track(new Future.error('error', trace))
|
| - .catchError((e, stackTrace) {
|
| - expect(e, equals('error'));
|
| - expect(stackTrace.toString(), equals(trace.toString()));
|
| - }), completes);
|
| - });
|
| - });
|
| -
|
| - group('Chain.track(Stream)', () {
|
| - test('forwards stream values within Chain.capture()', () {
|
| - Chain.capture(() {
|
| - var controller = new StreamController()
|
| - ..add(1)..add(2)..add(3)..close();
|
| - expect(Chain.track(controller.stream).toList(),
|
| - completion(equals([1, 2, 3])));
|
| -
|
| - var trace = new Trace.current();
|
| - controller = new StreamController()..addError('error', trace);
|
| - expect(Chain.track(controller.stream).toList()
|
| - .catchError((e, stackTrace) {
|
| - expect(e, equals('error'));
|
| - expect(stackTrace.toString(), equals(trace.toString()));
|
| - }), completes);
|
| - });
|
| - });
|
| -
|
| - test('forwards stream values outside of Chain.capture()', () {
|
| - Chain.capture(() {
|
| - var controller = new StreamController()
|
| - ..add(1)..add(2)..add(3)..close();
|
| - expect(Chain.track(controller.stream).toList(),
|
| - completion(equals([1, 2, 3])));
|
| -
|
| - var trace = new Trace.current();
|
| - controller = new StreamController()..addError('error', trace);
|
| - expect(Chain.track(controller.stream).toList()
|
| - .catchError((e, stackTrace) {
|
| - expect(e, equals('error'));
|
| - expect(stackTrace.toString(), equals(trace.toString()));
|
| - }), completes);
|
| - });
|
| - });
|
| + expect(
|
| + trace.toString(),
|
| + equals('$userSlashCode 10:11 Foo.bar\n'
|
| + 'dart:core 10:11 Bar.baz\n'
|
| + '$userSlashCode 10:11 Foo.bar\n'
|
| + 'dart:core 10:11 Bar.baz\n'));
|
| });
|
| -}
|
| +}
|
|
|