Add test for stack trace mapping and test expression eval tests using DDC library bundle format (#168017)

The bootstrap script utilizes a DDC utility function that maps paths to
their module name in order for the stack traces to show the Dart paths
and not the JS paths. This gets utilized in some stack tracing
functionalities like StackTrace.current. We should test that the mapping
is correct and we expect the correct stack traces.

These tests should be run with the DDC library bundle format as well, so
refactors them into shared code.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

----

Once we have the CL to emit inlined source maps for the DDC library
bundle format landed, we can fork this test and run it with that format
as well.
This commit is contained in:
Srujan Gaddam 2025-05-12 10:53:07 -07:00 committed by GitHub
parent 00dc13b3a5
commit 2871340407
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 87 additions and 16 deletions

View File

@ -0,0 +1,14 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@Tags(<String>['flutter-test-driver'])
library;
import '../src/common.dart';
import 'test_data/expression_evaluation_web_common.dart';
void main() async {
await testAll(useDDCLibraryBundleFormat: false);
}

View File

@ -0,0 +1,14 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@Tags(<String>['flutter-test-driver'])
library;
import '../src/common.dart';
import 'test_data/expression_evaluation_web_common.dart';
void main() async {
await testAll(useDDCLibraryBundleFormat: true);
}

View File

@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@Tags(<String>['flutter-test-driver'])
library;
import 'package:file/file.dart';
import 'package:vm_service/vm_service.dart';
import '../integration.shard/test_data/basic_project.dart';
import '../integration.shard/test_data/tests_project.dart';
import '../integration.shard/test_driver.dart';
import '../integration.shard/test_utils.dart';
import '../src/common.dart';
import '../../integration.shard/test_data/basic_project.dart';
import '../../integration.shard/test_data/tests_project.dart';
import '../../integration.shard/test_driver.dart';
import '../../integration.shard/test_utils.dart';
import '../../src/common.dart';
void main() {
// Created here as multiple groups use it.
final RegExp stackTraceCurrentRegexp = RegExp(r'\.dart\s+[0-9]+:[0-9]+\s+get current');
Future<void> testAll({required bool useDDCLibraryBundleFormat}) async {
group('Flutter run for web', () {
final BasicProject project = BasicProject();
late Directory tempDir;
@ -42,7 +42,10 @@ void main() {
withDebugger: true,
chrome: true,
expressionEvaluation: expressionEvaluation,
additionalCommandArgs: <String>['--verbose'],
additionalCommandArgs: <String>[
'--verbose',
if (useDDCLibraryBundleFormat) '--web-experimental-hot-reload',
],
);
}
@ -113,6 +116,27 @@ void main() {
await start(expressionEvaluation: true);
await evaluateWebLibraryBooleanFromEnvironmentInLibrary(flutter);
});
testWithoutContext('evaluated expression includes correctly mapped stack trace', () async {
await start(expressionEvaluation: true);
await breakInTopLevelFunction(flutter);
// Test that the call comes from some Dart getter called `current` (the
// location of which will be compiler-specific) and that the lines and
// file name of the current location is correct and reports a Dart path.
await evaluateStackTraceCurrent(flutter, (String stackTrace) {
final Iterable<RegExpMatch> matches = stackTraceCurrentRegexp.allMatches(stackTrace);
if (matches.length != 1) {
return false;
}
int end = matches.first.end;
end = stackTrace.indexOf('package:test/main.dart 24:5', end);
if (end == -1) {
return false;
}
end = stackTrace.indexOf('package:test/main.dart 15:7', end);
return end != -1;
});
});
});
group('Flutter test for web', () {
@ -181,6 +205,20 @@ void main() {
await startPaused(expressionEvaluation: true);
await evaluateWebLibraryBooleanFromEnvironmentInLibrary(flutter);
});
testWithoutContext('evaluated expression includes correctly mapped stack trace', () async {
await startPaused(expressionEvaluation: true);
await breakInMethod(flutter);
await evaluateStackTraceCurrent(flutter, (String stackTrace) {
final Iterable<RegExpMatch> matches = stackTraceCurrentRegexp.allMatches(stackTrace);
if (matches.length != 1) {
return false;
}
int end = matches.first.end;
end = stackTrace.indexOf('test.dart 6:9', end);
return end != -1;
});
});
});
}
@ -246,6 +284,15 @@ Future<void> evaluateWebLibraryBooleanFromEnvironmentInLibrary(FlutterTestDriver
expectInstance(res, InstanceKind.kBool, true.toString());
}
Future<void> evaluateStackTraceCurrent(
FlutterTestDriver flutter,
bool Function(String) matchStackTraces,
) async {
final LibraryRef library = await getRootLibrary(flutter);
final ObjRef res = await flutter.evaluate(library.id!, 'StackTrace.current.toString()');
expectInstance(res, InstanceKind.kString, predicate(matchStackTraces));
}
Future<LibraryRef> getRootLibrary(FlutterTestDriver flutter) async {
// `isolate.rootLib` returns incorrect library, so find the
// entrypoint manually here instead.
@ -255,12 +302,12 @@ Future<LibraryRef> getRootLibrary(FlutterTestDriver flutter) async {
return isolate.libraries!.firstWhere((LibraryRef l) => l.uri!.contains('org-dartlang-app'));
}
void expectInstance(ObjRef result, String kind, String message) {
void expectInstance(ObjRef result, String kind, Object matcher) {
expect(
result,
const TypeMatcher<InstanceRef>()
.having((InstanceRef instance) => instance.kind, 'kind', kind)
.having((InstanceRef instance) => instance.valueAsString, 'valueAsString', message),
.having((InstanceRef instance) => instance.valueAsString, 'valueAsString', matcher),
);
}

View File

@ -13,10 +13,6 @@ import '../../src/common.dart';
import 'hot_reload_index_html_samples.dart';
void main() async {
await testAll(useDDCLibraryBundleFormat: false);
}
Future<void> testAll({required bool useDDCLibraryBundleFormat}) async {
await _testProject(
HotReloadProject(),