|  | // 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 'package:dev_compiler/src/compiler/module_builder.dart' | 
|  | show ModuleFormat; | 
|  | import 'package:test/test.dart'; | 
|  |  | 
|  | import '../shared_test_options.dart'; | 
|  | import 'expression_compiler_e2e_suite.dart'; | 
|  |  | 
|  | void main(List<String> args) async { | 
|  | await runAllTests(args); | 
|  | } | 
|  |  | 
|  | Future<void> runAllTests(List<String> args) async { | 
|  | var driver = await ExpressionEvaluationTestDriver.init(); | 
|  | tearDownAll(() async { | 
|  | await driver.finish(); | 
|  | }); | 
|  | group('(AMD module system)', () { | 
|  | var setup = SetupCompilerOptions( | 
|  | moduleFormat: ModuleFormat.amd, args: args, enableExperiments: []); | 
|  | runSharedTests(setup, driver); | 
|  | }); | 
|  | group('(DDC module system)', () { | 
|  | final setup = SetupCompilerOptions( | 
|  | moduleFormat: ModuleFormat.ddc, args: args, enableExperiments: []); | 
|  | runSharedTests(setup, driver); | 
|  | }); | 
|  | } | 
|  |  | 
|  | const simpleClassSource = ''' | 
|  | import 'dart:js_interop'; | 
|  |  | 
|  | @JS() | 
|  | external void eval(String code); | 
|  |  | 
|  | @JS() | 
|  | external JSObject? catchError(JSFunction f); | 
|  |  | 
|  | int get globalField { print('globalField access!'); return 0; } | 
|  | late final int globalLateFinalField; | 
|  |  | 
|  | class BaseClass<T extends num> { | 
|  | static const int staticConstField = 0; | 
|  | static int staticField = 1; | 
|  | static int _staticField = 2; | 
|  | static int _unusedStaticField = 3; | 
|  | int field; | 
|  | T genericField; | 
|  |  | 
|  | int _field; | 
|  | int _unusedField = 4; | 
|  |  | 
|  | late final int lateFinalField; | 
|  |  | 
|  | int get getter => 6; | 
|  | int get _privateGetter => 7; | 
|  |  | 
|  | void Function() functionField = staticMethod; | 
|  | BaseClass? nullableField; | 
|  | AnotherClass nonNullableField = AnotherClass(); | 
|  |  | 
|  | Ext get extensionTypeGetter => Ext(AnotherClass()); | 
|  | Ext get _privateExtensionTypeGetter => Ext(AnotherClass()); | 
|  | ExtString extensionTypeField = ExtString('hello'); | 
|  | ExtString _privateExtensionTypeField = ExtString('hello'); | 
|  | static const ExtDuration staticConstExtensionTypeField = | 
|  | const ExtDuration(Duration.zero); | 
|  | static ExtDuration staticExtensionTypeField = ExtDuration(Duration.zero); | 
|  | static final ExtDuration staticFinalExtensionTypeField = | 
|  | ExtDuration(Duration.zero); | 
|  |  | 
|  | BaseClass(this.field, this._field) : genericField = 0 as T { | 
|  | int y = 1; | 
|  | lateFinalField = 35; | 
|  | } | 
|  |  | 
|  | BaseClass.named(this.field): _field = 42, genericField = 0 as T; | 
|  |  | 
|  | BaseClass.redirecting(int x) : this(x, 99); | 
|  |  | 
|  | factory BaseClass.factory() => BaseClass(42, 0); | 
|  |  | 
|  | void _privateMethod() {} | 
|  |  | 
|  | void method() {} | 
|  |  | 
|  | static void staticMethod() {} | 
|  | } | 
|  |  | 
|  | class DerivedClass extends BaseClass { | 
|  | static const int _newStaticConstPrivateField = -3; | 
|  | final int _newPrivateField = 0; | 
|  | final int newPublicField = 1; | 
|  |  | 
|  | DerivedClass(int field, int field2): super(field, field2); | 
|  | int stringLength(String input) => input.length; | 
|  | } | 
|  |  | 
|  | DerivedClass globalFunction(int a, int b) { | 
|  | return DerivedClass(a, b); | 
|  | } | 
|  |  | 
|  | class AnotherClass { | 
|  | int a = 0; | 
|  | } | 
|  |  | 
|  | extension type Ext(AnotherClass _) {} | 
|  |  | 
|  | extension type ExtString(String _) {} | 
|  |  | 
|  | extension type const ExtDuration(Duration _) {} | 
|  |  | 
|  | main() { | 
|  | eval(\'\'\' | 
|  | globalThis.catchError = function (f) { | 
|  | try { | 
|  | f(); | 
|  | } catch (e) { | 
|  | return e; | 
|  | } | 
|  | return null; | 
|  | }; | 
|  | \'\'\'); | 
|  |  | 
|  | int x = 15; | 
|  | var derived = DerivedClass(1, 3); | 
|  | var base = BaseClass<int>(5, 6); | 
|  | var set = <String>{ 'a', 'b', 'c' }; | 
|  | var list = <int>[1, 2, 3]; | 
|  | var map = <String, int>{'a': 1, 'b': 2}; | 
|  | var stream = Stream.fromIterable([1, 2, 3]); | 
|  | var record = (0, 2, name: 'cat'); | 
|  | var object = Object(); | 
|  | var globalMethod = globalFunction; | 
|  | var staticMethod = BaseClass.staticMethod; | 
|  |  | 
|  | var xType = x.runtimeType; | 
|  | var baseType = base.runtimeType; | 
|  | var baseTypeType = baseType.runtimeType; | 
|  | var setType = set.runtimeType; | 
|  | var listType = list.runtimeType; | 
|  | var mapType = map.runtimeType; | 
|  | var recordType = record.runtimeType; | 
|  |  | 
|  | // We want to test the type representation of the thrown error. However, we | 
|  | // can't do this in Dart as the `catch` block unwraps the error. Instead, use | 
|  | // interop to catch the JS wrapped error and return that directly. | 
|  | var error = catchError((() { | 
|  | throw 'Throwing Dart error that should be wrapped with DartError.'; | 
|  | } as void Function()).toJS); | 
|  |  | 
|  | // Breakpoint: BP | 
|  | print('foo'); | 
|  | } | 
|  | '''; | 
|  |  | 
|  | void runSharedTests( | 
|  | SetupCompilerOptions setup, ExpressionEvaluationTestDriver driver) { | 
|  | group('Runtime debugging API after loading sources but before running main |', | 
|  | () { | 
|  | var source = simpleClassSource; | 
|  |  | 
|  | // Set up and tear down after every test so that the bootstrapper script is | 
|  | // re-run every time, therefore triggering the `OnScheduleMain` breakpoint. | 
|  | setUp(() async { | 
|  | await driver.initSource(setup, source); | 
|  | }); | 
|  |  | 
|  | tearDown(() async { | 
|  | await driver.cleanupTest(); | 
|  | }); | 
|  |  | 
|  | test('getClassesInLibrary', () async { | 
|  | var getClasses = setup.emitLibraryBundle | 
|  | ? 'getClassesInLibrary' | 
|  | : 'getLibraryMetadata'; | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'OnScheduleMain', | 
|  | // Query a user definition to test if it's initialized. | 
|  | expression: 'dart.$getClasses("package:eval_test/test.dart")', | 
|  | expectedResult: ['BaseClass', 'DerivedClass', 'AnotherClass'], | 
|  | ); | 
|  | }); | 
|  |  | 
|  | test('getClassMetadata in non-SDK library', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'OnScheduleMain', | 
|  | // Query a user definition to test if it's initialized. | 
|  | expression: | 
|  | 'dart.getClassMetadata("package:eval_test/test.dart", "DerivedClass")', | 
|  | expectedResult: { | 
|  | 'className': 'DerivedClass', | 
|  | 'superClassName': 'BaseClass', | 
|  | 'superClassLibraryId': 'package:eval_test/test.dart', | 
|  | 'fields': { | 
|  | 'newPublicField': { | 
|  | 'isFinal': true, | 
|  | 'className': 'int', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | '_newPrivateField': { | 
|  | 'isFinal': true, | 
|  | 'className': 'int', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | '_newStaticConstPrivateField': {'isStatic': true}, | 
|  | }, | 
|  | 'methods': { | 
|  | 'stringLength': {}, | 
|  | 'lateFinalField': {'isGetter': true}, | 
|  | 'getter': {'isGetter': true}, | 
|  | '_privateGetter': {'isGetter': true}, | 
|  | 'factory': {'isStatic': true}, | 
|  | 'staticMethod': {'isStatic': true}, | 
|  | 'extensionTypeGetter': {'isGetter': true}, | 
|  | '_privateExtensionTypeGetter': {'isGetter': true}, | 
|  | }, | 
|  | }); | 
|  | }); | 
|  | }, | 
|  | // DDC module format doesn't guarantee that libraries are initialized when | 
|  | // using debugging APIs before main is started. | 
|  | skip: setup.moduleFormat == ModuleFormat.ddc && !setup.canaryFeatures); | 
|  |  | 
|  | group('Runtime debugging API |', () { | 
|  | var source = simpleClassSource; | 
|  |  | 
|  | setUpAll(() async { | 
|  | await driver.initSource(setup, source); | 
|  | }); | 
|  |  | 
|  | tearDownAll(() async { | 
|  | await driver.cleanupTest(); | 
|  | }); | 
|  |  | 
|  | test('getClassesInLibrary', () async { | 
|  | var getClasses = setup.emitLibraryBundle | 
|  | ? 'getClassesInLibrary' | 
|  | : 'getLibraryMetadata'; | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.$getClasses("package:eval_test/test.dart")', | 
|  | expectedResult: ['BaseClass', 'DerivedClass', 'AnotherClass'], | 
|  | ); | 
|  | }); | 
|  |  | 
|  | test('getClassMetadata (object)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getClassMetadata("dart:core", "Object")', | 
|  | expectedResult: { | 
|  | 'className': 'Object', | 
|  | 'fields': {}, | 
|  | 'methods': { | 
|  | '_equals': {}, | 
|  | 'toString': {}, | 
|  | 'noSuchMethod': {}, | 
|  | 'hashCode': {'isGetter': true}, | 
|  | 'runtimeType': {'isGetter': true}, | 
|  | 'hash': {'isStatic': true}, | 
|  | 'hashAll': {'isStatic': true}, | 
|  | 'hashAllUnordered': {'isStatic': true}, | 
|  | } | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getClassMetadata (base class)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: | 
|  | 'dart.getClassMetadata("package:eval_test/test.dart", "BaseClass", base)', | 
|  | expectedResult: { | 
|  | 'className': 'BaseClass', | 
|  | 'superClassName': 'Object', | 
|  | 'superClassLibraryId': 'dart:core', | 
|  | 'fields': { | 
|  | 'field': {'className': 'int', 'classLibraryId': 'dart:core'}, | 
|  | 'functionField': {'className': '() => void'}, | 
|  | 'nullableField': { | 
|  | 'className': 'BaseClass<num>?', | 
|  | 'classLibraryId': 'package:eval_test/test.dart', | 
|  | }, | 
|  | 'nonNullableField': { | 
|  | 'className': 'AnotherClass', | 
|  | 'classLibraryId': 'package:eval_test/test.dart', | 
|  | }, | 
|  | '_field': {'className': 'int', 'classLibraryId': 'dart:core'}, | 
|  | 'genericField': {'className': 'int'}, | 
|  | '_unusedField': { | 
|  | 'className': 'int', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | 'lateFinalField': { | 
|  | 'className': 'int?', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | 'staticConstField': {'isStatic': true}, | 
|  | 'staticField': {'isStatic': true}, | 
|  | '_staticField': {'isStatic': true}, | 
|  | '_unusedStaticField': {'isStatic': true}, | 
|  | // NOTE: Fields typed as an extension type appear as their static | 
|  | // erased type for now. This isn't necessarily the runtime type | 
|  | // of the value either. | 
|  | 'extensionTypeField': { | 
|  | 'className': 'String', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | '_privateExtensionTypeField': { | 
|  | 'className': 'String', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | 'staticConstExtensionTypeField': {'isStatic': true}, | 
|  | 'staticExtensionTypeField': {'isStatic': true}, | 
|  | 'staticFinalExtensionTypeField': {'isStatic': true}, | 
|  | }, | 
|  | 'methods': { | 
|  | 'method': {}, | 
|  | '_privateMethod': {}, | 
|  | 'lateFinalField': {'isGetter': true}, | 
|  | 'getter': {'isGetter': true}, | 
|  | '_privateGetter': {'isGetter': true}, | 
|  | 'factory': {'isStatic': true}, | 
|  | 'staticMethod': {'isStatic': true}, | 
|  | 'extensionTypeGetter': {'isGetter': true}, | 
|  | '_privateExtensionTypeGetter': {'isGetter': true}, | 
|  | }, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getClassMetadata (derived class)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: | 
|  | 'dart.getClassMetadata("package:eval_test/test.dart", "DerivedClass")', | 
|  | expectedResult: { | 
|  | 'className': 'DerivedClass', | 
|  | 'superClassName': 'BaseClass', | 
|  | 'superClassLibraryId': 'package:eval_test/test.dart', | 
|  | 'fields': { | 
|  | 'newPublicField': { | 
|  | 'isFinal': true, | 
|  | 'className': 'int', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | '_newPrivateField': { | 
|  | 'isFinal': true, | 
|  | 'className': 'int', | 
|  | 'classLibraryId': 'dart:core', | 
|  | }, | 
|  | '_newStaticConstPrivateField': {'isStatic': true}, | 
|  | }, | 
|  | 'methods': { | 
|  | 'stringLength': {}, | 
|  | 'lateFinalField': {'isGetter': true}, | 
|  | 'getter': {'isGetter': true}, | 
|  | '_privateGetter': {'isGetter': true}, | 
|  | 'factory': {'isStatic': true}, | 
|  | 'staticMethod': {'isStatic': true}, | 
|  | 'extensionTypeGetter': {'isGetter': true}, | 
|  | '_privateExtensionTypeGetter': {'isGetter': true}, | 
|  | }, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getClassMetadata (Record)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getClassMetadata("dart:core", "Record")', | 
|  | expectedResult: { | 
|  | 'className': 'Record', | 
|  | 'superClassName': 'Object', | 
|  | 'superClassLibraryId': 'dart:core', | 
|  | 'fields': {}, | 
|  | 'methods': { | 
|  | '_equals': {}, | 
|  | 'toString': {}, | 
|  | 'noSuchMethod': {}, | 
|  | 'hashCode': {'isGetter': true}, | 
|  | 'runtimeType': {'isGetter': true}, | 
|  | 'hash': {'isStatic': true}, | 
|  | 'hashAll': {'isStatic': true}, | 
|  | 'hashAllUnordered': {'isStatic': true}, | 
|  | } | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (int)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(x)', | 
|  | expectedResult: {}); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (object)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(object)', | 
|  | expectedResult: { | 
|  | 'className': 'Object', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'object', | 
|  | 'length': 0, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (object of derived class)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(base)', | 
|  | expectedResult: { | 
|  | 'className': 'BaseClass<int>', | 
|  | 'libraryId': 'package:eval_test/test.dart', | 
|  | 'runtimeKind': 'object', | 
|  | 'length': 10, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Set)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(set)', | 
|  | expectedResult: { | 
|  | 'className': 'LinkedSet<String>', | 
|  | 'libraryId': 'dart:_js_helper', | 
|  | 'runtimeKind': 'set', | 
|  | 'length': 3, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (List)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(list)', | 
|  | expectedResult: { | 
|  | 'className': 'JSArray<int>', | 
|  | 'libraryId': 'dart:_interceptors', | 
|  | 'runtimeKind': 'list', | 
|  | 'length': 3, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Map)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(map)', | 
|  | expectedResult: { | 
|  | 'className': 'IdentityMap<String, int>', | 
|  | 'libraryId': 'dart:_js_helper', | 
|  | 'runtimeKind': 'map', | 
|  | 'length': 2, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Stream)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(stream)', | 
|  | expectedResult: { | 
|  | 'className': '_MultiStream<int>', | 
|  | 'libraryId': 'dart:async', | 
|  | 'runtimeKind': 'object', | 
|  | 'length': 2, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Record)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(record)', | 
|  | expectedResult: { | 
|  | 'className': 'Record', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'record', | 
|  | 'length': 3, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (LegacyJavaScriptObject)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata({})', | 
|  | expectedResult: { | 
|  | 'className': 'LegacyJavaScriptObject', | 
|  | 'libraryId': 'dart:_interceptors', | 
|  | 'runtimeKind': 'nativeObject', | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (NativeError)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(new Error())', | 
|  | expectedResult: { | 
|  | 'className': 'NativeError', | 
|  | 'libraryId': 'dart:_interceptors', | 
|  | 'runtimeKind': 'nativeError', | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (DartError)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(error)', | 
|  | expectedResult: { | 
|  | 'className': 'NativeError', | 
|  | 'libraryId': 'dart:_interceptors', | 
|  | 'runtimeKind': 'nativeError', | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('typeName (int type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'xType.toString()', | 
|  | ); | 
|  | expect(typeName, 'int'); | 
|  | }); | 
|  |  | 
|  | test('typeName (base type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'baseType.toString()', | 
|  | ); | 
|  | expect(typeName, 'BaseClass<int>'); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (int type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'xType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(xType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (base type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'baseType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(baseType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'baseTypeType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(baseTypeType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Set type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'setType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(setType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (List type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'listType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(listType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Map type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'mapType.toString()', | 
|  | ); | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(mapType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'type', | 
|  | 'typeName': typeName, | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getObjectMetadata (Record type)', () async { | 
|  | var typeName = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'recordType.toString()', | 
|  | ); | 
|  | expect(typeName, '(int, int, {String name})'); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectMetadata(recordType)', | 
|  | expectedResult: { | 
|  | 'className': 'Type', | 
|  | 'libraryId': 'dart:core', | 
|  | 'runtimeKind': 'recordType', | 
|  | 'length': 3, | 
|  | }); | 
|  |  | 
|  | await driver.checkInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'record is Record', | 
|  | expectedResult: 'true', | 
|  | ); | 
|  |  | 
|  | await driver.checkInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'recordType is Type', | 
|  | expectedResult: 'true', | 
|  | ); | 
|  | }); | 
|  |  | 
|  | test('getObjectFieldNames (object)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectFieldNames(object)', | 
|  | expectedResult: []); | 
|  | }); | 
|  |  | 
|  | test('getObjectFieldNames (derived class)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectFieldNames(derived)', | 
|  | expectedResult: [ | 
|  | '_field', | 
|  | '_newPrivateField', | 
|  | '_privateExtensionTypeField', | 
|  | '_unusedField', | 
|  | 'extensionTypeField', | 
|  | 'field', | 
|  | 'functionField', | 
|  | 'genericField', | 
|  | 'lateFinalField', | 
|  | 'newPublicField', | 
|  | 'nonNullableField', | 
|  | 'nullableField', | 
|  | ]); | 
|  | }); | 
|  |  | 
|  | test('getObjectFieldNames (base class)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getObjectFieldNames(base)', | 
|  | expectedResult: [ | 
|  | '_field', | 
|  | '_privateExtensionTypeField', | 
|  | '_unusedField', | 
|  | 'extensionTypeField', | 
|  | 'field', | 
|  | 'functionField', | 
|  | 'genericField', | 
|  | 'lateFinalField', | 
|  | 'nonNullableField', | 
|  | 'nullableField', | 
|  | ]); | 
|  | }); | 
|  |  | 
|  | test('getSetElements', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSetElements(set)', | 
|  | expectedResult: { | 
|  | 'entries': ['a', 'b', 'c'], | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getMapElements', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getMapElements(map)', | 
|  | expectedResult: { | 
|  | 'keys': ['a', 'b'], | 
|  | 'values': [1, 2], | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getRecordFields', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getRecordFields(record)', | 
|  | expectedResult: { | 
|  | 'positionalCount': 2, | 
|  | 'named': ['name'], | 
|  | 'values': [0, 2, 'cat'], | 
|  | }); | 
|  | }); | 
|  |  | 
|  | // TODO(annagrin): Add recursive check for nested objects. | 
|  | test('getRecordTypeFields', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getRecordTypeFields(recordType)', | 
|  | expectedResult: { | 
|  | 'positionalCount': 2, | 
|  | 'named': ['name'], | 
|  | 'types': [{}, {}, {}], | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('getFunctionName (method)', () async { | 
|  | var getFunctionName = | 
|  | setup.emitLibraryBundle ? 'getFunctionName' : 'getFunctionMetadata'; | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.$getFunctionName(base.method)', | 
|  | expectedResult: 'method'); | 
|  | }); | 
|  |  | 
|  | test('getFunctionName (static method)', () async { | 
|  | var getFunctionName = | 
|  | setup.emitLibraryBundle ? 'getFunctionName' : 'getFunctionMetadata'; | 
|  | var expectedName = | 
|  | setup.emitLibraryBundle ? 'BaseClass.staticMethod' : 'staticMethod'; | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.$getFunctionName(staticMethod)', | 
|  | expectedResult: expectedName); | 
|  | }); | 
|  |  | 
|  | test('getFunctionName (global method)', () async { | 
|  | var getFunctionName = | 
|  | setup.emitLibraryBundle ? 'getFunctionName' : 'getFunctionMetadata'; | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.$getFunctionName(globalMethod)', | 
|  | expectedResult: 'globalFunction'); | 
|  | }); | 
|  |  | 
|  | test('getSubRange (set)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(set, 0, 3)', | 
|  | expectedResult: ['a', 'b', 'c']); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(set, 1, 2)', | 
|  | expectedResult: ['b', 'c']); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(set, 1, 5)', | 
|  | expectedResult: ['b', 'c']); | 
|  | }); | 
|  |  | 
|  | test('getSubRange (list)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(list, 0, 3)', | 
|  | expectedResult: [1, 2, 3]); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(list, 1, 2)', | 
|  | expectedResult: [2, 3]); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(list, 1, 5)', | 
|  | expectedResult: [2, 3]); | 
|  | }); | 
|  |  | 
|  | test('getSubRange (map)', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(map, 0, 3)', | 
|  | expectedResult: | 
|  | isA<List>().having((p) => p.length, 'length', equals(2)), | 
|  | ); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(map, 1, 2)', | 
|  | expectedResult: | 
|  | isA<List>().having((p) => p.length, 'length', equals(1)), | 
|  | ); | 
|  |  | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: 'dart.getSubRange(map, 1, 5)', | 
|  | expectedResult: | 
|  | isA<List>().having((p) => p.length, 'length', equals(1)), | 
|  | ); | 
|  | }); | 
|  |  | 
|  | test('callLibraryMethod', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: | 
|  | "dart.getObjectMetadata(dart.callLibraryMethod('package:eval_test/test.dart', 'globalFunction', [1, 3]))", | 
|  | expectedResult: { | 
|  | 'className': 'DerivedClass', | 
|  | 'libraryId': 'package:eval_test/test.dart', | 
|  | 'runtimeKind': 'object', | 
|  | 'length': 12 | 
|  | }, | 
|  | ); | 
|  | }, skip: !setup.emitLibraryBundle); | 
|  |  | 
|  | test('callInstanceMethod', () async { | 
|  | await driver.checkRuntimeInFrame( | 
|  | breakpointId: 'BP', | 
|  | expression: | 
|  | "dart.callInstanceMethod(dart.callLibraryMethod('package:eval_test/test.dart', 'globalFunction', [1, 3]), 'stringLength', ['hello'])", | 
|  | expectedResult: 5, | 
|  | ); | 
|  | }, skip: !setup.emitLibraryBundle); | 
|  | }); | 
|  |  | 
|  | group('extension type expression compilations |', () { | 
|  | var source = r''' | 
|  | //@dart=3.3 | 
|  | void main() { | 
|  | Foo f = new Foo(42); | 
|  | Baz b = new Baz(new Bar(42)); | 
|  | print(f); | 
|  | print(b); | 
|  | // Breakpoint: BP1 | 
|  | print(f.value); | 
|  | print(b.value); | 
|  | f.printValue(); | 
|  | f.printThis(); | 
|  | b.printThis(); | 
|  | } | 
|  | class Bar { | 
|  | final int i; | 
|  | Bar(this.i); | 
|  | String toString() => "Bar[$i]"; | 
|  | } | 
|  | extension type Foo(int value) { | 
|  | void printValue() { | 
|  | // Breakpoint: BP2 | 
|  | print("This foos value is '$value'"); | 
|  | } | 
|  | String printThis() { | 
|  | var foo = value; | 
|  | // Breakpoint: BP3 | 
|  | print("This foos this value is '$this'"); | 
|  | return "I printed '$value'!"; | 
|  | } | 
|  | } | 
|  | extension type Baz(Bar value) { | 
|  | String printThis() { | 
|  | var foo = value; | 
|  | // Breakpoint: BP4 | 
|  | print("This Baz' this value is '$this'"); | 
|  | return "I printed '$value'!"; | 
|  | } | 
|  | } | 
|  | '''; | 
|  |  | 
|  | setUpAll(() async { | 
|  | await driver.initSource(setup, source); | 
|  | }); | 
|  |  | 
|  | tearDownAll(() async { | 
|  | await driver.cleanupTest(); | 
|  | }); | 
|  |  | 
|  | test('value on extension type (int)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'f.value', | 
|  | ); | 
|  | expect(result, '42'); | 
|  | }); | 
|  |  | 
|  | test('value on extension type (custom class)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'b.value.toString()', | 
|  | ); | 
|  | expect(result, 'Bar[42]'); | 
|  | }); | 
|  |  | 
|  | test('method on extension type (int)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'f.printThis()', | 
|  | ); | 
|  | expect(result, "I printed '42'!"); | 
|  | }); | 
|  |  | 
|  | test('method on extension type (custom class)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'b.printThis()', | 
|  | ); | 
|  | expect(result, "I printed 'Bar[42]'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (int) (1)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP2', | 
|  | expression: 'printThis()', | 
|  | ); | 
|  | expect(result, "I printed '42'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (int) (2)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP3', | 
|  | expression: 'foo + value', | 
|  | ); | 
|  | expect(result, '84'); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (custom class) (1)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP4', | 
|  | expression: 'printThis()', | 
|  | ); | 
|  | expect(result, "I printed 'Bar[42]'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (custom class) (2)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP4', | 
|  | expression: 'foo.i + value.i', | 
|  | ); | 
|  | expect(result, '84'); | 
|  | }); | 
|  | }); | 
|  |  | 
|  | group('extensions expression compilations |', () { | 
|  | var source = r''' | 
|  | void main() { | 
|  | int i = 42; | 
|  | Bar b = new Bar(42); | 
|  | print(i); | 
|  | print(b); | 
|  | // Breakpoint: BP1 | 
|  | i.printThis(); | 
|  | b.printThis(); | 
|  | } | 
|  | class Bar { | 
|  | final int i; | 
|  | Bar(this.i); | 
|  | String toString() => "Bar[$i]"; | 
|  | } | 
|  | extension Foo on int { | 
|  | String printThis() { | 
|  | var value = this; | 
|  | // Breakpoint: BP2 | 
|  | print("This foos this value is '$this'"); | 
|  | return "I printed '$value'!"; | 
|  | } | 
|  | } | 
|  | extension Baz on Bar { | 
|  | String printThis() { | 
|  | var value = this; | 
|  | // Breakpoint: BP3 | 
|  | print("This Bars this value is '$this'"); | 
|  | return "I printed '$value'!"; | 
|  | } | 
|  | }'''; | 
|  |  | 
|  | setUpAll(() async { | 
|  | await driver.initSource(setup, source); | 
|  | }); | 
|  |  | 
|  | tearDownAll(() async { | 
|  | await driver.cleanupTest(); | 
|  | }); | 
|  |  | 
|  | test('call function on extension (int)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'i.printThis()', | 
|  | ); | 
|  | expect(result, "I printed '42'!"); | 
|  | }); | 
|  |  | 
|  | test('call function on extension (custom class)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'b.printThis()', | 
|  | ); | 
|  | expect(result, "I printed 'Bar[42]'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension method (int) (1)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP2', | 
|  | expression: 'printThis()', | 
|  | ); | 
|  | expect(result, "I printed '42'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (int) (2)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP2', | 
|  | expression: 'this + value', | 
|  | ); | 
|  | expect(result, '84'); | 
|  | }); | 
|  |  | 
|  | test('inside extension method (custom class) (1)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP3', | 
|  | expression: 'printThis()', | 
|  | ); | 
|  | expect(result, "I printed 'Bar[42]'!"); | 
|  | }); | 
|  |  | 
|  | test('inside extension type method (custom class) (2)', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP3', | 
|  | expression: 'this.i + value.i', | 
|  | ); | 
|  | expect(result, '84'); | 
|  | }); | 
|  | }); | 
|  |  | 
|  | group('part files expression compilations |', () { | 
|  | // WARNING: The (main) source and the part source have been constructred | 
|  | // so that the same offset (71) is valid on both, and both have an 'x' | 
|  | // variable, where one is a String and the other is an int. The 4 dots after | 
|  | // 'padding' for instance is not a mistake. | 
|  | var source = r''' | 
|  | part 'part.dart'; | 
|  | void main() { | 
|  | String x = "foo"; | 
|  | // padding.... | 
|  | foo(); | 
|  | print(x); | 
|  | }'''; | 
|  | var partSource = r''' | 
|  | part of 'test.dart'; | 
|  | void foo() { | 
|  | int x = 42; | 
|  | // Breakpoint: BP1 | 
|  | print(x); | 
|  | }'''; | 
|  |  | 
|  | setUpAll(() async { | 
|  | await driver.initSource(setup, source, partSource: partSource); | 
|  | }); | 
|  |  | 
|  | tearDownAll(() async { | 
|  | await driver.cleanupTest(); | 
|  | }); | 
|  |  | 
|  | test('can evaluate in part file', () async { | 
|  | var result = await driver.evaluateDartExpressionInFrame( | 
|  | breakpointId: 'BP1', | 
|  | expression: 'x + 1', | 
|  | ); | 
|  | expect(result, '43'); | 
|  | }); | 
|  | }); | 
|  | } |