diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index f5a9ad694..19f18cbaf 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -2,6 +2,7 @@ - Make data types null safe - Update `package:vm_service` to 8.3.0. - Convert JavaScript stack traces in uncaught exceptions to Dart stack traces. +- Fix failure to set breakpoints on windows with a base change in index.html. ## 14.0.2 - Update the min SDK constraint to 2.17.0. diff --git a/dwds/lib/src/loaders/frontend_server_require.dart b/dwds/lib/src/loaders/frontend_server_require.dart index b025749b3..c07d4d83e 100644 --- a/dwds/lib/src/loaders/frontend_server_require.dart +++ b/dwds/lib/src/loaders/frontend_server_require.dart @@ -37,7 +37,10 @@ class FrontendServerRequireStrategyProvider { String _removeBasePath(String path) => path.startsWith(_basePath) ? path.substring(_basePath.length) : null; - String _addBasePath(String serverPath) => p.join(_basePath, serverPath); + String _addBasePath(String serverPath) => + _basePath == null || _basePath.isEmpty + ? relativizePath(serverPath) + : '$_basePath/${relativizePath(serverPath)}'; Future> _moduleProvider( MetadataProvider metadataProvider) async => @@ -55,14 +58,12 @@ class FrontendServerRequireStrategyProvider { _addBasePath((await metadataProvider.moduleToModulePath)[module] ?? ''); Future _sourceMapPathForModule( - MetadataProvider metadataProvider, String module) async { - var path = (await metadataProvider.moduleToSourceMap)[module] ?? ''; - return _addBasePath(relativizePath(path)); - } + MetadataProvider metadataProvider, String module) async => + _addBasePath((await metadataProvider.moduleToSourceMap)[module] ?? ''); String _serverPathForAppUri(String appUri) { if (appUri.startsWith('org-dartlang-app:')) { - return _addBasePath(Uri.parse(appUri).path.substring(1)); + return _addBasePath(Uri.parse(appUri).path); } return null; } diff --git a/dwds/test/build_daemon_evaluate_test.dart b/dwds/test/build_daemon_evaluate_test.dart index 0f94c6dbc..f083b3133 100644 --- a/dwds/test/build_daemon_evaluate_test.dart +++ b/dwds/test/build_daemon_evaluate_test.dart @@ -5,664 +5,28 @@ // @dart = 2.9 @TestOn('vm') -import 'dart:async'; -import 'package:dwds/src/connections/debug_connection.dart'; -import 'package:dwds/src/services/chrome_proxy_service.dart'; -import 'package:path/path.dart' as p; import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; -import 'fixtures/logging.dart'; - -class TestSetup { - static final contextUnsound = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); - - static final contextSound = TestContext( - directory: p.join('..', 'fixtures', '_testPackageSound'), - entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); - - TestContext context; - - TestSetup.sound() : context = contextSound; - - TestSetup.unsound() : context = contextUnsound; - - ChromeProxyService get service => - fetchChromeProxyService(context.debugConnection); - WipConnection get tabConnection => context.tabConnection; -} +import 'evaluate_common.dart'; void main() async { // Enable verbose logging for debugging. var debug = false; - // Change to 'true' to print expression compiler messages to console. - // - // Note: expression compiler runs in an isolate, so its output is not - // currently redirected to a logger. As a result, it will be printed - // regardless of the logger settings. - var verboseCompiler = false; - for (var soundNullSafety in [false, true]) { - var setup = soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); - var context = setup.context; - group('${soundNullSafety ? "sound" : "weak"} null safety', () { - Future onBreakPoint(String isolate, ScriptRef script, - String breakPointId, Future Function() body) async { - Breakpoint bp; - try { - var line = - await context.findBreakpointLine(breakPointId, isolate, script); - bp = await setup.service - .addBreakpointWithScriptUri(isolate, script.uri, line); - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await setup.service.removeBreakpoint(isolate, bp.id); - } - } - } - - group('shared context with evaluation', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - enableExpressionEvaluation: true, - verboseCompiler: verboseCompiler, - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: debug)); - - group('evaluateInFrame', () { - VM vm; - Isolate isolate; - ScriptList scripts; - ScriptRef mainScript; - ScriptRef libraryScript; - ScriptRef testLibraryScript; - ScriptRef testLibraryPartScript; - Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: debug); - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - scripts = await setup.service.getScripts(isolate.id); - - await setup.service.streamListen('Debug'); - stream = setup.service.onEvent('Debug'); - - var testPackage = - soundNullSafety ? '_test_package_sound' : '_test_package'; - var test = soundNullSafety ? '_test_sound' : '_test'; - mainScript = scripts.scripts - .firstWhere((each) => each.uri.contains('main.dart')); - testLibraryScript = scripts.scripts.firstWhere((each) => - each.uri.contains('package:$testPackage/test_library.dart')); - testLibraryPartScript = scripts.scripts.firstWhere((each) => - each.uri.contains('package:$testPackage/src/test_part.dart')); - libraryScript = scripts.scripts.firstWhere( - (each) => each.uri.contains('package:$test/library.dart')); - }); - - tearDown(() async { - await setup.service.resume(isolate.id); - }); - - test('with scope override is not supported yet', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var object = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'MainClass(0)'); - - var param = object as InstanceRef; - - await expectLater( - () => setup.service.evaluateInFrame( - isolate.id, - event.topFrame.index, - 't.toString()', - scope: {'t': param.id}, - ), - throwsRPCError); - }); - }); - - test('local', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'local'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - - test('Type does not show native JavaScript object fields', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - Future getInstance(InstanceRef ref) async { - var result = await setup.service.getObject(isolate.id, ref.id); - expect(result, isA()); - return result as Instance; - } - - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'Type'); - expect(result, isA()); - var instanceRef = result as InstanceRef; - - // Type - var instance = await getInstance(instanceRef); - for (var field in instance.fields) { - var name = field.decl.name; - - // Type. (i.e. Type._type) - instance = await getInstance(field.value as InstanceRef); - for (var field in instance.fields) { - var nestedName = field.decl.name; - - // Type.. (i.e Type._type._subtypeCache) - instance = await getInstance(field.value as InstanceRef); - - expect( - instance, - isA().having( - (instance) => instance.classRef.name, - 'Type.$name.$nestedName: classRef.name', - isNot(isIn([ - 'NativeJavaScriptObject', - 'JavaScriptObject', - ])))); - } - } - }); - }); - - test('field', () async { - await onBreakPoint( - isolate.id, mainScript, 'printFieldFromLibraryClass', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('private field from another library', () async { - await onBreakPoint( - isolate.id, mainScript, 'printFieldFromLibraryClass', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance._field'); - - expect( - result, - isA().having( - (instance) => instance.message, - 'message', - contains("The getter '_field' isn't defined"))); - }); - }); - - test('private field from current library', () async { - await onBreakPoint(isolate.id, mainScript, 'printFieldMain', - () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance._field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('access instance fields after evaluation', () async { - await onBreakPoint( - isolate.id, mainScript, 'printFieldFromLibraryClass', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var instanceRef = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance') as InstanceRef; - - var instance = await setup.service - .getObject(isolate.id, instanceRef.id) as Instance; - - var field = instance.fields.firstWhere( - (BoundField element) => element.decl.name == 'field'); - - expect( - field.value, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('global', () async { - await onBreakPoint(isolate.id, mainScript, 'printGlobal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryValue'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '3')); - }); - }); - - test('call core function', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'print(local)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'null')); - }); - }); - - test('call library function with const param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryFunction(42)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - - test('call library function with local param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame(isolate.id, - event.topFrame.index, 'testLibraryFunction(local)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - - test('call library part function with const param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame(isolate.id, - event.topFrame.index, 'testLibraryPartFunction(42)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - - test('call library part function with local param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame(isolate.id, - event.topFrame.index, 'testLibraryPartFunction(local)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - - test('loop variable', () async { - await onBreakPoint(isolate.id, mainScript, 'printLoopVariable', - () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'item'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('evaluate expression in _test_package/test_library', () async { - await onBreakPoint( - isolate.id, testLibraryScript, 'testLibraryFunction', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'formal'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '23')); - }); - }); - - test('evaluate expression in a class constructor in a library', - () async { - await onBreakPoint( - isolate.id, testLibraryScript, 'testLibraryClassConstructor', - () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'this.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('evaluate expression in a class constructor in a library part', - () async { - await onBreakPoint(isolate.id, testLibraryPartScript, - 'testLibraryPartClassConstructor', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'this.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '1')); - }); - }); - - test('evaluate expression in caller frame', () async { - await onBreakPoint( - isolate.id, testLibraryScript, 'testLibraryFunction', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index + 1, 'local'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '23')); - }); - }); - - test('evaluate expression in a library', () async { - await onBreakPoint(isolate.id, libraryScript, 'Concatenate', - () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'a'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'Hello')); - }); - }); - - test('compilation error', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var error = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'typo'); - - expect( - error, - isA().having((instance) => instance.message, - 'message', contains('CompilationError:'))); - }); - }); - - test('module load error', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - var error = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'd.deferredPrintLocal()'); - - expect( - error, - isA().having((instance) => instance.message, - 'message', contains('LoadModuleError:'))); - }); - }, skip: 'https://github.com/dart-lang/sdk/issues/48587'); - - test('cannot evaluate in unsupported isolate', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - await expectLater( - setup.service - .evaluateInFrame('bad', event.topFrame.index, 'local'), - throwsRPCError); - }); - }); - }); - - group('evaluate', () { - VM vm; - Isolate isolate; - - setUp(() async { - setCurrentLogWriter(debug: debug); - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - - await setup.service.streamListen('Debug'); - }); - - tearDown(() async {}); - - test('with scope override', () async { - var library = isolate.rootLib; - var object = await setup.service - .evaluate(isolate.id, library.id, 'MainClass(0)'); - - var param = object as InstanceRef; - var result = await setup.service.evaluate( - isolate.id, library.id, 't.toString()', - scope: {'t': param.id}); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - '0')); - }); - - test('uses symbol from the same library', () async { - var library = isolate.rootLib; - var result = await setup.service - .evaluate(isolate.id, library.id, 'MainClass(0).toString()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - '0')); - }); - - test('uses symbol from another library', () async { - var library = isolate.rootLib; - var result = await setup.service.evaluate( - isolate.id, library.id, 'TestLibraryClass(0,1).toString()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'field: 0, _field: 1')); - }); - - test('closure call', () async { - var library = isolate.rootLib; - var result = await setup.service - .evaluate(isolate.id, library.id, '(() => 42)()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42')); - }); - }); - }, timeout: const Timeout.factor(2)); - - group('shared context with no evaluation', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - enableExpressionEvaluation: false, - verboseCompiler: verboseCompiler, + group('${soundNullSafety ? "sound" : "weak"} null safety |', () { + for (var basePath in ['', 'abc']) { + group('with base "$basePath" |', () { + testAll( + compilationMode: CompilationMode.buildDaemon, + soundNullSafety: soundNullSafety, + basePath: basePath, + debug: debug, ); }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: debug)); - - group('evaluateInFrame', () { - VM vm; - Isolate isolate; - ScriptList scripts; - ScriptRef mainScript; - Stream stream; - - setUp(() async { - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - scripts = await setup.service.getScripts(isolate.id); - - await setup.service.streamListen('Debug'); - stream = setup.service.onEvent('Debug'); - - mainScript = scripts.scripts - .firstWhere((each) => each.uri.contains('main.dart')); - }); - - tearDown(() async { - await setup.service.resume(isolate.id); - }); - - test('cannot evaluate expression', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint); - - await expectLater( - setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'local'), - throwsRPCError); - }); - }); - }); - }); + } }); } } diff --git a/dwds/test/evaluate_common.dart b/dwds/test/evaluate_common.dart new file mode 100644 index 000000000..af2f0a327 --- /dev/null +++ b/dwds/test/evaluate_common.dart @@ -0,0 +1,619 @@ +// Copyright (c) 2020, 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. + +// @dart = 2.9 + +@TestOn('vm') +import 'dart:async'; + +import 'package:dwds/src/connections/debug_connection.dart'; +import 'package:dwds/src/services/chrome_proxy_service.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; +import 'package:vm_service/vm_service.dart'; +import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; + +import 'fixtures/context.dart'; +import 'fixtures/logging.dart'; + +class TestSetup { + static final contextUnsound = TestContext( + directory: p.join('..', 'fixtures', '_testPackage'), + entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web'); + + static final contextSound = TestContext( + directory: p.join('..', 'fixtures', '_testPackageSound'), + entry: p.join('..', 'fixtures', '_testPackageSound', 'web', 'main.dart'), + path: 'index.html', + pathToServe: 'web'); + + TestContext context; + + TestSetup.sound() : context = contextSound; + + TestSetup.unsound() : context = contextUnsound; + + ChromeProxyService get service => + fetchChromeProxyService(context.debugConnection); + WipConnection get tabConnection => context.tabConnection; +} + +void testAll({ + CompilationMode compilationMode = CompilationMode.buildDaemon, + bool soundNullSafety = false, + String basePath = '', + bool debug = false, +}) { + var setup = soundNullSafety ? TestSetup.sound() : TestSetup.unsound(); + var context = setup.context; + + Future onBreakPoint(String isolate, ScriptRef script, + String breakPointId, Future Function() body) async { + Breakpoint bp; + try { + var line = + await context.findBreakpointLine(breakPointId, isolate, script); + bp = await setup.service + .addBreakpointWithScriptUri(isolate, script.uri, line); + await body(); + } finally { + // Remove breakpoint so it doesn't impact other tests or retries. + if (bp != null) { + await setup.service.removeBreakpoint(isolate, bp.id); + } + } + } + + group('shared context with evaluation', () { + setUpAll(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + enableExpressionEvaluation: true, + verboseCompiler: debug, + basePath: basePath, + ); + }); + + tearDownAll(() async { + await context.tearDown(); + }); + + setUp(() => setCurrentLogWriter(debug: debug)); + + group('evaluateInFrame', () { + VM vm; + Isolate isolate; + ScriptList scripts; + ScriptRef mainScript; + ScriptRef libraryScript; + ScriptRef testLibraryScript; + ScriptRef testLibraryPartScript; + Stream stream; + + setUp(() async { + setCurrentLogWriter(debug: debug); + vm = await setup.service.getVM(); + isolate = await setup.service.getIsolate(vm.isolates.first.id); + scripts = await setup.service.getScripts(isolate.id); + + await setup.service.streamListen('Debug'); + stream = setup.service.onEvent('Debug'); + + var testPackage = + soundNullSafety ? '_test_package_sound' : '_test_package'; + var test = soundNullSafety ? '_test_sound' : '_test'; + mainScript = scripts.scripts + .firstWhere((each) => each.uri.contains('main.dart')); + testLibraryScript = scripts.scripts.firstWhere((each) => + each.uri.contains('package:$testPackage/test_library.dart')); + testLibraryPartScript = scripts.scripts.firstWhere((each) => + each.uri.contains('package:$testPackage/src/test_part.dart')); + libraryScript = scripts.scripts.firstWhere( + (each) => each.uri.contains('package:$test/library.dart')); + }); + + tearDown(() async { + await setup.service.resume(isolate.id); + }); + + test('with scope override is not supported yet', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var object = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'MainClass(0)'); + + var param = object as InstanceRef; + + await expectLater( + () => setup.service.evaluateInFrame( + isolate.id, + event.topFrame.index, + 't.toString()', + scope: {'t': param.id}, + ), + throwsRPCError); + }); + }); + + test('local', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'local'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('Type does not show native JavaScript object fields', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + Future getInstance(InstanceRef ref) async { + var result = await setup.service.getObject(isolate.id, ref.id); + expect(result, isA()); + return result as Instance; + } + + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'Type'); + expect(result, isA()); + var instanceRef = result as InstanceRef; + + // Type + var instance = await getInstance(instanceRef); + for (var field in instance.fields) { + var name = field.decl.name; + + // Type. (i.e. Type._type) + instance = await getInstance(field.value as InstanceRef); + for (var field in instance.fields) { + var nestedName = field.decl.name; + + // Type.. (i.e Type._type._subtypeCache) + instance = await getInstance(field.value as InstanceRef); + + expect( + instance, + isA().having( + (instance) => instance.classRef.name, + 'Type.$name.$nestedName: classRef.name', + isNot(isIn([ + 'NativeJavaScriptObject', + 'JavaScriptObject', + ])))); + } + } + }); + }); + + test('field', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('private field from another library', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance._field'); + + expect( + result, + isA().having((instance) => instance.message, 'message', + contains("The getter '_field' isn't defined"))); + }); + }); + + test('private field from current library', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldMain', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance._field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('access instance fields after evaluation', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var instanceRef = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance') as InstanceRef; + + var instance = await setup.service + .getObject(isolate.id, instanceRef.id) as Instance; + + var field = instance.fields + .firstWhere((BoundField element) => element.decl.name == 'field'); + + expect( + field.value, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('global', () async { + await onBreakPoint(isolate.id, mainScript, 'printGlobal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'testLibraryValue'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '3')); + }); + }); + + test('call core function', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'print(local)'); + + expect( + result, + isA().having((instance) => instance.valueAsString, + 'valueAsString', 'null')); + }); + }); + + test('call library function with const param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'testLibraryFunction(42)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('call library function with local param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'testLibraryFunction(local)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('call library part function with const param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'testLibraryPartFunction(42)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('call library part function with local param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame(isolate.id, + event.topFrame.index, 'testLibraryPartFunction(local)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('loop variable', () async { + await onBreakPoint(isolate.id, mainScript, 'printLoopVariable', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'item'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('evaluate expression in _test_package/test_library', () async { + await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'formal'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '23')); + }); + }); + + test('evaluate expression in a class constructor in a library', () async { + await onBreakPoint( + isolate.id, testLibraryScript, 'testLibraryClassConstructor', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('evaluate expression in a class constructor in a library part', + () async { + await onBreakPoint(isolate.id, testLibraryPartScript, + 'testLibraryPartClassConstructor', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('evaluate expression in caller frame', () async { + await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index + 1, 'local'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '23')); + }); + }); + + test('evaluate expression in a library', () async { + await onBreakPoint(isolate.id, libraryScript, 'Concatenate', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'a'); + + expect( + result, + isA().having((instance) => instance.valueAsString, + 'valueAsString', 'Hello')); + }); + }); + + test('compilation error', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var error = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'typo'); + + expect( + error, + isA().having((instance) => instance.message, 'message', + contains('CompilationError:'))); + }); + }); + + test('module load error', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var error = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'd.deferredPrintLocal()'); + + expect( + error, + isA().having((instance) => instance.message, 'message', + contains('LoadModuleError:'))); + }); + }, skip: 'https://github.com/dart-lang/sdk/issues/48587'); + + test('cannot evaluate in unsupported isolate', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + await expectLater( + setup.service + .evaluateInFrame('bad', event.topFrame.index, 'local'), + throwsRPCError); + }); + }); + }); + + group('evaluate', () { + VM vm; + Isolate isolate; + + setUp(() async { + setCurrentLogWriter(debug: debug); + vm = await setup.service.getVM(); + isolate = await setup.service.getIsolate(vm.isolates.first.id); + + await setup.service.streamListen('Debug'); + }); + + tearDown(() async {}); + + test('with scope override', () async { + var library = isolate.rootLib; + var object = await setup.service + .evaluate(isolate.id, library.id, 'MainClass(0)'); + + var param = object as InstanceRef; + var result = await setup.service.evaluate( + isolate.id, library.id, 't.toString()', + scope: {'t': param.id}); + + expect( + result, + const TypeMatcher().having( + (instance) => instance.valueAsString, 'valueAsString', '0')); + }); + + test('uses symbol from the same library', () async { + var library = isolate.rootLib; + var result = await setup.service + .evaluate(isolate.id, library.id, 'MainClass(0).toString()'); + + expect( + result, + const TypeMatcher().having( + (instance) => instance.valueAsString, 'valueAsString', '0')); + }); + + test('uses symbol from another library', () async { + var library = isolate.rootLib; + var result = await setup.service.evaluate( + isolate.id, library.id, 'TestLibraryClass(0,1).toString()'); + + expect( + result, + const TypeMatcher().having( + (instance) => instance.valueAsString, + 'valueAsString', + 'field: 0, _field: 1')); + }); + + test('closure call', () async { + var library = isolate.rootLib; + var result = await setup.service + .evaluate(isolate.id, library.id, '(() => 42)()'); + + expect( + result, + const TypeMatcher().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + }, timeout: const Timeout.factor(2)); + + group('shared context with no evaluation', () { + setUpAll(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + enableExpressionEvaluation: false, + verboseCompiler: debug, + basePath: basePath, + ); + }); + + tearDownAll(() async { + await context.tearDown(); + }); + + setUp(() => setCurrentLogWriter(debug: debug)); + + group('evaluateInFrame', () { + VM vm; + Isolate isolate; + ScriptList scripts; + ScriptRef mainScript; + Stream stream; + + setUp(() async { + vm = await setup.service.getVM(); + isolate = await setup.service.getIsolate(vm.isolates.first.id); + scripts = await setup.service.getScripts(isolate.id); + + await setup.service.streamListen('Debug'); + stream = setup.service.onEvent('Debug'); + + mainScript = scripts.scripts + .firstWhere((each) => each.uri.contains('main.dart')); + }); + + tearDown(() async { + await setup.service.resume(isolate.id); + }); + + test('cannot evaluate expression', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + await expectLater( + setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'local'), + throwsRPCError); + }); + }); + }); + }); +} diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 79702ad59..6359ec9d0 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -133,6 +133,7 @@ class TestContext { bool enableExpressionEvaluation, bool verboseCompiler, SdkConfigurationProvider sdkConfigurationProvider, + String basePath, }) async { reloadConfiguration ??= ReloadConfiguration.none; serveDevTools ??= false; @@ -146,6 +147,7 @@ class TestContext { verboseCompiler ??= false; sdkConfigurationProvider ??= DefaultSdkConfigurationProvider(); soundNullSafety ??= false; + basePath ??= ''; try { configureLogWriter(); @@ -276,7 +278,7 @@ class TestContext { assetHandler = webRunner.devFS.assetServer.handleRequest; requireStrategy = FrontendServerRequireStrategyProvider( - reloadConfiguration, assetReader, () async => {}, '') + reloadConfiguration, assetReader, () async => {}, basePath) .strategy; buildResults = const Stream.empty(); diff --git a/dwds/test/frontend_server_evaluate_test.dart b/dwds/test/frontend_server_evaluate_test.dart index d9ad7febc..f19587f28 100644 --- a/dwds/test/frontend_server_evaluate_test.dart +++ b/dwds/test/frontend_server_evaluate_test.dart @@ -1,536 +1,35 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2020, 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. // @dart = 2.9 @TestOn('vm') -import 'dart:async'; -import 'package:dwds/src/connections/debug_connection.dart'; -import 'package:dwds/src/services/chrome_proxy_service.dart'; -import 'package:path/path.dart' as p; import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'fixtures/context.dart'; -import 'fixtures/logging.dart'; - -class TestSetup { - static final contextUnsound = TestContext( - directory: p.join('..', 'fixtures', '_testPackage'), - entry: p.join('..', 'fixtures', '_testPackage', 'web', 'main.dart'), - path: 'index.html', - pathToServe: 'web'); - - TestContext context; - - TestSetup.unsound() : context = contextUnsound; - - ChromeProxyService get service => - fetchChromeProxyService(context.debugConnection); - WipConnection get tabConnection => context.tabConnection; -} +import 'evaluate_common.dart'; void main() async { // Enable verbose logging for debugging. var debug = false; - // Change to 'false' to silence frontend server messages. - var verboseCompiler = true; - - var setup = TestSetup.unsound(); - var context = setup.context; - - Future onBreakPoint(String isolate, ScriptRef script, - String breakPointId, Future Function() body) async { - Breakpoint bp; - try { - var line = - await context.findBreakpointLine(breakPointId, isolate, script); - bp = await setup.service - .addBreakpointWithScriptUri(isolate, script.uri, line); - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await setup.service.removeBreakpoint(isolate, bp.id); + for (var soundNullSafety in [false, true]) { + group('${soundNullSafety ? "sound" : "weak"} null safety |', () { + for (var basePath in ['', 'abc']) { + group('with base "$basePath" |', () { + testAll( + compilationMode: CompilationMode.frontendServer, + soundNullSafety: soundNullSafety, + basePath: basePath, + debug: debug, + ); + }, + skip: + soundNullSafety // https://github.com/dart-lang/webdev/issues/1591 + ); } - } - } - - group('shared context with evaluation', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - enableExpressionEvaluation: true, - compilationMode: CompilationMode.frontendServer, - verboseCompiler: verboseCompiler); - }); - - tearDownAll(() async { - await context.tearDown(); }); - - setUp(() async { - setCurrentLogWriter(debug: debug); - }); - - group('evaluateInFrame', () { - VM vm; - Isolate isolate; - ScriptList scripts; - ScriptRef mainScript; - ScriptRef libraryScript; - ScriptRef testLibraryScript; - ScriptRef testLibraryPartScript; - Stream stream; - - setUp(() async { - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - scripts = await setup.service.getScripts(isolate.id); - - await setup.service.streamListen('Debug'); - stream = setup.service.onEvent('Debug'); - - mainScript = scripts.scripts - .firstWhere((each) => each.uri.contains('main.dart')); - testLibraryScript = scripts.scripts.firstWhere((each) => - each.uri.contains('package:_test_package/test_library.dart')); - testLibraryPartScript = scripts.scripts.firstWhere((each) => - each.uri.contains('package:_test_package/src/test_part.dart')); - libraryScript = scripts.scripts.firstWhere( - (each) => each.uri.contains('package:_test/library.dart')); - }); - - tearDown(() async { - await setup.service.resume(isolate.id); - }); - - test('local', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'local'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('local', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'local'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('field', () async { - await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('private field from another library', () async { - await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance._field'); - - expect( - result, - isA().having((instance) => instance.message, 'message', - contains("The getter '_field' isn't defined"))); - }); - }); - - test('private field from current library', () async { - await onBreakPoint(isolate.id, mainScript, 'printFieldMain', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance._field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('access instance fields after evaluation', () async { - await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var instanceRef = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'instance') as InstanceRef; - - var instance = await setup.service - .getObject(isolate.id, instanceRef.id) as Instance; - - var field = instance.fields - .firstWhere((BoundField element) => element.decl.name == 'field'); - - expect( - field.value, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('global', () async { - await onBreakPoint(isolate.id, mainScript, 'printGlobal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryValue'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '3')); - }); - }); - - test('call core function', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'print(local)'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'null')); - }); - }); - - test('call library function with const param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryFunction(42)'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('call library function with local param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryFunction(local)'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('call library part function with const param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'testLibraryPartFunction(42)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('call library part function with local param', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service.evaluateInFrame(isolate.id, - event.topFrame.index, 'testLibraryPartFunction(local)'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - - test('loop variable', () async { - await onBreakPoint(isolate.id, mainScript, 'printLoopVariable', - () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'item'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('evaluate expression in _test_package/test_library', () async { - await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'formal'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '23')); - }); - }); - - test('evaluate expression in a class constructor in a library', () async { - await onBreakPoint( - isolate.id, testLibraryScript, 'testLibraryClassConstructor', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('evaluate expression in a class constructor in a library part', - () async { - await onBreakPoint(isolate.id, testLibraryPartScript, - 'testLibraryPartClassConstructor', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '1')); - }); - }); - - test('evaluate expression in caller frame', () async { - await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', - () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index + 1, 'local'); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, 'valueAsString', '23')); - }); - }); - - test('evaluate expression in a library', () async { - await onBreakPoint(isolate.id, libraryScript, 'Concatenate', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var result = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'a'); - - expect( - result, - isA().having((instance) => instance.valueAsString, - 'valueAsString', 'Hello')); - }); - }); - - test('error', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - var error = await setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'typo'); - - expect( - error, - const TypeMatcher().having( - (instance) => instance.message, - 'message', - contains('CompilationError:'))); - }); - }); - - test('module load error', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - var error = await setup.service.evaluateInFrame( - isolate.id, event.topFrame.index, 'd.deferredPrintLocal()'); - - expect( - error, - isA().having((instance) => instance.message, 'message', - contains('LoadModuleError:'))); - }); - }, skip: 'https://github.com/dart-lang/sdk/issues/48587'); - }); - - group('evaluate', () { - VM vm; - Isolate isolate; - - setUp(() async { - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - - await setup.service.streamListen('Debug'); - }); - - tearDown(() async {}); - - test('uses symbol from the same library', () async { - var library = isolate.rootLib; - var result = await setup.service - .evaluate(isolate.id, library.id, 'MainClass(0).toString()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '0')); - }); - - test('uses symbol from another library', () async { - var library = isolate.rootLib; - var result = await setup.service.evaluate( - isolate.id, library.id, 'TestLibraryClass(0,1).toString()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'field: 0, _field: 1')); - }); - - test('closure call', () async { - var library = isolate.rootLib; - var result = await setup.service - .evaluate(isolate.id, library.id, '(() => 42)()'); - - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, 'valueAsString', '42')); - }); - }); - }); - - group('shared context with no evaluation', () { - setUpAll(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - enableExpressionEvaluation: false, - compilationMode: CompilationMode.frontendServer, - verboseCompiler: verboseCompiler); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() async { - setCurrentLogWriter(debug: debug); - }); - - group('evaluateInFrame', () { - VM vm; - Isolate isolate; - ScriptList scripts; - ScriptRef mainScript; - Stream stream; - - setUp(() async { - vm = await setup.service.getVM(); - isolate = await setup.service.getIsolate(vm.isolates.first.id); - scripts = await setup.service.getScripts(isolate.id); - - await setup.service.streamListen('Debug'); - stream = setup.service.onEvent('Debug'); - - mainScript = scripts.scripts - .firstWhere((each) => each.uri.contains('main.dart')); - }); - - tearDown(() async { - await setup.service.resume(isolate.id); - }); - - test('cannot evaluate expression', () async { - await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { - var event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint); - - await expectLater( - setup.service - .evaluateInFrame(isolate.id, event.topFrame.index, 'local'), - throwsRPCError); - }); - }); - }); - }); + } }