Make padding consistent across all stack traces for Chain.toString().
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//963893002
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42c6d8b..aaa409a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@
* Remove the line numbers and specific files in all terse folded frames, not
just those from core libraries.
+* Make padding consistent across all stack traces for `Chain.toString()`.
+
## 1.2.1
* Add `terse` to `LazyTrace.foldFrames()`.
diff --git a/README.md b/README.md
index 24da03c..fe85adb 100644
--- a/README.md
+++ b/README.md
@@ -169,20 +169,20 @@
dart:io/timer_impl.dart 292 _handleTimeout
dart:isolate-patch/isolate_patch.dart 115 _RawReceivePortImpl._handleMessage
===== asynchronous gap ===========================
- dart:async/zone.dart 476 _ZoneDelegate.registerUnaryCallback
- dart:async/zone.dart 666 _CustomizedZone.registerUnaryCallback
- dart:async/future_impl.dart 164 _Future._Future._then
- dart:async/future_impl.dart 187 _Future.then
- test.dart 13:12 scheduleAsync
- test.dart 7:18 main.<fn>
- dart:async/zone.dart 710 _rootRun
- dart:async/zone.dart 440 _ZoneDelegate.run
- dart:async/zone.dart 650 _CustomizedZone.run
- dart:async/zone.dart 944 runZoned
- package:stack_trace/src/chain.dart 93:20 Chain.capture
- test.dart 6:16 main
- dart:isolate-patch/isolate_patch.dart 216 _startIsolate.isolateStartHandler
- dart:isolate-patch/isolate_patch.dart 115 _RawReceivePortImpl._handleMessage
+ dart:async/zone.dart 476 _ZoneDelegate.registerUnaryCallback
+ dart:async/zone.dart 666 _CustomizedZone.registerUnaryCallback
+ dart:async/future_impl.dart 164 _Future._Future._then
+ dart:async/future_impl.dart 187 _Future.then
+ test.dart 13:12 scheduleAsync
+ test.dart 7:18 main.<fn>
+ dart:async/zone.dart 710 _rootRun
+ dart:async/zone.dart 440 _ZoneDelegate.run
+ dart:async/zone.dart 650 _CustomizedZone.run
+ dart:async/zone.dart 944 runZoned
+ package:stack_trace/src/chain.dart 93:20 Chain.capture
+ test.dart 6:16 main
+ dart:isolate-patch/isolate_patch.dart 216 _startIsolate.isolateStartHandler
+ dart:isolate-patch/isolate_patch.dart 115 _RawReceivePortImpl._handleMessage
That's a lot of text! If you look closely, though, you can see that `main` is
listed in the first trace in the chain.
@@ -191,8 +191,8 @@
the frames you don't care about. The terse version of the stack chain above is
this:
- test.dart 17:3 runAsync
- test.dart 13:28 scheduleAsync.<fn>
+ test.dart 17:3 runAsync
+ test.dart 13:28 scheduleAsync.<fn>
===== asynchronous gap ===========================
dart:async _Future.then
test.dart 13:12 scheduleAsync
diff --git a/lib/src/chain.dart b/lib/src/chain.dart
index 9555e76..03dbed6 100644
--- a/lib/src/chain.dart
+++ b/lib/src/chain.dart
@@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:collection';
+import 'dart:math' as math;
import 'frame.dart';
import 'stack_zone_specification.dart';
@@ -15,6 +16,10 @@
/// A function that handles errors in the zone wrapped by [Chain.capture].
typedef void ChainHandler(error, Chain chain);
+/// The line used in the string representation of stack chains to represent
+/// the gap between traces.
+const _gap = '===== asynchronous gap ===========================\n';
+
/// A chain of stack traces.
///
/// A stack chain is a collection of one or more stack traces that collectively
@@ -36,9 +41,6 @@
/// "$stackChain");
/// });
class Chain implements StackTrace {
- /// The line used in the string representation of stack chains to represent
- /// the gap between traces.
- static const _GAP = '===== asynchronous gap ===========================\n';
/// The stack traces that make up this chain.
///
@@ -180,5 +182,19 @@
/// in the chain.
Trace toTrace() => new Trace(flatten(traces.map((trace) => trace.frames)));
- String toString() => traces.join(_GAP);
+ String toString() {
+ // Figure out the longest path so we know how much to pad.
+ var longest = traces.map((trace) {
+ return trace.frames.map((frame) => frame.location.length)
+ .fold(0, math.max);
+ }).fold(0, math.max);
+
+ // Don't call out to [Trace.toString] here because that doesn't ensure that
+ // padding is consistent across all traces.
+ return traces.map((trace) {
+ return trace.frames.map((frame) {
+ return '${padRight(frame.location, longest)} ${frame.member}\n';
+ }).join();
+ }).join(_gap);
+ }
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 24acfbc..1ac6caf 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,7 @@
#
# When the major version is upgraded, you *must* update that version constraint
# in pub to stay in sync with this.
-version: 1.2.2-dev
+version: 1.2.2
author: "Dart Team <misc@dartlang.org>"
homepage: http://github.com/dart-lang/stack_trace
description: >
diff --git a/test/chain_test.dart b/test/chain_test.dart
index cf8a61f..bfe322c 100644
--- a/test/chain_test.dart
+++ b/test/chain_test.dart
@@ -479,6 +479,18 @@
});
});
+ 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'));
+ });
+
var userSlashCode = p.join('user', 'code.dart');
group('Chain.terse', () {
test('makes each trace terse', () {