Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 1.10.0-nullsafety.3-dev

* Fix bug parsing asynchronous suspension gap markers at the end of stack
traces.

## 1.10.0-nullsafety.2

* Forward fix for a change in SDK type promotion behavior.
Expand Down
6 changes: 5 additions & 1 deletion lib/src/trace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ class Trace implements StackTrace {
static List<Frame> _parseVM(String trace) {
// Ignore [vmChainGap]. This matches the behavior of
// `Chain.parse().toTrace()`.
var lines = trace.trim().replaceAll(vmChainGap, '').split('\n');
var lines = trace
.trim()
.replaceAll(vmChainGap, '')
.split('\n')
.where((line) => line.isNotEmpty);
var frames = lines
.take(lines.length - 1)
.map((line) => Frame.parseVM(line))
Expand Down
2 changes: 1 addition & 1 deletion lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const chainGap = '===== asynchronous gap ===========================\n';

/// The line used in the string representation of VM stack chains to represent
/// the gap between traces.
const vmChainGap = '<asynchronous suspension>\n';
final vmChainGap = RegExp(r'^<asynchronous suspension>\n?$', multiLine: true);

// TODO(nweiz): When cross-platform imports work, use them to set this.
/// Whether we're running in a JS context.
Expand Down
41 changes: 41 additions & 0 deletions test/trace_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,25 @@ void main() {
equals(Uri.parse('https://dart.dev/foo/quux.dart')));
});

test('parses a package:stack_trace stack chain with end gap correctly', () {
var trace =
Trace.parse('https://dart.dev/foo/bar.dart 10:11 Foo.<fn>.bar\n'
'https://dart.dev/foo/baz.dart Foo.<fn>.bar\n'
'https://dart.dev/foo/bang.dart 10:11 Foo.<fn>.bar\n'
'https://dart.dev/foo/quux.dart Foo.<fn>.bar'
'===== asynchronous gap ===========================\n');

expect(trace.frames.length, 4);
expect(trace.frames[0].uri,
equals(Uri.parse('https://dart.dev/foo/bar.dart')));
expect(trace.frames[1].uri,
equals(Uri.parse('https://dart.dev/foo/baz.dart')));
expect(trace.frames[2].uri,
equals(Uri.parse('https://dart.dev/foo/bang.dart')));
expect(trace.frames[3].uri,
equals(Uri.parse('https://dart.dev/foo/quux.dart')));
});

test('parses a real package:stack_trace stack trace correctly', () {
var traceString = Trace.current().toString();
expect(Trace.parse(traceString).toString(), equals(traceString));
Expand All @@ -259,6 +278,28 @@ void main() {
expect(trace.frames, isEmpty);
expect(trace.toString(), equals(''));
});

test('parses trace with async gap correctly', () {
var trace = Trace.parse('#0 bop (file:///pull.dart:42:23)\n'
'<asynchronous suspension>\n'
'#1 twist (dart:the/future.dart:0:2)\n'
'#2 main (dart:my/file.dart:4:6)\n');

expect(trace.frames.length, 3);
expect(trace.frames[0].uri, equals(Uri.parse('file:///pull.dart')));
expect(trace.frames[1].uri, equals(Uri.parse('dart:the/future.dart')));
expect(trace.frames[2].uri, equals(Uri.parse('dart:my/file.dart')));
});

test('parses trace with async gap at end correctly', () {
var trace = Trace.parse('#0 bop (file:///pull.dart:42:23)\n'
'#1 twist (dart:the/future.dart:0:2)\n'
'<asynchronous suspension>\n');

expect(trace.frames.length, 2);
expect(trace.frames[0].uri, equals(Uri.parse('file:///pull.dart')));
expect(trace.frames[1].uri, equals(Uri.parse('dart:the/future.dart')));
});
});

test('.toString() nicely formats the stack trace', () {
Expand Down