Files
sdk/pkg/dds/test/dap/utils_test.dart
T
Danny Tuppeny 131fe7b525 [dds/dap] Extract URIs from stack traces with regex instead of package_stack_trace
package:stack_trace only parses stack traces in very specific formats and this has caused us to miss some in the past. https://github.com/Dart-Code/Dart-Code/issues/5360 reports that this is also the case when there is any prefix (including `flutter:`) in the output.

Rather than trying to clean up the input to pass to package:stack_trace, this just uses a simple regex to extract the URIs (and optional line/cols) from the line instead.

Fixes https://github.com/Dart-Code/Dart-Code/issues/5360

Change-Id: I13192fb201499f6cee6e28e7aa86d882557c0232
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400380
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Derek Xu <derekx@google.com>
Reviewed-by: Derek Xu <derekx@google.com>
2025-01-06 09:19:24 -08:00

271 lines
8.3 KiB
Dart

// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'package:dds/src/dap/utils.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
main() {
group('isResolvableUri', () {
test('false for files', () async {
expect(isResolvableUri(Uri.parse('file:///foo/bar.dart')), isFalse);
expect(isResolvableUri(Uri.parse('file:///c:/foo/bar.dart')), isFalse);
});
test('false for http(s)', () async {
expect(isResolvableUri(Uri.parse('http://example.org')), isFalse);
expect(isResolvableUri(Uri.parse('https://example.org')), isFalse);
});
test('true for dart:foo', () async {
expect(isResolvableUri(Uri.parse('dart:async')), isTrue);
expect(isResolvableUri(Uri.parse('dart:async/foo')), isTrue);
});
test('true for package:foo', () async {
expect(isResolvableUri(Uri.parse('package:foo')), isTrue);
expect(isResolvableUri(Uri.parse('package:foo/foo')), isTrue);
});
test('false for foo:', () async {
expect(isResolvableUri(Uri.parse('foo:')), isFalse);
});
});
group('parseDartStackFrame', () {
void expectFrames(
List<String> inputs,
Uri uri, [
int? line,
int? col,
]) {
for (var input in inputs) {
var frame = parseDartStackFrame(input);
expect(frame, isNotNull, reason: 'Failed to parse "$input"');
expect(frame!.uri, uri, reason: 'Failed to parse URI from "$input"');
expect(frame.line, line, reason: 'Failed to parse line from "$input"');
expect(frame.column, col, reason: 'Failed to parse col from "$input"');
}
}
test('returns null for non-stack frames', () {
expect(parseDartStackFrame(''), isNull);
expect(parseDartStackFrame('1'), isNull);
expect(parseDartStackFrame('test'), isNull);
expect(parseDartStackFrame('foo.dart2'), isNull);
expect(parseDartStackFrame('foo.darty'), isNull);
expect(parseDartStackFrame('.dart'), isNull);
});
group('package URIs', () {
test('without line/col', () {
expectFrames(
[
'package:foo/bar/baz.dart',
'(package:foo/bar/baz.dart)',
'package:foo/bar/baz.dart',
'#1 package:foo/bar/baz.dart',
'#1 package:foo/bar/baz.dart 1 2 3 4 5',
'#1 A.b (package:foo/bar/baz.dart) 123',
'flutter: #1 A.b (package:foo/bar/baz.dart)',
],
Uri.parse('package:foo/bar/baz.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'(package:foo/bar/baz.dart:1:2)',
'#1 package:foo/bar/baz.dart:1:2',
'#1 package:foo/bar/baz.dart:1:2 1 2 3 4 5',
'#1 A.b (package:foo/bar/baz.dart:1:2) 123',
'flutter: #1 A.b (package:foo/bar/baz.dart:1:2)',
'(package:foo/bar/baz.dart 1:2)',
'#1 package:foo/bar/baz.dart 1:2',
'#1 package:foo/bar/baz.dart 1:2 1 2 3 4 5',
'#1 A.b (package:foo/bar/baz.dart 1:2) 123',
'flutter: #1 A.b (package:foo/bar/baz.dart 1:2)',
],
Uri.parse('package:foo/bar/baz.dart'),
1,
2,
);
});
});
group('dart URIs', () {
test('without line/col', () {
expectFrames(
[
'#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart)',
],
Uri.parse('dart:isolate-patch/isolate_patch.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:1:2)',
'#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart 1:2)',
],
Uri.parse('dart:isolate-patch/isolate_patch.dart'),
1,
2,
);
});
});
group('Posix file URIs', () {
test('without line/col', () {
expectFrames(
[
'#1 A.b (file:///a/b/c/d.dart)',
'flutter: #1 A.b (file:///a/b/c/d.dart)',
],
Uri.parse('file:///a/b/c/d.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'#1 A.b (file:///a/b/c/d.dart:1:2)',
'flutter: #1 A.b (file:///a/b/c/d.dart:1:2)',
'flutter: #1 A.b (file:///a/b/c/d.dart 1:2)',
],
Uri.parse('file:///a/b/c/d.dart'),
1,
2,
);
});
});
group('Posix dart-macro+file URIs', () {
test('without line/col', () {
expectFrames(
[
'#1 A.b (dart-macro+file:///a/b/c/d.dart)',
'flutter: #1 A.b (dart-macro+file:///a/b/c/d.dart)',
],
Uri.parse('dart-macro+file:///a/b/c/d.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'#1 A.b (dart-macro+file:///a/b/c/d.dart:1:2)',
'flutter: #1 A.b (dart-macro+file:///a/b/c/d.dart:1:2)',
],
Uri.parse('dart-macro+file:///a/b/c/d.dart'),
1,
2,
);
});
});
group('Posix relative paths', () {
test('without line/col', () {
expectFrames(
[
'foo a/b/c/d.dart',
'#1 A.b (a/b/c/d.dart)',
'flutter: #1 A.b (a/b/c/d.dart)',
],
Uri.file(path.join(Directory.current.path, 'a/b/c/d.dart')),
);
});
test('with line/col', () {
expectFrames(
[
'foo a/b/c/d.dart:1:2',
'#1 A.b (a/b/c/d.dart:1:2)',
'flutter: #1 A.b (a/b/c/d.dart:1:2)',
'flutter: #1 A.b (a/b/c/d.dart 1:2)',
],
Uri.file(path.join(Directory.current.path, 'a/b/c/d.dart')),
1,
2,
);
});
}, skip: Platform.isWindows);
group('Windows file URIs', () {
test('without line/col', () {
expectFrames(
[
'#1 A.b (file:///a:/b/c/d.dart)',
'flutter: #1 A.b (file:///a:/b/c/d.dart)',
],
Uri.parse('file:///a:/b/c/d.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'#1 A.b (file:///a:/b/c/d.dart:1:2)',
'flutter: #1 A.b (file:///a:/b/c/d.dart:1:2)',
],
Uri.parse('file:///a:/b/c/d.dart'),
1,
2,
);
});
});
group('Windows dart-macro+file URIs', () {
test('without line/col', () {
expectFrames(
[
'#1 A.b (dart-macro+file:///a:/b/c/d.dart)',
'flutter: #1 A.b (dart-macro+file:///a:/b/c/d.dart)',
],
Uri.parse('dart-macro+file:///a:/b/c/d.dart'),
);
});
test('with line/col', () {
expectFrames(
[
'#1 A.b (dart-macro+file:///a:/b/c/d.dart:1:2)',
'flutter: #1 A.b (dart-macro+file:///a:/b/c/d.dart:1:2)',
],
Uri.parse('dart-macro+file:///a:/b/c/d.dart'),
1,
2,
);
});
});
group('Windows relative paths', () {
test('without line/col', () {
expectFrames(
[
r'foo a\b\c\d.dart',
r'#1 A.b (a\b\c\d.dart)',
r'flutter: #1 A.b (a\b\c\d.dart)',
],
Uri.file(path.join(Directory.current.path, 'a/b/c/d.dart')),
);
});
test('with line/col', () {
expectFrames(
[
r'foo a\b\c\d.dart:1:2',
r'#1 A.b (a\b\c\d.dart:1:2)',
r'flutter: #1 A.b (a\b\c\d.dart:1:2)',
r'flutter: #1 A.b (a\b\c\d.dart 1:2)',
],
Uri.file(path.join(Directory.current.path, 'a/b/c/d.dart')),
1,
2,
);
});
}, skip: !Platform.isWindows);
});
}